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 dff27e2ea9869abde08d775cd52772c9c319e2d6
parent 27cb32ed16e7e7e223cb6bb51411eb3461d86313
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 19 Nov 2020 11:51:14 +0100

Merge branch 'release_0.7.3'

Diffstat:
MREADME.md | 9++++++++-
Mcmake/CMakeLists.txt | 2+-
Msrc/s3d.h | 8++++----
Msrc/s3d_backend.h | 12++++++++++++
Msrc/s3d_scene_view_closest_point.c | 55+++++++++++++++++++++++++++++++++----------------------
Msrc/test_s3d_closest_point.c | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
6 files changed, 172 insertions(+), 37 deletions(-)

diff --git a/README.md b/README.md @@ -120,9 +120,16 @@ with `<STAR3D_INSTALL_DIR>` the install directory of Star-3D and ## Release notes +### Version 0.7.3 + +- Fix the `s3d_scene_view_closest_point` function on the scenes containing + instantiated meshes: the rotation of the instances was wrongly taken into + account. +- Speed up the `s3d_scene_view_closest_point` query on instantiated meshes. + ### Version 0.7.2 -- Fix a precision issue in the `s3d_scene_view_closes_point` function: the +- Fix a precision issue in the `s3d_scene_view_closest_point` function: the returned hit could have invalid barycentric coordinates. ### Version 0.7.1 diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -58,7 +58,7 @@ endif() ################################################################################ set(VERSION_MAJOR 0) set(VERSION_MINOR 7) -set(VERSION_PATCH 2) +set(VERSION_PATCH 3) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(S3D_FILES_SRC diff --git a/src/s3d.h b/src/s3d.h @@ -207,7 +207,7 @@ static const struct s3d_accel_struct_conf S3D_ACCEL_STRUCT_CONF_DEFAULT = /* Filter function data type. One can define such function to discard * intersections along a ray or the result of a closest point query with * respect to user defined criteria, e.g.: masked/transparent primitive, etc. - * Return 0 or the intersection is not discarded and a value not equal to zero + * Return 0 if or the intersection is not discarded and a value not equal to zero * otherwise. */ typedef int (*s3d_hit_filter_function_T) @@ -470,16 +470,16 @@ s3d_shape_flip_surface /******************************************************************************* * Primitive API - Define a geometric primitive of a shape ******************************************************************************/ -/* Retrieve the attribute of the shape primitive `iprim' at the barycentric +/* Retrieve the attribute of the shape primitive `prim' at the barycentric * coordinates `uv' */ S3D_API res_T s3d_primitive_get_attrib (const struct s3d_primitive* prim, const enum s3d_attrib_usage attr, /* Attribute to retrieve */ - const float st[2], /* Parametric coordinates of `attr' on `iprim' */ + const float st[2], /* Parametric coordinates of `attr' on `prim' */ struct s3d_attrib* attrib); /* Resulting attrib */ -/* Retrieve if the primitive `iprim' has the attribute `attr' */ +/* Retrieve if the primitive `prim' has the attribute `attr' */ S3D_API res_T s3d_primitive_has_attrib (const struct s3d_primitive* prim, diff --git a/src/s3d_backend.h b/src/s3d_backend.h @@ -33,6 +33,18 @@ #ifndef S3D_BACKEND_H #define S3D_BACKEND_H +#include <rsys/rsys.h> /* COMPILER_CL */ + +#ifdef COMPILER_CL + /* Structure was padded due to alignment specifier */ + #pragma warning(push) + #pragma warning(disable: 4324) +#endif + #include <embree3/rtcore.h> +#ifdef COMPILER_CL + #pragma warning(pop) +#endif + #endif /* S3D_BACKEND_H */ diff --git a/src/s3d_scene_view_closest_point.c b/src/s3d_scene_view_closest_point.c @@ -171,7 +171,8 @@ closest_point_mesh struct hit_filter* filter = NULL; const uint32_t* ids = NULL; float closest_point[3]; - float query_pos[3]; + float query_pos_ws[3]; /* World space query position */ + float query_pos_ls[3]; /* Local space query position */ float v0[3], v1[3], v2[3]; float E0[3], E1[3], Ng[3]; float vec[3]; @@ -191,34 +192,46 @@ closest_point_mesh f3_set(v2, mesh_get_pos(geom->data.mesh) + ids[2]*3/*#coords per vertex*/); /* Local copy of the query position */ - query_pos[0] = args->query->x; - query_pos[1] = args->query->y; - query_pos[2] = args->query->z; - - if(args->context->instStackSize) { /* The mesh is instantiated */ - const float* transform; - transform = inst->data.instance->transform; + query_pos_ws[0] = args->query->x; + query_pos_ws[1] = args->query->y; + query_pos_ws[2] = args->query->z; + + if(!args->context->instStackSize) { /* The mesh is instantiated */ + query_pos_ls[0] = query_pos_ws[0]; + query_pos_ls[1] = query_pos_ws[1]; + query_pos_ls[2] = query_pos_ws[2]; + } else { + const float* world2inst; + float a[3], b[3], c[3]; ASSERT(args->context->instStackSize == 1); - ASSERT(args->similarityScale == 1); ASSERT(inst && inst->type == GEOM_INSTANCE); - ASSERT(f3_eq_eps(transform+0, args->context->inst2world[0]+0, 1.e-6f)); - ASSERT(f3_eq_eps(transform+3, args->context->inst2world[0]+4, 1.e-6f)); - ASSERT(f3_eq_eps(transform+6, args->context->inst2world[0]+8, 1.e-6f)); - ASSERT(f3_eq_eps(transform+9, args->context->inst2world[0]+12,1.e-6f)); - /* Transform the triangle vertices in world space */ - f3_add(v0, f33_mulf3(v0, transform, v0), transform+9); - f3_add(v1, f33_mulf3(v1, transform, v1), transform+9); - f3_add(v2, f33_mulf3(v2, transform, v2), transform+9); + world2inst = args->context->world2inst[0]; + + /* Transform the query position in instance space */ + f3_mulf(a, world2inst+0, query_pos_ws[0]); + f3_mulf(b, world2inst+4, query_pos_ws[1]); + f3_mulf(c, world2inst+8, query_pos_ws[2]); + query_pos_ls[0] = a[0] + b[0] + c[0] + world2inst[12]; + query_pos_ls[1] = a[1] + b[1] + c[1] + world2inst[13]; + query_pos_ls[2] = a[2] + b[2] + c[2] + world2inst[14]; flip_surface = inst->flip_surface; } /* Compute the closest point onto the triangle from the submitted point */ - closest_point_triangle(query_pos, v0, v1, v2, closest_point, uv); + closest_point_triangle(query_pos_ls, v0, v1, v2, closest_point, uv); - f3_sub(vec, closest_point, query_pos); + /* Compute the distance */ + f3_sub(vec, closest_point, query_pos_ls); dst = f3_len(vec); + + /* Transform the distance in world space */ + if(args->context->instStackSize != 0) { + ASSERT(args->similarityScale > 0); + dst /= args->similarityScale; + } + if(dst >= args->query->radius) return 0; /* Compute the triangle normal in world space */ @@ -252,7 +265,7 @@ closest_point_mesh * computed hit */ filter = &geom->data.mesh->filter; if(filter->func - && filter->func(&hit, query_pos, vec, query_data, filter->data)) { + && filter->func(&hit, query_pos_ws, vec, query_data, filter->data)) { return 0; /* This point is filtered. Discard it! */ } @@ -296,7 +309,6 @@ closest_point_sphere const float* transform; transform = inst->data.instance->transform; ASSERT(args->context->instStackSize == 1); - ASSERT(args->similarityScale == 1); ASSERT(inst && inst->type == GEOM_INSTANCE); ASSERT(f3_eq_eps(transform+0, args->context->inst2world[0]+0, 1.e-6f)); ASSERT(f3_eq_eps(transform+3, args->context->inst2world[0]+4, 1.e-6f)); @@ -390,7 +402,6 @@ closest_point(struct RTCPointQueryFunctionArguments* args) (ctx->scnview, args->geomID); } else { ASSERT(args->context->instStackSize == 1); - ASSERT(args->similarityScale == 1); inst = scene_view_geometry_from_embree_id (ctx->scnview, args->context->instID[0]); geom = scene_view_geometry_from_embree_id diff --git a/src/test_s3d_closest_point.c b/src/test_s3d_closest_point.c @@ -35,6 +35,7 @@ #include "test_s3d_utils.h" #include <rsys/float3.h> +#include <rsys/float33.h> #include <limits.h> #define ON_EDGE_EPSILON 1.e-4f @@ -80,11 +81,12 @@ closest_point_triangle float ab[3], ac[3], bc[3]; float ap[3], bp[3], cp[3]; float d1, d2, d3, d4, d5, d6, d; + float lab, lac, lbc; 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)); + lab = f3_normalize(ab, f3_sub(ab, b, a)); + lac = f3_normalize(ac, f3_sub(ac, c, a)); + lbc = f3_normalize(bc, f3_sub(bc, c, b)); /* Compute the triangle normal */ f3_cross(N, ac, ab); @@ -108,22 +110,22 @@ closest_point_triangle if(d5 <= 0 && d6 <= 0) return f3_set(pt, c); /* Check if the nearest point is on the 1st triangle edge */ - f3_normalize(Nbc, f3_cross(Nab, ab, N)); + f3_normalize(Nab, f3_cross(Nab, ab, N)); if(f3_dot(Nab, ap) <= 0) { - return f3_add(pt, a, f3_mulf(pt, ab, d1)); + return f3_add(pt, a, f3_mulf(pt, ab, MMIN(d1, lab))); } /* Check if the nearest point is on the 2nd triangle edge */ f3_normalize(Nbc, f3_cross(Nbc, bc, N)); if(f3_dot(Nbc, bp) <= 0) { - return f3_add(pt, b, f3_mulf(pt, bc, d3)); + return f3_add(pt, b, f3_mulf(pt, bc, MMIN(d3, lbc))); } /* Check if the nearest point is on the 3rd triangle edge */ f3_normalize(Nca, 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)); + return f3_add(pt, c, f3_mulf(pt, ac,-MMIN(d5, lac))); } /* The nearest point is in the triangle */ @@ -746,10 +748,28 @@ test_cbox(struct s3d_device* dev) mid[1] = (low[1] + upp[1]) * 0.5f; mid[2] = (low[2] + upp[2]) * 0.5f; + /* Filter nothing */ + filter_data.geom_to_filter[0] = S3D_INVALID_ID; + filter_data.geom_to_filter[1] = S3D_INVALID_ID; + filter_data.geom_to_filter[2] = S3D_INVALID_ID; + + /* Check a specific position that exhibits a precision issues of the + * closest_point_triangle test routine */ + { + union { float f; uint32_t ui; } ucast; + pos[0] = (ucast.ui = 0xc386cc9a, ucast.f); + pos[1] = (ucast.ui = 0x43e635b8, ucast.f); + pos[2] = (ucast.ui = 0x4319ab78, ucast.f); + f3_set(filter_data.query_pos, pos); + CHK(s3d_scene_view_closest_point + (scnview, pos, (float)INF, &filter_data, &hit) == RES_OK); + check_closest_point_cbox(pos, geom_id, &hit); + } + /* Check closest point query on Cornell box */ FOR_EACH(i, 0, 10000) { /* Randomly generate a point in a bounding box that is 2 times the size of - * the triangle AABB */ + * the cornell box AABB */ pos[0] = mid[0] + (rand_canonic() * 2 - 1) * (upp[0] - low[0]); pos[1] = mid[1] + (rand_canonic() * 2 - 1) * (upp[1] - low[1]); pos[2] = mid[2] + (rand_canonic() * 2 - 1) * (upp[2] - low[2]); @@ -768,7 +788,7 @@ test_cbox(struct s3d_device* dev) /* Check closest point query filtering */ FOR_EACH(i, 0, 10000) { /* Randomly generate a point in a bounding box that is 2 times the size of - * the triangle AABB */ + * the cornell box AABB */ pos[0] = mid[0] + (rand_canonic() * 2 - 1) * (upp[0] - low[0]); pos[1] = mid[1] + (rand_canonic() * 2 - 1) * (upp[1] - low[1]); pos[2] = mid[2] + (rand_canonic() * 2 - 1) * (upp[2] - low[2]); @@ -932,6 +952,90 @@ test_single_triangle(struct s3d_device* dev) CHK(s3d_scene_ref_put(scn) == RES_OK); } +static void +test_single_triangle_instantiated(struct s3d_device* dev) +{ + union { float f; uint32_t u32; } ucast; + struct s3d_scene* scn = NULL; + struct s3d_shape* shape = NULL; + struct s3d_scene_view* view0 = NULL; + struct s3d_scene_view* view1 = NULL; + struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL; + struct s3d_hit hit0 = S3D_HIT_NULL; + struct s3d_hit hit1 = S3D_HIT_NULL; + float transform[12]; + float vertices[9]; + float transformed_vertices[9]; + float query_pos[3]; + + vdata.usage = S3D_POSITION; + vdata.type = S3D_FLOAT3; + vdata.get = triangle_get_pos; + + /* Setup the query position. The following data are retrieved from a user + * case and are thus setuped as it, in its raw binary format */ + query_pos[0] = (ucast.u32 = 0xc1dc7a9e, ucast.f); + query_pos[1] = (ucast.u32 = 0xc382179f, ucast.f); + query_pos[2] = (ucast.u32 = 0xc32181b0, ucast.f); + + f3(vertices+0, -28.5f, -298.5f, 69.964429f); + f3(vertices+3, -27.0f, -298.5f, 69.899651f); + f3(vertices+6, -27.0f, -297.0f, 69.204593f); + + /* Setup the triangle transformation */ + f33_rotation(transform, (float)MDEG2RAD(45.0), 0, 0); + f3_splat(transform+9, 0); + + /* Transform the triangle directly */ + f33_mulf3(transformed_vertices+0, transform, vertices+0); + f33_mulf3(transformed_vertices+3, transform, vertices+3); + f33_mulf3(transformed_vertices+6, transform, vertices+6); + f3_add(transformed_vertices+0, transformed_vertices+0, transform+9); + f3_add(transformed_vertices+1, transformed_vertices+1, transform+9); + f3_add(transformed_vertices+2, transformed_vertices+2, transform+9); + + /* Setup the scene with the pre-transformed triangle */ + CHK(s3d_scene_create(dev, &scn) == RES_OK); + CHK(s3d_shape_create_mesh(dev, &shape) == RES_OK); + CHK(s3d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s3d_mesh_setup_indexed_vertices + (shape, 1, triangle_get_ids, 3, &vdata, 1, transformed_vertices) == RES_OK); + CHK(s3d_scene_view_create(scn, S3D_TRACE, &view0) == RES_OK); + CHK(s3d_scene_ref_put(scn) == RES_OK); + CHK(s3d_shape_ref_put(shape) == RES_OK); + + /* Setup the same scene with the transformation performed by Star-3D through + * instantiation */ + CHK(s3d_scene_create(dev, &scn) == RES_OK); + CHK(s3d_shape_create_mesh(dev, &shape) == RES_OK); + CHK(s3d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s3d_mesh_setup_indexed_vertices + (shape, 1, triangle_get_ids, 3, &vdata, 1, vertices) == RES_OK); + CHK(s3d_shape_ref_put(shape) == RES_OK); + CHK(s3d_scene_instantiate(scn, &shape) == RES_OK); + CHK(s3d_instance_set_transform(shape, transform) == RES_OK); + CHK(s3d_scene_ref_put(scn) == RES_OK); + CHK(s3d_scene_create(dev, &scn) == RES_OK); + CHK(s3d_scene_attach_shape(scn, shape) == RES_OK); + CHK(s3d_scene_view_create(scn, S3D_TRACE, &view1) == RES_OK); + CHK(s3d_scene_ref_put(scn) == RES_OK); + CHK(s3d_shape_ref_put(shape) == RES_OK); + + /* Find the closest point */ + CHK(s3d_scene_view_closest_point + (view0, query_pos, (float)INF, NULL, &hit0) == RES_OK); + CHK(s3d_scene_view_closest_point + (view1, query_pos, (float)INF, NULL, &hit1) == RES_OK); + + /* Check that the found hits are the same */ + CHK(!S3D_HIT_NONE(&hit0)); + CHK(!S3D_HIT_NONE(&hit1)); + CHK(eq_epsf(hit0.distance, hit1.distance, 1.e-6f)); + + CHK(s3d_scene_view_ref_put(view0) == RES_OK); + CHK(s3d_scene_view_ref_put(view1) == RES_OK); +} + /******************************************************************************* * Miscellaneous test ******************************************************************************/ @@ -976,6 +1080,7 @@ main(int argc, char** argv) test_api(dev); test_single_triangle(dev); + test_single_triangle_instantiated(dev); test_cbox(dev); test_sphere(dev); test_cbox_sphere(dev);