star-vx

Structuring voxels for ray-tracing
git clone git://git.meso-star.fr/star-vx.git
Log | Files | Refs | README | LICENSE

commit 3e141ddbc625bc5d3a0958d60d6586dbfb8f1dc6
parent 887b3e5faa0f439eb5b3eb57f15364819fb2a25a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  4 May 2018 15:31:03 +0200

Rename the svx_octree_at function

Make it generic to the tree dimension. It is thus renamed in svx_tree_at
and can be invoked on both bintree and octree.

Diffstat:
Msrc/svx.h | 2+-
Msrc/svx_octree.c | 192-------------------------------------------------------------------------------
Msrc/svx_tree.c | 20+++++++++++++++++++-
Msrc/svx_tree_generic_func.h | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_svx_octree.c | 2+-
5 files changed, 127 insertions(+), 195 deletions(-)

diff --git a/src/svx.h b/src/svx.h @@ -253,7 +253,7 @@ svx_octree_trace_ray struct svx_hit* hit); SVX_API res_T -svx_octree_at +svx_tree_at (struct svx_tree* octree, const double position[3], svx_at_filter_T filter, diff --git a/src/svx_octree.c b/src/svx_octree.c @@ -169,196 +169,4 @@ error: goto exit; } -#if 0 -res_T -svx_octree_for_each_leaf - (struct svx_tree* oct, svx_leaf_function_T func, void* ctx) -{ - struct stack_entry { - struct buffer_index inode; - size_t depth; - double low[3]; - double hsz[3]; /* Half size */ - } stack[TREE_DEPTH_MAX*8]; - int istack; - struct svx_voxel leaf = SVX_VOXEL_NULL; - size_t ileaf = 0; - - if(!oct || !func || oct->type != SVX_OCTREE) return RES_BAD_ARG; - - stack[0].depth = 0; - stack[0].inode = oct->root; - stack[0].low[0] = oct->tree_low[0]; - stack[0].low[1] = oct->tree_low[1]; - stack[0].low[2] = oct->tree_low[2]; - stack[0].hsz[0] = (oct->tree_upp[0] - oct->tree_low[0])*0.5; - stack[0].hsz[1] = (oct->tree_upp[1] - oct->tree_low[1])*0.5; - stack[0].hsz[2] = (oct->tree_upp[2] - oct->tree_low[2])*0.5; - istack = 1; - - do { - const struct stack_entry entry = stack[--istack]; - const size_t child_depth = entry.depth + 1; - double child_hsz[3]; - double mid[3]; /* Middle point of the current node */ - struct buffer_xnode* node; - int ichild; - - node = buffer_get_node(&oct->buffer, entry.inode); - - mid[0] = entry.low[0] + entry.hsz[0]; - mid[1] = entry.low[1] + entry.hsz[1]; - mid[2] = entry.low[2] + entry.hsz[2]; - child_hsz[0] = entry.hsz[0] * 0.5; - child_hsz[1] = entry.hsz[1] * 0.5; - child_hsz[2] = entry.hsz[2] * 0.5; - - FOR_EACH(ichild, 0, 8) { - const uint8_t ichild_flag = (uint8_t)BIT(ichild); - double low[3]; - - if((node->is_valid & ichild_flag) == 0) continue; /* Empty node */ - - low[0] = ichild&4 ? mid[0] : entry.low[0]; - low[1] = ichild&2 ? mid[1] : entry.low[1]; - low[2] = ichild&1 ? mid[2] : entry.low[2]; - - if(node->is_leaf & ichild_flag) { - struct buffer_index iattr; - - iattr = buffer_get_child_attr_index - (&oct->buffer, entry.inode, ichild); - - d3_set(leaf.lower, low); - d3_add(leaf.upper, low, entry.hsz); - leaf.data = buffer_get_attr(&oct->buffer, iattr); - leaf.id = buffer_absolute_attr_index(&oct->buffer, iattr); - leaf.depth = child_depth; - leaf.is_leaf = 1; - - func(&leaf, ileaf++, ctx); - } else { - struct stack_entry* top = stack + istack; - - top->inode = buffer_get_child_node_index - (&oct->buffer, entry.inode, ichild); - d3_set(top->low, low); - d3_set(top->hsz, child_hsz); - top->depth = child_depth; - ++istack; - } - } - } while(istack); - - return RES_OK; -} -#endif - -res_T -svx_octree_at - (struct svx_tree* oct, - const double position[3], - svx_at_filter_T filter, - void* context, - struct svx_voxel* voxel) -{ - struct buffer_index inode; - struct buffer_index iattr; - struct svx_voxel vox = SVX_VOXEL_NULL; - double scale_exp2; - double low[3]; - double pos[3]; - res_T res = RES_OK; - - if(!oct || !position || !voxel || oct->type != SVX_OCTREE) { - res = RES_BAD_ARG; - goto error; - } - - *voxel = SVX_VOXEL_NULL; - - /* The position is outside the octree */ - if(position[0] > oct->upper[0] || position[0] < oct->lower[0] - || position[1] > oct->upper[1] || position[1] < oct->lower[1] - || position[2] > oct->upper[2] || position[2] < oct->lower[2]) { - goto exit; - } - - /* Transform the position in the normalized octree space, - * i.e. octree lies in [0, 1]^2 */ - pos[0] = (position[0] - oct->tree_low[0]) / oct->tree_size[0]; - pos[1] = (position[1] - oct->tree_low[1]) / oct->tree_size[1]; - pos[2] = (position[2] - oct->tree_low[2]) / oct->tree_size[2]; - - /* Initialized the lower left corner of the current node */ - low[0] = 0; - low[1] = 0; - low[2] = 0; - - /* Root voxel */ - vox.depth = 0; - vox.is_leaf = 0; - d3_set(vox.lower, oct->lower); - d3_set(vox.upper, oct->upper); - if(filter) { - vox.data = oct->root_attr; - vox.id = buffer_absolute_attr_index(&oct->buffer, oct->buffer.attr_head); - if(!filter(&vox, position, context)) { *voxel = vox; goto exit; } - } - - scale_exp2 = 0.5; - inode = oct->root; - for(;;) { - struct buffer_xnode* node = buffer_get_node(&oct->buffer, inode); - int ichild; - uint8_t ichild_flag; - double mid[3]; - - ++vox.depth; - - /* Compute the middle point of the node */ - mid[0] = low[0] + scale_exp2; - mid[1] = low[1] + scale_exp2; - mid[2] = low[2] + scale_exp2; - - /* Define the child of the current node into which pos `lies' and compute - * its lower left corner */ - ichild = 0; - if(pos[0] > mid[0]) { ichild |= 4; low[0] = mid[0]; } - if(pos[1] > mid[1]) { ichild |= 2; low[1] = mid[1]; } - if(pos[2] > mid[2]) { ichild |= 1; low[2] = mid[2]; } - - ichild_flag = (uint8_t)BIT(ichild); - if((node->is_valid & ichild_flag) == 0) break; /* Empty node */ - - vox.is_leaf = (node->is_leaf & ichild_flag) != 0; - if(filter || vox.is_leaf) { - iattr = buffer_get_child_attr_index(&oct->buffer, inode, ichild); - - /* Setup the voxel */ - vox.lower[0] = low[0] * oct->tree_size[0] + oct->tree_low[0]; - vox.lower[1] = low[1] * oct->tree_size[1] + oct->tree_low[1]; - vox.lower[2] = low[2] * oct->tree_size[2] + oct->tree_low[2]; - vox.upper[0] = vox.lower[0] + oct->tree_size[0] * scale_exp2; - vox.upper[1] = vox.lower[1] + oct->tree_size[1] * scale_exp2; - vox.upper[2] = vox.lower[2] + oct->tree_size[2] * scale_exp2; - vox.data = buffer_get_attr(&oct->buffer, iattr); - vox.id = buffer_absolute_attr_index(&oct->buffer, iattr); - vox.is_leaf = (node->is_leaf & ichild_flag) != 0; - - if(vox.is_leaf || !filter(&vox, position, context)) { - *voxel = vox; - break; - } - } - - inode = buffer_get_child_node_index(&oct->buffer, inode, ichild); - scale_exp2 *= 0.5; - } - -exit: - return res; -error: - goto exit; -} diff --git a/src/svx_tree.c b/src/svx_tree.c @@ -82,7 +82,7 @@ res_T svx_tree_for_each_leaf(struct svx_tree* tree, svx_leaf_function_T func, void* ctx) { res_T res = RES_OK; - if(!tree || !func) return RES_BAD_ARG; + if(!tree) return RES_BAD_ARG; switch(tree->type) { case SVX_BINTREE: res = bintree_for_each_leaf(tree, func, ctx); break; case SVX_OCTREE: res = octree_for_each_leaf(tree, func, ctx); break; @@ -91,6 +91,24 @@ svx_tree_for_each_leaf(struct svx_tree* tree, svx_leaf_function_T func, void* ct return res; } +res_T +svx_tree_at + (struct svx_tree* tree, + const double pos[3], + svx_at_filter_T filter, + void* context, + struct svx_voxel* vox) +{ + res_T res = RES_OK; + if(!tree) return RES_BAD_ARG; + switch(tree->type){ + case SVX_BINTREE: res = bintree_at(tree, pos, filter, context, vox); break; + case SVX_OCTREE: res = octree_at(tree, pos, filter, context, vox); break; + default: FATAL("Unreachable code.\n"); break; + } + return res; +} + /******************************************************************************* * Local functions ******************************************************************************/ diff --git a/src/svx_tree_generic_func.h b/src/svx_tree_generic_func.h @@ -128,6 +128,112 @@ TREE_FUNC(for_each_leaf) return RES_OK; } +static res_T +TREE_FUNC(at) + (struct svx_tree* tree, + const double position[3], + svx_at_filter_T filter, + void* context, + struct svx_voxel* voxel) +{ + struct buffer_index inode; + struct buffer_index iattr; + struct svx_voxel vox = SVX_VOXEL_NULL; + double scale_exp2; + double low[TREE_DIMENSION]; + double pos[TREE_DIMENSION]; + int i; + res_T res = RES_OK; + + if(!tree || !position || !voxel || tree->type != SVX_TREE_TYPE) { + res = RES_BAD_ARG; + goto error; + } + + *voxel = SVX_VOXEL_NULL; + + /* The position is outside the octree */ + FOR_EACH(i, 0, TREE_DIMENSION) { + if(position[tree->frame[i]] > tree->upper[tree->frame[i]] + || position[tree->frame[i]] < tree->lower[tree->frame[i]]) + goto exit; + } + + FOR_EACH(i, 0, TREE_DIMENSION) { + /* Transform the position in the normalized octree space, + * i.e. octree lies in [0, 1]^2 */ + pos[i] = (position[tree->frame[i]] - tree->tree_low[tree->frame[i]]) + / tree->tree_size[i]; + /* Initialized the lower left corner of the current node */ + low[i] = 0; + } + + /* Root voxel */ + vox.depth = 0; + vox.is_leaf = 0; + FOR_EACH(i, 0, TREE_DIMENSION) { + vox.lower[tree->frame[i]] = tree->lower[tree->frame[i]]; + vox.upper[tree->frame[i]] = tree->upper[tree->frame[i]]; + } + if(filter) { + vox.data = tree->root_attr; + vox.id = buffer_absolute_attr_index(&tree->buffer, tree->buffer.attr_head); + if(!filter(&vox, position, context)) { *voxel = vox; goto exit; } + } + + scale_exp2 = 0.5; + inode = tree->root; + for(;;) { + struct buffer_xnode* node = buffer_get_node(&tree->buffer, inode); + int ichild; + uint8_t ichild_flag; + double mid[TREE_DIMENSION]; + + ++vox.depth; + + /* Compute the middle point of the node */ + FOR_EACH(i, 0, TREE_DIMENSION) mid[i] = low[i] + scale_exp2; + + /* Define the child of the current node into which pos `lies' and compute + * its lower left corner */ + ichild = 0; + FOR_EACH(i, 0, TREE_DIMENSION) { + if(pos[i] > mid[i]) { ichild |= BIT(TREE_DIMENSION-1-i); low[i] = mid[i]; } + } + + ichild_flag = (uint8_t)BIT(ichild); + if((node->is_valid & ichild_flag) == 0) break; /* Empty node */ + + vox.is_leaf = (node->is_leaf & ichild_flag) != 0; + if(filter || vox.is_leaf) { + iattr = buffer_get_child_attr_index(&tree->buffer, inode, ichild); + + /* Setup the voxel */ + FOR_EACH(i, 0, TREE_DIMENSION) { + const int iaxis = tree->frame[i]; + vox.lower[iaxis] = low[i] * tree->tree_size[iaxis] + tree->tree_low[iaxis]; + vox.upper[iaxis] = vox.lower[iaxis] + tree->tree_size[iaxis] * scale_exp2; + } + vox.data = buffer_get_attr(&tree->buffer, iattr); + vox.id = buffer_absolute_attr_index(&tree->buffer, iattr); + vox.is_leaf = (node->is_leaf & ichild_flag) != 0; + + if(vox.is_leaf || !filter(&vox, position, context)) { + *voxel = vox; + break; + } + } + + inode = buffer_get_child_node_index(&tree->buffer, inode, ichild); + scale_exp2 *= 0.5; + } + +exit: + return res; +error: + goto exit; +} + #undef TREE_FUNC #undef SVX_TREE_TYPE #undef TREE_DIMENSION diff --git a/src/test_svx_octree.c b/src/test_svx_octree.c @@ -230,7 +230,7 @@ test_at_accessor(struct svx_tree* oct, const size_t nvoxels[3]) if(z*(1u<<iter) >= nvoxels[2]) break; d3_set(ctx.position, pos); - CHK(svx_octree_at(oct, pos, max_lod, &ctx, &vox) == RES_OK); + CHK(svx_tree_at(oct, pos, max_lod, &ctx, &vox) == RES_OK); CHK(!SVX_VOXEL_NONE(&vox)); ui3[0] = (uint32_t)x * (1u << iter) + ((1u << iter) - 1);