star-vx

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

commit 3b4c9b48b1e7718f42dcc0b191ce3bb5e982b82d
parent a638ee17618af470f1ebac6a84abcd8624c2f976
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 29 Mar 2021 08:59:58 +0200

Invoke the hit challenge/filter functor on the root node

Previously, the root node of a <binary|oct>-tree was not
challenged/filtered by the user defined functors; the
challenging/filtering began on its children. This commit updates the
ray-tracing functions to handle the root node as any other nodes.

Diffstat:
Msrc/svx_bintree_trace_ray.c | 23+++++++++++++++++++++++
Msrc/svx_octree_trace_ray.c | 30++++++++++++++++++++++++++++--
Msrc/test_svx_bintree_trace_ray.c | 32+++++++++++++++++++++++++++++++-
Msrc/test_svx_octree_trace_ray.c | 24++++++++++++++++++++++++
4 files changed, 106 insertions(+), 3 deletions(-)

diff --git a/src/svx_bintree_trace_ray.c b/src/svx_bintree_trace_ray.c @@ -147,6 +147,29 @@ bintree_trace_ray pos_min = MMAX(dir * ray_range[0] + org, 0); pos_max = MMIN(dir * ray_range[1] + org, 1); + /* Challenge the root node */ + if(challenge) { + struct svx_hit hit_root; + const double t_min = null_dir ? ray_range[0] : (pos_min - org) * ts; + const double t_max = null_dir ? ray_range[1] : (pos_max - org) * ts; + struct buffer_index iattr_dummy = buffer_get_child_attr_index + (&btree->buffer, btree->root, 0/*arbitrarly child index*/); + + /* Use the regular setup_hit procedure by providing a dummy attribute + * index, and then overwrite the voxel data with the root one */ + setup_hit(btree, iattr_dummy, t_min, t_max, 0.f/*low*/, 1.f/*scale_exp2*/, + 0/*depth*/, 0/*is_leaf*/, flip, &hit_root); + hit_root.voxel.data = btree->root_attr; + + if(challenge(&hit_root, ray_org, ray_dir, ray_range, context)) { + if(!filter /* By default, i.e. with no filter, stop the traversal */ + || !filter(&hit_root, ray_org, ray_dir, ray_range, context)) { + *hit = hit_root; + return RES_OK; /* Do not traverse the binary tree */ + } + } + } + /* Define the first traversed child and set its lower bound */ if(pos_min <= 0.5) { /* Note that we use less than or *equal* in the previous test to be diff --git a/src/svx_octree_trace_ray.c b/src/svx_octree_trace_ray.c @@ -206,7 +206,33 @@ trace_ray t_max = MMIN(ray->range[1], t_max); if(t_min >= t_max) return RES_OK; /* No intersection */ - /* Traverrsal initialisation */ + /* Challenge the root */ + if(challenge) { + struct svx_hit hit_root; + struct buffer_index iattr_dummy = buffer_get_child_attr_index + (&oct->buffer, oct->root, 0/*arbitrarly child index*/); + + /* Lower left corner of the root node in the [1, 2]^3 space */ + corner[0] = 1.f; + corner[1] = 1.f; + corner[2] = 1.f; + + /* Use the regular setup_hit procedure by providing a dummy attribute + * index, and then overwrite the voxel data with the root one */ + setup_hit(oct, iattr_dummy, t_min, t_max, corner, 1.f/*scale_exp2*/, + 0/*depth*/, 0/*is_leaf*/, ray->octant_mask, &hit_root); + hit_root.voxel.data = oct->root_attr; + + if(challenge(&hit_root, ray->orgws, ray->dirws, ray->range, context)) { + if(!filter /* By default, i.e. with no filter, stop the traversal */ + || !filter(&hit_root, ray->orgws, ray->dirws, ray->range, context)) { + *hit = hit_root; + return RES_OK; /* Do not traverse the octree */ + } + } + } + + /* Traversal initialisation */ inode = oct->root; scale_exp2 = 0.5f; scale = SCALE_MAX - 1; @@ -255,7 +281,7 @@ trace_ray setup_hit(oct, iattr, t_min, t_max_child, corner, scale_exp2, depth, is_leaf, ray->octant_mask, &hit_tmp); - if(is_leaf + if(is_leaf || challenge(&hit_tmp, ray->orgws, ray->dirws, ray->range, context)) { go_deeper = 0; /* Stop the traversal if no filter is defined or if the filter diff --git a/src/test_svx_bintree_trace_ray.c b/src/test_svx_bintree_trace_ray.c @@ -117,6 +117,18 @@ hit_challenge } static int +hit_challenge_root + (const struct svx_hit* hit, + const double ray_org[3], + const double ray_dir[3], + const double ray_range[2], + void* context) +{ + (void)hit, (void)ray_org, (void)ray_dir, (void)ray_range, (void)context; + return hit->voxel.depth == 0; +} + +static int hit_challenge_pass_through (const struct svx_hit* hit, const double ray_org[3], @@ -450,7 +462,7 @@ main(int argc, char** argv) CHK(*(char*)hit2.voxel.data == 1); CHK(hit2.voxel.depth < 3); - /* Stil lcheck a ray with null dir along the tree axis */ + /* Still check a ray with null dir along the tree axis */ d3(r.org, -0.51, 31, 41); CHK(RT(btree, r.org, r.dir, r.range, NULL, NULL, NULL, &hit) == RES_OK); CHK(eq_eps(hit.distance[0], r.range[0], 1.e-6)); @@ -472,6 +484,24 @@ main(int argc, char** argv) CHK(SVX_HIT_NONE(&hit)); CHK(accum == 1); + /* Check the root node challenge */ + d3(r.org, 1.01, 1234, 10); + d3_normalize(r.dir, d3(r.dir, -1, -1, -1)); + CHK(RT(btree, r.org, r.dir, r.range, hit_challenge_root, NULL, NULL, &hit) + == RES_OK); + CHK(!SVX_HIT_NONE(&hit)); + CHK(hit.voxel.lower[0] == -1); + CHK(hit.voxel.upper[0] == 1); + CHK(IS_INF(hit.voxel.lower[1])); + CHK(IS_INF(hit.voxel.upper[1])); + CHK(IS_INF(hit.voxel.lower[2])); + CHK(IS_INF(hit.voxel.upper[2])); + CHK(hit.voxel.depth == 0); + CHK(hit.voxel.is_leaf == 0); + CHK(*((char*)hit.voxel.data) == 1); + CHK(eq_eps(hit.distance[0], (hit.voxel.upper[0]-r.org[0])/r.dir[0], 1.e-4)); + CHK(eq_eps(hit.distance[1], (hit.voxel.lower[0]-r.org[0])/r.dir[0], 1.e-4)); + image_init(NULL, &img); image_init(NULL, &img2); draw_image(&img, btree); diff --git a/src/test_svx_octree_trace_ray.c b/src/test_svx_octree_trace_ray.c @@ -217,6 +217,18 @@ hit_challenge_pass_through return 0; } +static int +hit_challenge_root + (const struct svx_hit* hit, + const double ray_org[3], + const double ray_dir[3], + const double ray_range[2], + void* context) +{ + (void)hit, (void)ray_org, (void)ray_dir, (void)ray_range, (void)context; + return hit->voxel.depth == 0; +} + static void draw_image(struct image* img, struct svx_tree* oct, const struct scene* scn) { @@ -424,6 +436,18 @@ main(int argc, char** argv) CHK(SVX_HIT_NONE(&hit)); CHK(accum != 0); + /* Check the root node challenge */ + CHK(RT(oct, r.org, r.dir, r.range, hit_challenge_root, NULL, NULL, &hit) + == RES_OK); + CHK(!SVX_HIT_NONE(&hit)); + CHK(d3_eq_eps(hit.voxel.lower, lower, 1.e-6)); + CHK(d3_eq_eps(hit.voxel.upper, upper, 1.e-6)); + CHK(hit.voxel.depth == 0); + CHK(hit.voxel.is_leaf == 0); + CHK(*(char*)hit.voxel.data == 1); + CHK(eq_eps(hit.distance[0], hit.voxel.lower[1] - r.org[1], 1.e-6)); + CHK(eq_eps(hit.distance[1], hit.voxel.upper[1] - r.org[1], 1.e-6)); + image_init(NULL, &img); image_init(NULL, &img2); draw_image(&img, oct, &scn);