star-vx

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

commit 51affe8d794d8cb51bb6878c6065fec392f16bfc
parent 695d9c868c1efa18fa18b1aa35dd7ecf574533cf
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue,  6 Feb 2018 09:56:37 +0100

Add and test the htvox_scene_for_each_voxel function

Diffstat:
Msrc/htvox.h | 7+++++++
Msrc/htvox_scene.c | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/htvox_scene.h | 3++-
Msrc/test_htvox_scene.c | 82++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
4 files changed, 163 insertions(+), 22 deletions(-)

diff --git a/src/htvox.h b/src/htvox.h @@ -103,6 +103,13 @@ htvox_scene_get_aabb double upper[3]); HTVOX_API res_T +htvox_scene_for_each_voxel + (struct htvox_scene* scn, + void (*functor) + (const double val, const double low[3], const double upp[3], void* ctx), + void* context); + +HTVOX_API res_T htvox_scene_trace_ray (struct htvox_scene* scn, const double ray_origin[3], diff --git a/src/htvox_scene.c b/src/htvox_scene.c @@ -163,7 +163,7 @@ stack_write size_t offset = SIZE_MAX; if(node->data == VOXEL_EMPTY_DATA) { - xnodes[inode].offset |= OCTREE_XNODE_FLAG_EMPTY; + xnodes[inode].offset = OCTREE_XNODE_FLAG_EMPTY; } else { if(node->is_leaf) { double* leaf; @@ -193,7 +193,6 @@ stack_write * rewrite the whole stacked nodes in a new page. */ res = octree_buffer_alloc_far_index(buffer, &index); if(res != RES_OK) { - printf("Hop\n"); break; } far_id = octree_buffer_get_far_index(buffer, index); @@ -457,9 +456,9 @@ htvox_scene_create morton_xyz_decode_u21(mcode, ui3); /* Out of bound voxels */ - if(ui3[0] > nvoxels[0] - || ui3[1] > nvoxels[1] - || ui3[2] > nvoxels[2]) { + if(ui3[0] >= nvoxels[0] + || ui3[1] >= nvoxels[1] + || ui3[2] >= nvoxels[2]) { vox.data = VOXEL_EMPTY_DATA; } else { /* Retrieve the voxel data from the caller */ @@ -485,6 +484,10 @@ htvox_scene_create d3_set(scn->lower, lower); d3_set(scn->upper, upper); + d3_set(scn->oclow, lower); + scn->ocupp[0] = (double)scn->definition * vox_sz[0]; + scn->ocupp[1] = (double)scn->definition * vox_sz[1]; + scn->ocupp[2] = (double)scn->definition * vox_sz[2]; exit: if(out_scn) *out_scn = scn; @@ -515,7 +518,7 @@ htvox_scene_ref_put(struct htvox_scene* scn) res_T htvox_scene_get_aabb - (const struct htvox_scene* scn, + (const struct htvox_scene* scn, double lower[3], double upper[3]) { @@ -524,3 +527,81 @@ htvox_scene_get_aabb d3_set(upper, scn->upper); return RES_OK; } + +res_T +htvox_scene_for_each_voxel + (struct htvox_scene* scn, + void (*func) + (const double val, const double low[3], const double upp[3], void* ctx), + void* ctx) +{ + struct stack_entry { + struct octree_index inode; + double low[3]; + double upp[3]; + } stack[OCTREE_DEPTH_MAX*8]; + int istack; + + if(!scn || !func) return RES_BAD_ARG; + + stack[0].inode = scn->root; + stack[0].low[0] = scn->oclow[0]; + stack[0].low[1] = scn->oclow[1]; + stack[0].low[2] = scn->oclow[2]; + stack[0].upp[0] = scn->ocupp[0]; + stack[0].upp[1] = scn->ocupp[1]; + stack[0].upp[2] = scn->ocupp[2]; + istack = 1; + + do { + const struct stack_entry entry = stack[--istack]; + struct octree_xnode* node; + + node = octree_buffer_get_node(&scn->buffer, entry.inode); + + if(OCTREE_XNODE_IS_LEAF(node)) { + double val; + struct octree_index ileaf; + + ileaf = octree_buffer_get_child_index(&scn->buffer, entry.inode, 0); + val = *octree_buffer_get_leaf(&scn->buffer, ileaf); + + ASSERT(entry.upp[0] <= scn->upper[0]); + ASSERT(entry.upp[1] <= scn->upper[1]); + ASSERT(entry.upp[2] <= scn->upper[2]); + ASSERT(entry.low[0] >= scn->lower[0]); + ASSERT(entry.low[1] >= scn->lower[1]); + ASSERT(entry.low[2] >= scn->lower[2]); + + func(val, entry.low, entry.upp, ctx); + + } else if(!OCTREE_XNODE_IS_EMPTY(node)) { + double half_sz[3]; /* Half size of the current node */ + double mid[3]; /* Middle point of the current node */ + int i; + + half_sz[0] = (entry.upp[0] - entry.low[0])*0.5; + half_sz[1] = (entry.upp[1] - entry.low[1])*0.5; + half_sz[2] = (entry.upp[2] - entry.low[2])*0.5; + mid[0] = entry.low[0] + half_sz[0]; + mid[1] = entry.low[1] + half_sz[1]; + mid[2] = entry.low[2] + half_sz[2]; + + /* Push the children */ + FOR_EACH(i, 0, 8) { + struct stack_entry* top = stack + istack; + top->inode = octree_buffer_get_child_index(&scn->buffer, entry.inode, i); + top->low[0] = i&4 ? mid[0] : entry.low[0]; + top->low[1] = i&2 ? mid[1] : entry.low[1]; + top->low[2] = i&1 ? mid[2] : entry.low[2]; + top->upp[0] = top->low[0] + half_sz[0]; + top->upp[1] = top->low[1] + half_sz[1]; + top->upp[2] = top->low[2] + half_sz[2]; + ++istack; + } + } + } while(istack); + + return RES_OK; +} + diff --git a/src/htvox_scene.h b/src/htvox_scene.h @@ -23,7 +23,8 @@ struct htvox_scene { double vox_scale[3]; /* Scale factor of the octree */ size_t definition; /* Definition of the octree */ - double lower[3], upper[3]; /* World space AABB */ + double lower[3], upper[3]; /* World space AABB of the scene */ + double oclow[3], ocupp[3]; /* World space AABB of the octree */ struct octree_buffer buffer; struct octree_index root; /* Index toward the root node of the octree */ diff --git a/src/test_htvox_scene.c b/src/test_htvox_scene.c @@ -19,11 +19,18 @@ #include <rsys/double3.h> +struct context { + double* lower; + double* upper; + size_t* nvoxels; +}; + static int merge(const double min_val, const double max_val, void* ctx) { + (void)min_val, (void)max_val; CHK((intptr_t)ctx == 0xDECAFBAD); - return (max_val - min_val) < 0.5; + return 0; /* Merge nothing */ } static void @@ -40,7 +47,45 @@ get(const size_t xyz[3], double* val, void* ctx) ui3[2] = (uint32_t)xyz[2]; mcode = morton_xyz_encode_u21(ui3); - *val = (double)(mcode % 8) / (double)4; + *val = (double)mcode; +} + +static void +check_voxel + (const double val, const double low[3], const double upp[3], void* context) +{ + struct context* ctx = context; + uint64_t mcode; + uint32_t xyz[3]; + double lower[3]; + double delta[3]; + + CHK(val >= 0); + CHK(low != NULL); + CHK(upp != NULL); + CHK(ctx != NULL); + CHK(low[0] < upp[0]); + CHK(low[1] < upp[1]); + CHK(low[2] < upp[2]); + + mcode = (uint64_t)val; + CHK(val == (double)mcode); + + delta[0] = (ctx->upper[0] - ctx->lower[0]) / (double)ctx->nvoxels[0]; + delta[1] = (ctx->upper[1] - ctx->lower[1]) / (double)ctx->nvoxels[1]; + delta[2] = (ctx->upper[2] - ctx->lower[2]) / (double)ctx->nvoxels[2]; + + morton_xyz_decode_u21(mcode, xyz); + lower[0] = xyz[0] * delta[0]; + lower[1] = xyz[1] * delta[1]; + lower[2] = xyz[2] * delta[2]; + + CHK(eq_eps(lower[0], low[0], 1.e-6)); + CHK(eq_eps(lower[1], low[1], 1.e-6)); + CHK(eq_eps(lower[2], low[2], 1.e-6)); + CHK(eq_eps(lower[0] + delta[0], upp[0], 1.e-6)); + CHK(eq_eps(lower[1] + delta[1], upp[1], 1.e-6)); + CHK(eq_eps(lower[2] + delta[2], upp[2], 1.e-6)); } int @@ -52,7 +97,8 @@ main(int argc, char** argv) double low[3]; double upp[3]; size_t nvxls[3]; - void* ctx = (void*)0xDECAFBAD; + struct context ctx; + void* ptr = (void*)0xDECAFBAD; (void)argc, (void)argv; CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); @@ -63,9 +109,13 @@ main(int argc, char** argv) d3_splat(upp, 1.0); nvxls[0] = nvxls[1] = nvxls[2] = 10; + ctx.lower = low; + ctx.upper = upp; + ctx.nvoxels = nvxls; + #define NEW_SCN htvox_scene_create - CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, &scn) == RES_OK); + CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, &scn) == RES_OK); CHK(htvox_scene_ref_get(NULL) == RES_BAD_ARG); CHK(htvox_scene_ref_get(scn) == RES_OK); @@ -74,25 +124,27 @@ main(int argc, char** argv) CHK(htvox_scene_ref_put(scn) == RES_OK); upp[0] = low[0]; - CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG); upp[0] = 1.0; nvxls[2] = 0; - CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG); - nvxls[2] = 10; + CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG); + nvxls[2] = nvxls[0]; - CHK(NEW_SCN(NULL, low, upp, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, NULL, upp, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, NULL, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, upp, NULL, get, merge, ctx, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, upp, nvxls, NULL, merge, ctx, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, upp, nvxls, get, NULL, ctx, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, NULL) == RES_BAD_ARG); + CHK(NEW_SCN(NULL, low, upp, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, NULL, upp, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, NULL, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, NULL, get, merge, ptr, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, nvxls, NULL, merge, ptr, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, nvxls, get, NULL, ptr, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, NULL) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, &scn) == RES_OK); + CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, &scn) == RES_OK); #undef NEW_SCN + CHK(htvox_scene_for_each_voxel(scn, check_voxel, &ctx) == RES_OK); + d3_splat(low, DBL_MAX); d3_splat(upp,-DBL_MAX); CHK(htvox_scene_get_aabb(scn, low, upp) == RES_OK);