float BVH4i::sah (NodeRef& node, const BBox3f& bounds) { float f = bounds.empty() ? 0.0f : area(bounds); if (node.isNode()) { Node* n = node.node(nodePtr()); for (size_t c=0; c<4; c++) f += sah(n->child(c),n->bounds(c)); return f; } else { size_t num; node.leaf(triPtr(),num); return f*num; } }
// pick best split plane among all possible splits float Bvh::pickBestSplit( unsigned& axis , float& split_pos , Bvh_Node* node , unsigned _start , unsigned _end ) { BBox inner; for( unsigned i = _start ; i < _end ; i++ ) inner.Union( m_bvhpri[i].m_centroid ); unsigned tri_num = _end - _start; axis = inner.MaxAxisId(); float min_sah = FLT_MAX; // distribute the triangles into bins unsigned bin[BVH_SPLIT_COUNT]; BBox bbox[BVH_SPLIT_COUNT]; BBox rbox[BVH_SPLIT_COUNT-1]; memset( bin , 0 , sizeof( unsigned ) * BVH_SPLIT_COUNT ); float split_start = inner.m_Min[axis]; float split_delta = inner.Delta(axis) * BVH_INV_SPLIT_COUNT; float inv_split_delta = 1.0f / split_delta; for( unsigned i = _start ; i < _end ; i++ ){ int index = (int)((m_bvhpri[i].m_centroid[axis] - split_start) * inv_split_delta); index = min( index , (int)(BVH_SPLIT_COUNT - 1) ); bin[index]++; bbox[index].Union( m_bvhpri[i].GetBBox() ); } rbox[BVH_SPLIT_COUNT-2].Union( bbox[BVH_SPLIT_COUNT-1] ); for( int i = BVH_SPLIT_COUNT-3; i >= 0 ; i-- ) rbox[i] = Union( rbox[i+1] , bbox[i+1] ); unsigned left = bin[0]; BBox lbox = bbox[0]; float pos = split_delta + split_start ; for( unsigned i = 0 ; i < BVH_SPLIT_COUNT - 1 ; i++ ){ float sah_value = sah( left , tri_num - left , lbox , rbox[i] , node->bbox ); if( sah_value < min_sah ){ min_sah = sah_value; split_pos = pos; } left += bin[i+1]; lbox.Union( bbox[i+1] ); pos += split_delta; } return min_sah; }
float BVH4i::sah (NodeRef& node, BBox3fa bounds) { float f = bounds.empty() ? 0.0f : area(bounds); if (node.isNode()) { Node* n = node.node(nodePtr()); for (size_t c=0; c<BVH4i::N; c++) if (n->child(c) != BVH4i::invalidNode) f += sah(n->child(c),n->bounds(c)); return f; } else { unsigned int num; node.leaf(triPtr(),num); return f*num; } }
float BVH4i::sah () { return sah(root,bounds)/area(bounds); }