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:
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);