X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=bvh.h;h=b054741facdcfbac6d80ee5f6d36dfaac24a5e09;hb=16f58e6b8d79762919000b9ae8266ad55a01a870;hp=491756acb0db460df2d5e697002b9b5e5e560169;hpb=777083e1f715a26d3f68be4ba5bdf2cbcaa84a05;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/bvh.h b/bvh.h index 491756a..b054741 100644 --- a/bvh.h +++ b/bvh.h @@ -5,7 +5,6 @@ #ifndef BVH_H #define BVH_H #include "common.h" -#include "distq.h" /* * Usage: @@ -69,8 +68,7 @@ VG_STATIC void bh_update_bounds( bh_tree *bh, u32 inode ) bh_node *node = &bh->nodes[ inode ]; box_init_inf( node->bbx ); - for( u32 i=0; icount; i++ ) - { + for( u32 i=0; icount; i++ ){ u32 idx = node->start+i; bh->system->expand_bound( bh->user, node->bbx, idx ); } @@ -91,7 +89,6 @@ VG_STATIC void bh_subdivide( bh_tree *bh, u32 inode ) if( extent[2] > extent[axis] ) axis = 2; float split = node->bbx[0][axis] + extent[axis]*0.5f; - float avg = 0.0; for( u32 t=0; tcount; t++ ) { @@ -99,18 +96,16 @@ VG_STATIC void bh_subdivide( bh_tree *bh, u32 inode ) avg += bh->system->item_centroid( bh->user, idx, axis ); } avg /= (float)node->count; - split = avg; + i32 i = node->start, j = i + node->count-1; - while( i <= j ) - { + while( i <= j ){ if( bh->system->item_centroid( bh->user, i, axis ) < split ) i ++; - else - { + else{ bh->system->item_swap( bh->user, i, j ); j --; } @@ -145,17 +140,10 @@ VG_STATIC bh_tree *bh_create( void *lin_alloc, bh_system *system, { assert( max_per_leaf > 0 ); - if( item_count == 0 ) - { - bh_tree *bh = vg_linear_alloc( lin_alloc, sizeof(bh_tree) ); - bh->node_count = 0; - bh->system = system; - bh->user = user; - return bh; - } + u32 alloc_count = VG_MAX( 1, item_count ); - u32 totsize = sizeof(bh_tree) + sizeof(bh_node)*(item_count*2-1); - bh_tree *bh = vg_linear_alloc( lin_alloc, totsize ); + u32 totsize = sizeof(bh_tree) + sizeof(bh_node)*(alloc_count*2-1); + bh_tree *bh = vg_linear_alloc( lin_alloc, vg_align8(totsize) ); bh->system = system; bh->user = user; bh->max_per_leaf = max_per_leaf; @@ -169,41 +157,52 @@ VG_STATIC bh_tree *bh_create( void *lin_alloc, bh_system *system, root->start = 0; bh_update_bounds( bh, 0 ); - bh_subdivide( bh, 0 ); - totsize = sizeof(bh_tree) + sizeof(bh_node) * bh->node_count; + if( item_count > 2 ) + bh_subdivide( bh, 0 ); + + totsize = vg_align8(sizeof(bh_tree) + sizeof(bh_node) * bh->node_count); bh = vg_linear_resize( lin_alloc, bh, totsize ); - vg_success( "BVH done, size: %u/%u\n", bh->node_count, (item_count*2-1) ); + vg_success( "BVH done, size: %u/%u\n", bh->node_count, (alloc_count*2-1) ); return bh; } -VG_STATIC void bh_debug_node( bh_tree *bh, u32 inode, v3f pos, u32 colour ) +/* + * Draw items in this leaf node. + * *item_debug() must be set! + */ +VG_STATIC void bh_debug_leaf( bh_tree *bh, bh_node *node ) +{ + vg_line_boxf( node->bbx, 0xff00ff00 ); + + if( bh->system->item_debug ){ + for( u32 i=0; icount; i++ ){ + u32 idx = node->start+i; + bh->system->item_debug( bh->user, idx ); + } + } +} + +/* + * Trace the bh tree all the way down to the leaf nodes where pos is inside + */ +VG_STATIC void bh_debug_trace( bh_tree *bh, u32 inode, v3f pos, u32 colour ) { bh_node *node = &bh->nodes[ inode ]; if( (pos[0] >= node->bbx[0][0] && pos[0] <= node->bbx[1][0]) && (pos[2] >= node->bbx[0][2] && pos[2] <= node->bbx[1][2]) ) { - if( !node->count ) - { + if( !node->count ){ vg_line_boxf( node->bbx, colour ); - bh_debug_node( bh, node->il, pos, colour ); - bh_debug_node( bh, node->ir, pos, colour ); + bh_debug_trace( bh, node->il, pos, colour ); + bh_debug_trace( bh, node->ir, pos, colour ); } - else - { - vg_line_boxf( node->bbx, 0xff00ff00 ); - + else{ if( bh->system->item_debug ) - { - for( u32 i=0; icount; i++ ) - { - u32 idx = node->start+i; - bh->system->item_debug( bh->user, idx ); - } - } + bh_debug_leaf( bh, node ); } } } @@ -220,16 +219,17 @@ VG_STATIC int bh_ray( bh_tree *bh, v3f co, v3f dir, ray_hit *hit ) stack[0] = 0; stack[1] = bh->nodes[0].il; stack[2] = bh->nodes[0].ir; + + v3f dir_inv; + dir_inv[0] = 1.0f/dir[0]; + dir_inv[1] = 1.0f/dir[1]; + dir_inv[2] = 1.0f/dir[2]; - while(depth) - { + while(depth){ bh_node *inode = &bh->nodes[ stack[depth] ]; - if( ray_aabb( inode->bbx, co, dir, hit->dist ) ) - { - if( inode->count ) - { - for( u32 i=0; icount; i++ ) - { + if( ray_aabb1( inode->bbx, co, dir_inv, hit->dist ) ){ + if( inode->count ){ + for( u32 i=0; icount; i++ ){ u32 idx = inode->start+i; if( bh->system->cast_ray ) @@ -240,10 +240,8 @@ VG_STATIC int bh_ray( bh_tree *bh, v3f co, v3f dir, ray_hit *hit ) depth --; } - else - { - if( depth+1 >= vg_list_size(stack) ) - { + else{ + if( depth+1 >= vg_list_size(stack) ){ vg_error( "Maximum stack reached!\n" ); return count; } @@ -253,8 +251,7 @@ VG_STATIC int bh_ray( bh_tree *bh, v3f co, v3f dir, ray_hit *hit ) depth ++; } } - else - { + else{ depth --; } } @@ -284,43 +281,36 @@ VG_STATIC void bh_iter_init( int root, bh_iter *it ) VG_STATIC int bh_next( bh_tree *bh, bh_iter *it, boxf box, int *em ) { - while( it->depth >= 0 ) - { + while( it->depth >= 0 ){ bh_node *inode = &bh->nodes[ it->stack[it->depth].id ]; - if( box_overlap( inode->bbx, box ) ) - { - if( inode->count ) - { - if( it->i < inode->count ) - { - *em = inode->start+it->i; - it->i ++; - return 1; - } - else - { - it->depth --; - it->i = 0; - } - } - else - { - if( it->depth+1 >= vg_list_size(it->stack) ) - { - vg_error( "Maximum stack reached!\n" ); - return 0; - } + /* Only process overlapping nodes */ + if( !box_overlap( inode->bbx, box ) ){ + it->depth --; + continue; + } - it->stack[it->depth ].id = inode->il; - it->stack[it->depth+1].id = inode->ir; - it->depth ++; + if( inode->count ){ + if( it->i < inode->count ){ + *em = inode->start+it->i; + it->i ++; + return 1; + } + else{ + it->depth --; it->i = 0; } } - else - { - it->depth --; + else{ + if( it->depth+1 >= vg_list_size(it->stack) ){ + vg_error( "Maximum stack reached!\n" ); + return 0; + } + + it->stack[it->depth ].id = inode->il; + it->stack[it->depth+1].id = inode->ir; + it->depth ++; + it->i = 0; } } @@ -341,8 +331,7 @@ VG_STATIC int bh_closest_point( bh_tree *bh, v3f pos, queue[0] = 0; - while( depth >= 0 ) - { + while( depth >= 0 ){ bh_node *inode = &bh->nodes[ queue[depth] ]; v3f p1; @@ -350,18 +339,14 @@ VG_STATIC int bh_closest_point( bh_tree *bh, v3f pos, /* branch into node if its closer than current best */ float node_dist = v3_dist2( pos, p1 ); - if( node_dist < max_dist ) - { - if( inode->count ) - { - for( int i=0; icount; i++ ) - { + if( node_dist < max_dist ){ + if( inode->count ){ + for( int i=0; icount; i++ ){ v3f p2; bh->system->item_closest( bh->user, inode->start+i, pos, p2 ); float item_dist = v3_dist2( pos, p2 ); - if( item_dist < max_dist ) - { + if( item_dist < max_dist ){ max_dist = item_dist; v3_copy( p2, closest ); best_item = inode->start+i; @@ -370,8 +355,7 @@ VG_STATIC int bh_closest_point( bh_tree *bh, v3f pos, depth --; } - else - { + else{ queue[depth] = inode->il; queue[depth+1] = inode->ir;