commit f3c2adce4b40ff2754520b420cc5cff2598e7a80
parent 2e72cca8cf66c111d3b84fe0386c7f041ffedf43
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 13 Jul 2022 10:07:57 +0200
Add a filtering function to the Star3D mesh
Diffstat:
3 files changed, 152 insertions(+), 5 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -68,6 +68,10 @@ rcmake_prepend_path(RNGRD_FILES_DOC ${PROJECT_SOURCE_DIR}/../)
add_library(rngrd SHARED ${RNGRD_FILES_SRC} ${RNGRD_FILES_INC} ${RNGRD_FILES_INC_API})
target_link_libraries(rngrd RSys Star3D StarMesh)
+if(CMAKE_COMPILER_IS_GNUCC)
+ target_link_libraries(rngrd m)
+endif()
+
set_target_properties(rngrd PROPERTIES
DEFINE_SYMBOL RNGRD_SHARED_BUILD
VERSION ${VERSION}
diff --git a/src/rngrd.h b/src/rngrd.h
@@ -21,6 +21,8 @@
#ifndef RNGRD_H
#define RNGRD_H
+#include <star/s3d.h>
+
#include <rsys/rsys.h>
/* Library symbol management */
@@ -55,7 +57,6 @@ struct rngrd_create_args {
struct mem_allocator* allocator; /* NULL <=> use default allocator */
int verbose; /* Verbosity level */
};
-
#define RNGRD_CREATE_ARGS_DEFAULT__ { \
NULL, /* Star-Mesh geometry */ \
NULL, /* Per-triangle properties */ \
@@ -69,6 +70,30 @@ struct rngrd_create_args {
static const struct rngrd_create_args RNDGR_CREATE_ARGS_DEFAULT =
RNGRD_CREATE_ARGS_DEFAULT__;
+struct rngrd_trace_ray_args {
+ double org[3]; /* Ray origin */
+ double dir[3]; /* Ray direction */
+ double range[2]; /* Ray range */
+
+ /* Intersection from which the ray starts. Used to avoid self intersection */
+ struct s3d_hit hit_from;
+
+ s3d_hit_filter_function_T filter; /* NULL <=> Stop RT at 1st hit triangle */
+ void* filter_data; /* User data send to the filter function */
+};
+#define RNGRD_TRACE_RAY_ARGS_DEFAULT__ { \
+ {0,0,0}, /* Ray origin */ \
+ {0,0,1}, /* Ray direction */ \
+ {0,DBL_MAX}, /* Ray range */ \
+ \
+ S3D_HIT_NULL__, /* Hit from */ \
+ \
+ NULL, /* Filter function */ \
+ NULL /* Filter data */ \
+}
+static const struct rngrd_trace_ray_args RNGRD_TRACE_RAY_ARGS_DEFAULT =
+ RNGRD_TRACE_RAY_ARGS_DEFAULT__;
+
/* Opaque data types */
struct rngrd;
diff --git a/src/rngrd_setup_mesh.c b/src/rngrd_setup_mesh.c
@@ -26,10 +26,129 @@
#include <star/smsh.h>
#include <rsys/cstr.h>
+#include <rsys/float3.h>
/*******************************************************************************
* Helper functions
******************************************************************************/
+static INLINE int
+hit_on_edge
+ (const struct s3d_hit* hit,
+ const float org[3],
+ const float dir[3])
+{
+ const float on_edge_epsilon = 1.e-4f;
+
+ struct s3d_attrib v0, v1, v2;
+ float E0[3], E1[3], N[3];
+ float tri_2area;
+ float hit_2area0;
+ float hit_2area1;
+ float hit_2area2;
+ float hit_pos[3];
+ ASSERT(hit && !S3D_HIT_NONE(hit) && org && dir);
+
+ /* Retrieve the triangle vertices */
+ S3D(triangle_get_vertex_attrib(&hit->prim, 0, S3D_POSITION, &v0));
+ S3D(triangle_get_vertex_attrib(&hit->prim, 1, S3D_POSITION, &v1));
+ S3D(triangle_get_vertex_attrib(&hit->prim, 2, S3D_POSITION, &v2));
+
+ /* Compute the intersection position */
+ f3_add(hit_pos, org, f3_mulf(hit_pos, dir, hit->distance));
+
+ /* Compute the area of the intersected triangle. Actually we compute the
+ * area*2 to save computation time */
+ f3_sub(E0, v1.value, v0.value);
+ f3_sub(E1, v2.value, v0.value);
+ tri_2area = f3_len(f3_cross(N, E0, E1));
+
+ /* Calculate the areas of the 3 triangles formed by an edge of the
+ * intersecting triangle and the position of intersection. Actually we
+ * compute the areas*2 to save computation time. */
+ f3_sub(E0, v0.value, hit_pos);
+ f3_sub(E1, v1.value, hit_pos);
+ hit_2area0 = f3_len(f3_cross(N, E0, E1));
+ f3_sub(E0, v1.value, hit_pos);
+ f3_sub(E1, v2.value, hit_pos);
+ hit_2area1 = f3_len(f3_cross(N, E0, E1));
+ f3_sub(E0, v2.value, hit_pos);
+ f3_sub(E1, v0.value, hit_pos);
+ hit_2area2 = f3_len(f3_cross(N, E0, E1));
+
+ if(hit_2area0/tri_2area < on_edge_epsilon
+ || hit_2area1/tri_2area < on_edge_epsilon
+ || hit_2area2/tri_2area < on_edge_epsilon)
+ return 1;
+
+ return 0;
+}
+
+/* Returns 1 if the intersection found is a self-intersection, i.e. if the
+ * intersection triangle is the triangle from which the ray starts. */
+static INLINE int
+self_hit
+ (const struct s3d_hit* hit,
+ const float ray_org[3],
+ const float ray_dir[3],
+ const float ray_range[2],
+ const struct s3d_hit* hit_from)
+{
+ ASSERT(hit && hit_from);
+ (void)ray_org, (void)ray_dir;
+
+ if(S3D_HIT_NONE(hit_from))
+ return 0;
+
+ /* The intersected triangle is the one from which the ray starts. We ignore
+ * this intersection */
+ if(S3D_PRIMITIVE_EQ(&hit->prim, &hit_from->prim))
+ return 1;
+
+ /* If the intersection is close to the origin of the ray, we check if it is
+ * on an edge/vertex shared by the triangle from which the ray originates. If
+ * yes, we assume self-intersection and ignore it. */
+ if(hit->distance/ray_range[1] < 1.e-4f
+ && hit_on_edge(hit_from, ray_org, ray_dir)
+ && hit_on_edge(hit, ray_org, ray_dir)) {
+ return 1;
+ }
+
+ /* No self hit */
+ return 0;
+}
+
+static int
+mesh_filter
+ (const struct s3d_hit* hit,
+ const float ray_org[3],
+ const float ray_dir[3],
+ const float ray_range[2],
+ void* ray_data,
+ void* filter_data)
+{
+ const struct rngrd_trace_ray_args* ray_args = ray_data;
+ (void)filter_data;
+
+ /* Internally, Star-3D relies on Embree which, due to numerical imprecision,
+ * can find intersections whose distances are not strictly within the ray
+ * range. We reject these intersections. */
+ if(hit->distance <= ray_range[0] || hit->distance >= ray_range[1])
+ return 1;
+
+ if(!ray_args) /* Nothing more to do */
+ return 0;
+
+ /* Discard this intersection */
+ if(self_hit(hit, ray_org, ray_dir, ray_range, &ray_args->hit_from))
+ return 1;
+
+ if(!ray_args->filter) /* No user-defined filter functions */
+ return 0;
+
+ return ray_args->filter /* Invoke user-defined filtering */
+ (hit, ray_org, ray_dir, ray_range, ray_args->filter_data, filter_data);
+}
+
static void
get_indices(const unsigned itri, unsigned ids[3], void* ctx)
{
@@ -100,8 +219,11 @@ setup_s3d(struct rngrd* ground, struct smsh_desc* smsh_desc)
res = s3d_device_create
(ground->logger, ground->allocator, ground->verbose, &ground->s3d);
if(res != RES_OK) goto error;
+
res = s3d_shape_create_mesh(ground->s3d, &mesh);
if(res != RES_OK) goto error;
+ res = s3d_mesh_set_hit_filter_function(mesh, mesh_filter, NULL);
+ if(res != RES_OK) goto error;
res = s3d_scene_create(ground->s3d, &scene);
if(res != RES_OK) goto error;
res = s3d_scene_attach_shape(scene, mesh);
@@ -114,9 +236,6 @@ setup_s3d(struct rngrd* ground, struct smsh_desc* smsh_desc)
get_indices, (unsigned)smsh_desc->nnodes, &vdata, 1, smsh_desc);
if(res != RES_OK) goto error;
- /* TODO set the filter function
- * TODO demander à Vincent si on peut imposer un sens pour les normales */
-
res = s3d_scene_view_create(scene, S3D_TRACE, &ground->s3d_view);
if(res != RES_OK) goto error;
@@ -124,7 +243,6 @@ exit:
if(mesh) S3D(shape_ref_put(mesh));
if(scene) S3D(scene_ref_put(scene));
return res;
-
error:
log_err(ground, "Could not setup the Star-3D data structures -- %s\n",
res_to_cstr(res));