star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.fr/star-3d.git
Log | Files | Refs | README | LICENSE

commit 6382123ac1077a616def64a6504dd30dfdc9a25f
parent 75f1f08a29585a9b425f144e86d84e82cb92fda4
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  4 Oct 2019 15:50:05 +0200

Perform basic tests on s3d_scene_view_point_query

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/s3d.h | 2+-
Asrc/test_s3d_point_query.c | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 273 insertions(+), 1 deletion(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -140,6 +140,7 @@ if(NOT NO_TEST) new_test(test_s3d_shape) new_test(test_s3d_sphere) new_test(test_s3d_sphere_box) + new_test(test_s3d_point_query) new_test(test_s3d_primitive) new_test(test_s3d_trace_ray_instance) new_test(test_s3d_trace_ray_sphere) diff --git a/src/s3d.h b/src/s3d.h @@ -333,7 +333,7 @@ S3D_API res_T s3d_scene_view_point_query (struct s3d_scene_view* scnview, const float pos[3], /* Position to query */ - const float radius, /* Maxium search distance around pos */ + const float radius, /* Search distance in [0, radius[ */ void* query_data, /* User data sent to the hit filter func. May be NULL */ struct s3d_hit* hit); diff --git a/src/test_s3d_point_query.c b/src/test_s3d_point_query.c @@ -0,0 +1,271 @@ +/* Copyright (C) 2015-2019 |Meso|Star> (contact@meso-star.com) + * + * This software is a computer program whose purpose is to describe a + * virtual 3D environment that can be ray-traced and sampled both robustly + * and efficiently. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#include "s3d.h" +#include "test_s3d_utils.h" + +#include <rsys/float3.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +/* Inefficient function that computes the point onto the triangle that ensures + * the minimum distance between the submitted `pos' and the triangle. Use this + * routine to cross check the result of the s3d_scene_view_point_query function + * that internally rely on a more efficient implementation */ +static float* +closest_point_triangle + (const float p[3], /* Input pos */ + const float a[3], /* 1st triangle vertex */ + const float b[3], /* 2nd triangle vertex */ + const float c[3], /* 3rd triangle vertex */ + float pt[3]) /* Closest point of pos onto the triangle */ +{ + float N[3]; /* Triangle normal */ + float Nab[3], Nbc[3], Nca[3]; /* Edge normals */ + float ab[3], ac[3], bc[3]; + float ap[3], bp[3], cp[3]; + float d1, d2, d3, d4, d5, d6, d; + CHK(p && a && b && c && pt); + + f3_normalize(ab, f3_sub(ab, b, a)); + f3_normalize(ac, f3_sub(ac, c, a)); + f3_normalize(bc, f3_sub(bc, c, b)); + + /* Compute the triangle normal */ + f3_cross(N, ac, ab); + + /* Check if the nearest point is the 1st triangle vertex */ + f3_sub(ap, p, a); + d1 = f3_dot(ab, ap); + d2 = f3_dot(ac, ap); + if(d1 <= 0 && d2 <= 0) return f3_set(pt, a); + + /* Check if the nearest point is the 2nd triangle vertex */ + f3_sub(bp, p, b); + d3 = f3_dot(bc, bp); + d4 =-f3_dot(ab, bp); + if(d3 <= 0 && d4 <= 0) return f3_set(pt, b); + + /* Check if the nearest point is the 3rd triangle vertex */ + f3_sub(cp, p, c); + d5 =-f3_dot(ac, cp); + d6 =-f3_dot(bc, cp); + if(d5 <= 0 && d6 <= 0) return f3_set(pt, c); + + /* Check if the nearest point is on the 1st triangle edge */ + f3_cross(Nab, ab, N); + if(f3_dot(Nab, ap) <= 0) { + return f3_add(pt, a, f3_mulf(pt, ab, d1)); + } + + /* Check if the nearest point is on the 2nd triangle edge */ + f3_cross(Nbc, bc, N); + if(f3_dot(Nbc, bp) <= 0) { + return f3_add(pt, b, f3_mulf(pt, bc, d3)); + } + + /* Check if the nearest point is on the 3rd triangle edge */ + f3_cross(Nca, ac, N); + f3_minus(Nca, Nca); + if(f3_dot(Nca, cp) <= 0) { + return f3_add(pt, c, f3_mulf(pt, ac,-d5)); + } + + /* The nearest point is in the triangle */ + f3_normalize(N, N); + d = f3_dot(N, ap); + return f3_add(pt, p, f3_mulf(pt, N, -d)); +} + +/******************************************************************************* + * Single triangle test + ******************************************************************************/ +static void +triangle_get_ids(const unsigned itri, unsigned ids[3], void* ctx) +{ + (void)ctx; + CHK(itri == 0); + CHK(ids); + ids[0] = 0; + ids[1] = 1; + ids[2] = 2; +} + +static void +triangle_get_pos(const unsigned ivert, float pos[3], void* ctx) +{ + (void)ctx; + CHK(ivert < 3); + CHK(pos); + switch(ivert) { /* Setup a random triangle */ + case 0: f3(pos, -0.5f, -0.3f, 0.1f); break; + case 1: f3(pos, -0.4f, 0.2f, 0.3f); break; + case 2: f3(pos, 0.7f, 0.01f, -0.5f); break; + default: FATAL("Unreachable code\n"); break; + } +} + +static void +test_single_triangle(struct s3d_device* dev) +{ + struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL; + struct s3d_hit hit = S3D_HIT_NULL; + struct s3d_scene* scn = NULL; + struct s3d_scene_view* view = NULL; + struct s3d_shape* msh = NULL; + struct s3d_attrib attr; + float v0[3], v1[3], v2[3]; + float pos[3] = {0,0,0}; + float closest_pos[3] = {0,0,0}; + float low[3], upp[3]; + size_t i; + + CHK(s3d_scene_create(dev, &scn) == RES_OK); + CHK(s3d_shape_create_mesh(dev, &msh) == RES_OK); + CHK(s3d_scene_attach_shape(scn, msh) == RES_OK); + + vdata.usage = S3D_POSITION; + vdata.type = S3D_FLOAT3; + vdata.get = triangle_get_pos; + CHK(s3d_mesh_setup_indexed_vertices + (msh, 1, triangle_get_ids, 3, &vdata, 1, NULL) == RES_OK); + + CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); + + triangle_get_pos(0, v0, NULL); + triangle_get_pos(1, v1, NULL); + triangle_get_pos(2, v2, NULL); + + /* Compute the triangle AABB */ + low[0] = MMIN(MMIN(v0[0], v1[0]), v2[0]); + low[1] = MMIN(MMIN(v0[1], v1[1]), v2[1]); + low[2] = MMIN(MMIN(v0[2], v1[2]), v2[2]); + upp[0] = MMAX(MMAX(v0[0], v1[0]), v2[0]); + upp[1] = MMAX(MMAX(v0[1], v1[1]), v2[1]); + upp[2] = MMAX(MMAX(v0[2], v1[2]), v2[2]); + + FOR_EACH(i, 0, 10000) { + /* Randomly generate a point in a bounding box that is 10 times the size of + * the triangle AABB */ + pos[0] = (rand_canonic() * 2 - 1) * (upp[0] - low[0]) * 10.f; + pos[1] = (rand_canonic() * 2 - 1) * (upp[1] - low[1]) * 10.f; + pos[2] = (rand_canonic() * 2 - 1) * (upp[2] - low[2]) * 10.f; + + CHK(s3d_scene_view_point_query(view, pos, (float)INF, NULL, &hit) == RES_OK); + CHK(!S3D_HIT_NONE(&hit)); + CHK(s3d_primitive_get_attrib(&hit.prim, S3D_POSITION, hit.uv, &attr) == RES_OK); + + /* Cross check the point query result */ + closest_point_triangle(pos, v0, v1, v2, closest_pos); + CHK(f3_eq_eps(closest_pos, attr.value, 1.e-4f)); + } + + FOR_EACH(i, 0, 10000) { + float radius; + + /* Randomly generate a point in a bounding box that is 10 times the size of + * the triangle AABB */ + pos[0] = (rand_canonic() * 2 - 1) * (upp[0] - low[0]) * 10.f; + pos[1] = (rand_canonic() * 2 - 1) * (upp[1] - low[1]) * 10.f; + pos[2] = (rand_canonic() * 2 - 1) * (upp[2] - low[2]) * 10.f; + + CHK(s3d_scene_view_point_query(view, pos, (float)INF, NULL, &hit) == RES_OK); + CHK(!S3D_HIT_NONE(&hit)); + + /* Check that the radius is an exclusive upper bound */ + radius = hit.distance; + CHK(s3d_scene_view_point_query(view, pos, radius, NULL, &hit) == RES_OK); + CHK(S3D_HIT_NONE(&hit)); + radius = nextafterf(radius, FLT_MAX); + CHK(s3d_scene_view_point_query(view, pos, radius, NULL, &hit) == RES_OK); + CHK(!S3D_HIT_NONE(&hit)); + CHK(hit.distance == nextafterf(radius, 0.f)); + } + + CHK(s3d_shape_ref_put(msh) == RES_OK); + CHK(s3d_scene_view_ref_put(view) == RES_OK); + CHK(s3d_scene_ref_put(scn) == RES_OK); +} + +/******************************************************************************* + * Miscellaneous test + ******************************************************************************/ +static void +test_api(struct s3d_device* dev) +{ + struct s3d_hit hit = S3D_HIT_NULL; + struct s3d_scene* scn = NULL; + struct s3d_scene_view* view = NULL; + float pos[3] = {0,0,0}; + + CHK(s3d_scene_create(dev, &scn) == RES_OK); + CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); + + CHK(s3d_scene_view_point_query(NULL, pos, 1.f, NULL, &hit) == RES_BAD_ARG); + CHK(s3d_scene_view_point_query(view, NULL, 1.f, NULL, &hit) == RES_BAD_ARG); + CHK(s3d_scene_view_point_query(view, pos, 0.f, NULL, &hit) == RES_BAD_ARG); + CHK(s3d_scene_view_point_query(view, pos, 1.f, NULL, NULL) == RES_BAD_ARG); + CHK(s3d_scene_view_point_query(view, pos, 1.f, NULL, &hit) == RES_OK); + CHK(S3D_HIT_NONE(&hit)); + + CHK(s3d_scene_view_ref_put(view) == RES_OK); + CHK(s3d_scene_view_create(scn, S3D_SAMPLE, &view) == RES_OK); + CHK(s3d_scene_view_point_query(view, pos, 1.f, NULL, &hit) == RES_BAD_OP); + + CHK(s3d_scene_view_ref_put(view) == RES_OK); + CHK(s3d_scene_ref_put(scn) == RES_OK); +} + +/******************************************************************************* + * Main function + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct s3d_device* dev = NULL; + (void)argc, (void)argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHK(s3d_device_create(NULL, &allocator, 1, &dev) == RES_OK); + + test_api(dev); + test_single_triangle(dev); + + CHK(s3d_device_ref_put(dev) == RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +}