commit aba7e50b586998d548fa314d6b90188361a22f4f
parent 430ae867b63ad4aaaf3535edd76d6e6359fb4992
Author: Eduardo Fontana Lazzari <edufonlaz@gmail.com>
Date: Wed, 9 Jul 2025 14:20:09 +0200
Attach a hit filter function to the global scene view
During path sampling, the hit function is responsible for discarding
ray-geometry intersections that should not be considered valid.
Currently, only self-intersections are discarded. A hit is considered
a self-intersection when the primitive from which the ray originates
is the same as the one it intersects. Self-intersections are usually
detected by comparing the IDs of the primitives, assuming they belong
to the same scene_view.
However, in star-phor, there are multiple scene_views: one containing
all primitives, and one scene_view per source used in sampling.
Therefore, ID comparison is not sufficient. Instead, self-intersections
are detected by comparing the coordinates of the three vertices of the
departing and intersected primitives, which allows filtering out
self-intersections even across different scene_view contexts.
Diffstat:
| M | src/sphor_config.c | | | 67 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 67 insertions(+), 0 deletions(-)
diff --git a/src/sphor_config.c b/src/sphor_config.c
@@ -25,6 +25,7 @@
#include "sphor.h"
#include "sphor_c.h"
+#include <rsys/float3.h>
#include <star/sphin.h>
#include <star/s3d.h>
#include <star/suniq.h>
@@ -511,6 +512,69 @@ error:
goto exit;
}
+/* Check if two primitives are geometrically identical by comparing the coordinates
+ * of their vertices. If all vertices have the same positions, return 1; otherwise,
+ * return 0. This function is particularly useful when dealing with configurations
+ * composed of multiple scenes, where primitive IDs may not be reliable.
+ * In cases where primitives are known to belong to the same scene, it is simpler
+ * and more efficient to compare their IDs directly. */
+static int
+are_primitives_coordinates_identical(
+ const struct s3d_primitive* prim0,
+ const struct s3d_primitive* prim1)
+{
+ struct s3d_attrib prim0_pos;
+ struct s3d_attrib prim1_pos;
+ int i, j; /* Iterators */
+ /* Barycentric coordinates corresponding to each one of the vertices in the
+ * primitive */
+ float st[3][2] = {{0,0}, {0,1}, {1,0}};
+
+ ASSERT(NULL != prim0);
+ ASSERT(NULL != prim1);
+
+ FOR_EACH(i, 0, 3) {
+ int equal = 0;
+ s3d_primitive_get_attrib(prim0, S3D_POSITION, st[i], &prim0_pos);
+ FOR_EACH(j, 0, 3) {
+ s3d_primitive_get_attrib(prim1, S3D_POSITION, st[j], &prim1_pos);
+ if (1 == f3_eq(prim0_pos.value, prim1_pos.value)) {
+ equal = 1;
+ break;
+ }
+ }
+ if (1 != equal) {
+ /* vertex i of prim0 does not match any vertex in prim1 -> primitives
+ * vertices are not the same */
+ return 0;
+ }
+ }
+ /* All vertices in prim0 match exactly one vertex in prim1 -> primitives are
+ * the same */
+ return 1;
+}
+
+/* Function attached to the scene view that determines whether a hit is valid.
+ * Returns 0 if the hit is valid, 1 otherwise. */
+static int
+hit_filter_function
+ (const struct s3d_hit* hit,
+ const float pos[3],
+ const float dir[3],
+ const float range[2],
+ void* primitive,
+ void* interface)
+{
+ (void)pos;
+ (void)dir;
+ (void)range;
+ (void)interface;
+
+ struct s3d_primitive* prim = primitive;
+
+ return are_primitives_coordinates_identical(prim, &hit->prim);
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
@@ -652,6 +716,9 @@ setup_geometry_accel_struct
res = s3d_scene_create(device, &scene);
if (RES_OK != res) { goto error; }
+ res = s3d_mesh_set_hit_filter_function(shape, hit_filter_function, NULL);
+ if (RES_OK != res) { goto error; }
+
res = s3d_scene_attach_shape(scene, shape);
if (RES_OK != res) { goto error; }