rngrd

Describe a surface and its physical properties
git clone git://git.meso-star.fr/rngrd.git
Log | Files | Refs | README | LICENSE

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:
Mcmake/CMakeLists.txt | 4++++
Msrc/rngrd.h | 27++++++++++++++++++++++++++-
Msrc/rngrd_setup_mesh.c | 126++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
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));