commit d01a4ad76131dd4e236fb569823dae267dcd27cc
parent 985c112d6b0876f0f8f6f32b24060a64d7979b50
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 4 Apr 2018 16:21:35 +0200
Add several use cases in the trace_ray test
Diffstat:
5 files changed, 178 insertions(+), 14 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -78,17 +78,17 @@ if(NOT NO_TEST)
add_executable(${_name}
${SVX_SOURCE_DIR}/${_name}.c
${SVX_SOURCE_DIR}/test_svx_utils.h)
- target_link_libraries(${_name} svx RSys)
+ target_link_libraries(${_name} svx RSys ${ARGN})
endfunction()
function(new_test _name)
- build_test(${_name})
+ build_test(${_name} ${ARGN})
add_test(${_name} ${_name})
endfunction()
new_test(test_svx_device)
new_test(test_svx_octree)
- new_test(test_svx_octree_trace_ray)
+ new_test(test_svx_octree_trace_ray m)
endif()
################################################################################
diff --git a/src/svx.h b/src/svx.h
@@ -55,6 +55,8 @@ struct svx_voxel {
NULL, SIZE_MAX, SIZE_MAX, 0 }
static const struct svx_voxel SVX_VOXEL_NULL = SVX_VOXEL_NULL__;
+#define SVX_VOXEL_EQ(V0, V1) ((V0)->id == (V1)->id)
+
#define SVX_VOXEL_NONE(Voxel) ((Voxel)->id == SVX_VOXEL_NULL.id)
/* Descriptor of a voxel */
diff --git a/src/svx_octree.c b/src/svx_octree.c
@@ -568,9 +568,9 @@ svx_octree_create
oct->oclow[0] = lower[0];
oct->oclow[1] = lower[1];
oct->oclow[2] = lower[2];
- oct->ocupp[0] = (double)oct->definition * vox_sz[0];
- oct->ocupp[1] = (double)oct->definition * vox_sz[1];
- oct->ocupp[2] = (double)oct->definition * vox_sz[2];
+ oct->ocupp[0] = oct->oclow[0] + (double)oct->definition * vox_sz[0];
+ oct->ocupp[1] = oct->oclow[1] + (double)oct->definition * vox_sz[1];
+ oct->ocupp[2] = oct->oclow[2] + (double)oct->definition * vox_sz[2];
oct->ocsize[0] = oct->ocupp[0] - oct->oclow[0];
oct->ocsize[1] = oct->ocupp[1] - oct->oclow[1];
oct->ocsize[2] = oct->ocupp[2] - oct->oclow[2];
diff --git a/src/svx_octree_trace_ray.c b/src/svx_octree_trace_ray.c
@@ -148,8 +148,8 @@ setup_ray
/* Mirror rays with position directions */
ray->octant_mask = 0;
if(dir[0] > 0) { ray->octant_mask ^= 4; ray->org[0] = 3.0 - ray->org[0]; }
- if(dir[1] > 0) { ray->octant_mask ^= 2; ray->org[0] = 3.0 - ray->org[1]; }
- if(dir[2] > 0) { ray->octant_mask ^= 1; ray->org[0] = 3.0 - ray->org[2]; }
+ if(dir[1] > 0) { ray->octant_mask ^= 2; ray->org[1] = 3.0 - ray->org[1]; }
+ if(dir[2] > 0) { ray->octant_mask ^= 1; ray->org[2] = 3.0 - ray->org[2]; }
/* Save the world space ray origin */
ray->orgws[0] = org[0];
@@ -218,7 +218,7 @@ trace_ray
/* Octree traversal */
scale_max = scale + 1;
- while(scale < scale_max) {
+ while(scale < scale_max && t_min < t_max) {
const struct octree_xnode* node = octree_buffer_get_node(&oct->buffer, inode);
double t_corner[3];
double t_max_corner;
@@ -242,21 +242,24 @@ trace_ray
/* If the current voxel is a leaf or if a challenge function is set,
* check the current hit */
if(is_leaf || challenge) {
- const double dst = t_min < ray->range[0] ? t_max_child : t_min;
+ struct svx_hit hit_tmp;
+ const double dst = t_min <= ray->range[0] ? t_max_child : t_min;
const size_t depth = SCALE_MAX - scale;
const struct octree_index iattr = octree_buffer_get_child_attr_index
(&oct->buffer, inode, (int)ichild_adjusted);
setup_hit(oct, iattr, dst, corner, scale_exp2, depth, is_leaf,
- ray->octant_mask, hit);
+ ray->octant_mask, &hit_tmp);
- if(is_leaf || challenge(hit, context)) {
+ if(is_leaf || challenge(&hit_tmp, context)) {
go_deeper = 0;
/* Stop the traversal if no filter is defined or if the filter
* function returns 0 */
if(!filter /* By default, i.e. with no filter, stop the traversal */
- || !filter(hit, ray->orgws, ray->dirws, ray->range, context))
+ || !filter(&hit_tmp, ray->orgws, ray->dirws, ray->range, context)) {
+ *hit = hit_tmp;
break;
+ }
}
}
@@ -282,7 +285,11 @@ trace_ray
stack[scale].t_max = t_max_parent;
stack[scale].inode = inode;
- /* Define the id and the lower left corner of the first child */
+ /* Get the node index of the traversed child */
+ inode = octree_buffer_get_child_node_index
+ (&oct->buffer, inode, (int)ichild_adjusted);
+
+ /* Define the id and the lower left corner of the first grand child */
ichild = 0;
if(t_center[0] > t_min) { ichild ^= 4; corner[0] += scale_exp2_child; }
if(t_center[1] > t_min) { ichild ^= 2; corner[1] += scale_exp2_child; }
diff --git a/src/test_svx_octree_trace_ray.c b/src/test_svx_octree_trace_ray.c
@@ -13,11 +13,23 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#define _POSIX_C_SOURCE 200112L /* nextafter function */
+
#include "svx.h"
#include "test_svx_utils.h"
+#include <math.h>
+
+#include <rsys/double2.h>
+#include <rsys/double3.h>
#include <rsys/math.h>
+struct ray {
+ double org[3];
+ double dir[3];
+ double range[3];
+};
+
struct scene {
double origin[3];
double vxsz[3];
@@ -119,17 +131,83 @@ write_scalars
fprintf(stream, "%d\n", *(char*)leaf->data);
}
+static int
+hit_filter
+ (const struct svx_hit* hit,
+ const double ray_org[3],
+ const double ray_dir[3],
+ const double ray_range[3],
+ void* context)
+{
+ const struct ray* ray = context;
+
+ CHK(hit && ray_org && ray_dir && ray_range && context);
+ CHK(d3_eq(ray->org, ray_org));
+ CHK(d3_eq(ray->dir, ray_dir));
+ CHK(d2_eq(ray->range, ray_range));
+ CHK(!SVX_HIT_NONE(hit));
+
+ return *((char*)hit->voxel.data) == 0;
+}
+
+static int
+hit_filter2
+ (const struct svx_hit* hit,
+ const double ray_org[3],
+ const double ray_dir[3],
+ const double ray_range[3],
+ void* context)
+{
+ const struct svx_voxel* voxel = context;
+
+ CHK(hit && ray_org && ray_dir && ray_range && context);
+ CHK(!SVX_HIT_NONE(hit));
+ return SVX_VOXEL_EQ(&hit->voxel, voxel)
+ || *((char*)hit->voxel.data) == 0;
+}
+
+static int
+hit_filter3
+ (const struct svx_hit* hit,
+ const double ray_org[3],
+ const double ray_dir[3],
+ const double ray_range[3],
+ void* context)
+{
+ int* accum = context;
+ CHK(hit && ray_org && ray_dir && ray_range && context);
+ CHK(!SVX_HIT_NONE(hit));
+ *accum += *(char*)hit->voxel.data;
+ return 1;
+}
+
+static int
+hit_challenge(const struct svx_hit* hit, void* context)
+{
+ (void)context;
+ CHK(hit);
+ CHK(!SVX_HIT_NONE(hit));
+ return 1;
+}
+
int
main(int argc, char** argv)
{
struct scene scn;
+ struct ray r;
struct svx_device* dev = NULL;
struct svx_octree* oct = NULL;
+ struct svx_octree_desc octree_desc = SVX_OCTREE_DESC_NULL;
struct svx_voxel_desc voxel_desc = SVX_VOXEL_DESC_NULL;
+ struct svx_hit hit = SVX_HIT_NULL;
+ struct svx_hit hit2 = SVX_HIT_NULL;
const double lower[3] = {-1,-1,-1};
const double upper[3] = { 1, 1, 1};
const size_t def[3] = {32, 32, 32};
double scnsz[3];
+ double vxsz;
+ double dst;
+ int accum;
(void)argc, (void)argv;
CHK(svx_device_create(NULL, NULL, 1, &dev) == RES_OK);
@@ -159,6 +237,83 @@ main(int argc, char** argv)
dump_data(stdout, oct, CHAR, 1, write_scalars);
+ #define RT svx_octree_trace_ray
+ d3(r.org, -5,-5, 0);
+ d3(r.dir, 0, 1, 0);
+ d2(r.range, 0, INF);
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, NULL, NULL, &hit) == RES_OK);
+ CHK(SVX_HIT_NONE(&hit));
+
+ r.org[0] = 0;
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, NULL, NULL, &hit) == RES_OK);
+ CHK(!SVX_HIT_NONE(&hit));
+ CHK(eq_eps(hit.distance, hit.voxel.lower[1] - r.org[1], 1.e-6));
+ CHK(hit.voxel.is_leaf);
+ CHK(*(char*)hit.voxel.data == 0);
+
+ /* Use challenge functor to intersect voxels that are not leaves */
+ CHK(svx_octree_get_desc(oct, &octree_desc) == RES_OK);
+ CHK(RT(oct, r.org, r.dir, r.range, hit_challenge, NULL, NULL, &hit2) == RES_OK);
+ CHK(!SVX_HIT_NONE(&hit2));
+ CHK(!SVX_VOXEL_EQ(&hit.voxel, &hit2.voxel));
+ CHK(hit2.voxel.is_leaf == 0);
+ CHK(*(char*)hit2.voxel.data == 1);
+ CHK(eq_eps(hit.distance, hit2.distance, 1.e-6));
+
+ /* Use filter function to discard leaves with a value == 0 */
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, hit_filter, &r, &hit) == RES_OK);
+ CHK(!SVX_HIT_NONE(&hit));
+ CHK(eq_eps(hit.distance, hit.voxel.lower[1] - r.org[1], 1.e-6));
+ CHK(hit.voxel.is_leaf);
+ CHK(*(char*)hit.voxel.data == 1);
+
+ /* Use th ray range to vvoid the intersection closest voxel */
+ r.range[1] = nextafter(hit.distance, -1);
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, hit_filter, &r, &hit) == RES_OK);
+ CHK(SVX_HIT_NONE(&hit));
+
+ r.range[1] = INF;
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, hit_filter, &r, &hit) == RES_OK);
+ CHK(!SVX_HIT_NONE(&hit));
+ CHK(*(char*)hit.voxel.data == 1);
+ CHK(hit.voxel.is_leaf);
+
+ /* Use the ray range to discard the closest voxel */
+ dst = hit.voxel.upper[1] - r.org[1];
+ r.range[0] = nextafter(dst, DBL_MAX);
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, hit_filter, &r, &hit2) == RES_OK);
+ CHK(!SVX_HIT_NONE(&hit2));
+ CHK(!SVX_VOXEL_EQ(&hit.voxel, &hit2.voxel));
+ vxsz = hit2.voxel.upper[1] - hit2.voxel.lower[1];
+ CHK(eq_eps(hit2.distance, dst + vxsz, 1.e-6));
+ CHK(*(char*)hit.voxel.data == 1);
+ CHK(hit.voxel.is_leaf);
+
+ /* Adjust the ray range to hit the interior of the closest voxel */
+ r.range[0] = nextafter(hit.distance, DBL_MAX);
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, hit_filter, &r, &hit2) == RES_OK);
+ CHK(!SVX_HIT_NONE(&hit2));
+ CHK(SVX_VOXEL_EQ(&hit.voxel, &hit2.voxel));
+ CHK(eq_eps(hit2.distance, dst, 1.e-6));
+ CHK(*(char*)hit.voxel.data == 1);
+ CHK(hit.voxel.is_leaf);
+
+ /* Discard the closest voxel with the filter function */
+ r.range[0] = 0;
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, hit_filter2, &hit.voxel, &hit2) == RES_OK);
+ CHK(eq_eps(hit2.distance, hit2.voxel.lower[1] - r.org[1], 1.e-6));
+ CHK(!SVX_HIT_NONE(&hit2));
+ CHK(!SVX_VOXEL_EQ(&hit.voxel, &hit2.voxel));
+ CHK(eq_eps(hit2.distance, dst, 1.e-6));
+ CHK(*(char*)hit.voxel.data == 1);
+ CHK(hit.voxel.is_leaf);
+
+ /* Use the filter functor to accumulate the leaves */
+ accum = 0;
+ CHK(RT(oct, r.org, r.dir, r.range, NULL, hit_filter3, &accum, &hit) == RES_OK);
+ CHK(SVX_HIT_NONE(&hit));
+ CHK(accum != 0);
+
CHK(svx_octree_ref_put(oct) == RES_OK);
CHK(svx_device_ref_put(dev) == RES_OK);
CHK(mem_allocated_size() == 0);