commit 143b47ca87a51035d6ee8e44bd967a66f899d754
parent 29bad16975d47e5209a7aaab3dd823d290f144ef
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 11 Oct 2019 14:59:17 +0200
Mv the ray_trace implementation in a specific file
Diffstat:
3 files changed, 304 insertions(+), 251 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -70,6 +70,7 @@ set(S3D_FILES_SRC
s3d_scene.c
s3d_scene_view.c
s3d_scene_view_closest_point.c
+ s3d_scene_view_trace_ray.c
s3d_shape.c
s3d_sphere.c)
set(S3D_FILES_INC_API s3d.h)
diff --git a/src/s3d_scene_view.c b/src/s3d_scene_view.c
@@ -41,14 +41,6 @@
#include <rsys/float33.h>
#include <rsys/mem_allocator.h>
-struct intersect_context {
- struct RTCIntersectContext rtc;
- struct s3d_scene_view* scnview;
- void* data; /* Per ray user defined data */
- float ws_org[3]; /* World space ray origin */
- float ws_dir[3]; /* World space ray direction */
-};
-
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -138,100 +130,6 @@ on_shape_detach
}
}
-static INLINE void
-hit_setup
- (struct s3d_scene_view* scnview,
- const struct RTCRayHit* ray_hit,
- struct s3d_hit* hit)
-{
- float w;
- char flip_surface = 0;
-
- ASSERT(scnview && hit && ray_hit);
-
- if(ray_hit->hit.geomID == RTC_INVALID_GEOMETRY_ID) { /* No hit */
- *hit = S3D_HIT_NULL;
- return;
- }
-
- hit->normal[0] = ray_hit->hit.Ng_x;
- hit->normal[1] = ray_hit->hit.Ng_y;
- hit->normal[2] = ray_hit->hit.Ng_z;
- hit->distance = ray_hit->ray.tfar;
-
- if(ray_hit->hit.instID[0] == RTC_INVALID_GEOMETRY_ID) {
- struct geometry* geom_shape;
- geom_shape = scene_view_geometry_from_embree_id(scnview, ray_hit->hit.geomID);
- hit->prim.shape__ = geom_shape;
- hit->prim.inst__ = NULL;
- hit->prim.prim_id = ray_hit->hit.primID;
- hit->prim.geom_id = geom_shape->name;
- hit->prim.inst_id = S3D_INVALID_ID;
- hit->prim.scene_prim_id = /* Compute the "scene space" primitive id */
- hit->prim.prim_id /* Mesh space */
- + geom_shape->scene_prim_id_offset; /* Scene space */
-
- } else { /* The hit shape is instantiated */
- /* Retrieve the hit instance */
- struct geometry* geom_inst;
- struct geometry* geom_shape;
- float transform[9];
- geom_inst = scene_view_geometry_from_embree_id
- (scnview, ray_hit->hit.instID[0]);
- geom_shape = scene_view_geometry_from_embree_id
- (geom_inst->data.instance->scnview, ray_hit->hit.geomID);
- hit->prim.shape__ = geom_shape;
- hit->prim.inst__ = geom_inst;
- hit->prim.prim_id = ray_hit->hit.primID;
- hit->prim.geom_id = geom_shape->name;
- hit->prim.inst_id = geom_inst->name;
- hit->prim.scene_prim_id = /* Compute the "scene space" primitive id */
- hit->prim.prim_id /* Shape space */
- + geom_shape->scene_prim_id_offset /* Inst space */
- + geom_inst->scene_prim_id_offset; /* Scene space */
-
- flip_surface = geom_inst->flip_surface;
- ASSERT(hit->prim.inst__);
- ASSERT(((struct geometry*)hit->prim.inst__)->type == GEOM_INSTANCE);
-
- /* Transform the normal in world space */
- f33_invtrans(transform, geom_inst->data.instance->transform);
- f33_mulf3(hit->normal, transform, hit->normal);
- }
- ASSERT(hit->prim.shape__);
- ASSERT(((struct geometry*)hit->prim.shape__)->type == GEOM_MESH
- ||((struct geometry*)hit->prim.shape__)->type == GEOM_SPHERE);
-
- hit->uv[0] = ray_hit->hit.u;
- hit->uv[1] = ray_hit->hit.v;
-
- if(((struct geometry*)hit->prim.shape__)->type == GEOM_MESH) {
- w = 1.f - hit->uv[0] - hit->uv[1];
- ASSERT(w <= 1.f); /* This may not occurs */
- if(w < 0.f) { /* Handle precision error */
- if(hit->uv[0] > hit->uv[1]) hit->uv[0] += w;
- else hit->uv[1] += w;
- w = 0.f;
- }
-
- /* Embree stores on the u and v ray parameters the barycentric coordinates of
- * the hit with respect to the second and third triangle vertices,
- * respectively. The following code computes the barycentric coordinates of
- * the hit for the first and second triangle vertices */
- hit->uv[1] = hit->uv[0];
- hit->uv[0] = w;
-
- /* In Embree3 the normal orientation is flipped wrt to Star-3D convention */
- #if RTC_VERSION_MAJOR >= 3
- f3_minus(hit->normal, hit->normal);
- #endif
- }
-
- /* Flip geometric normal with respect to the flip surface flag */
- flip_surface ^= ((struct geometry*)hit->prim.shape__)->flip_surface;
- if(flip_surface) f3_minus(hit->normal, hit->normal);
-}
-
static res_T
embree_geometry_register
(struct s3d_scene_view* scnview,
@@ -805,7 +703,7 @@ scene_view_compute_nprims_cdf
nprims += 1;
break;
case GEOM_INSTANCE:
- /* The instance CDF was computed during its scnview synchronisation */
+ /* The instance CDF was computed during its scnview synchronisation */
len = darray_nprims_cdf_size_get
(&geom->data.instance->scnview->nprims_cdf);
if(len) {
@@ -1162,120 +1060,6 @@ s3d_scene_view_get_mask(struct s3d_scene_view* scnview, int* mask)
}
res_T
-s3d_scene_view_trace_ray
- (struct s3d_scene_view* scnview,
- const float org[3],
- const float dir[3],
- const float range[2],
- void* ray_data,
- struct s3d_hit* hit)
-{
- struct RTCRayHit ray_hit;
- struct intersect_context intersect_ctx;
- size_t i;
-
- if(!scnview || !org || !dir || !range || !hit)
- return RES_BAD_ARG;
- if(!f3_is_normalized(dir)) {
- log_error(scnview->scn->dev,
- "%s: unnormalized ray direction {%g, %g, %g}.\n",
- FUNC_NAME, SPLIT3(dir));
- return RES_BAD_ARG;
- }
- if(range[0] < 0) {
- log_error(scnview->scn->dev,
- "%s: invalid ray range [%g, %g] - it must be in [0, INF).\n",
- FUNC_NAME, range[0], range[1]);
- return RES_BAD_ARG;
- }
- if((scnview->mask & S3D_TRACE) == 0) {
- log_error(scnview->scn->dev,
- "%s: the S3D_TRACE flag is not active onto the submitted scene view.\n",
- FUNC_NAME);
- return RES_BAD_OP;
- }
- if(range[0] > range[1]) { /* Degenerated range <=> disabled ray */
- *hit = S3D_HIT_NULL;
- return RES_OK;
- }
-
- /* Initialise the ray */
- ray_hit.ray.org_x = org[0];
- ray_hit.ray.org_y = org[1];
- ray_hit.ray.org_z = org[2];
- ray_hit.ray.dir_x = dir[0];
- ray_hit.ray.dir_y = dir[1];
- ray_hit.ray.dir_z = dir[2];
- ray_hit.ray.tnear = range[0];
- ray_hit.ray.tfar = range[1];
- ray_hit.ray.time = FLT_MAX; /* Invalid fields */
- ray_hit.ray.mask = UINT_MAX; /* Invalid fields */
- ray_hit.ray.id = UINT_MAX; /* Invalid fields */
- ray_hit.ray.flags = UINT_MAX; /* Invalid fields */
-
- /* Initialise the hit */
- ray_hit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
- FOR_EACH(i, 0, RTC_MAX_INSTANCE_LEVEL_COUNT) {
- ray_hit.hit.instID[i] = RTC_INVALID_GEOMETRY_ID;
- }
-
- /* Initialise the intersect context */
- rtcInitIntersectContext(&intersect_ctx.rtc);
- intersect_ctx.ws_org[0] = org[0];
- intersect_ctx.ws_org[1] = org[1];
- intersect_ctx.ws_org[2] = org[2];
- intersect_ctx.ws_dir[0] = dir[0];
- intersect_ctx.ws_dir[1] = dir[1];
- intersect_ctx.ws_dir[2] = dir[2];
- intersect_ctx.scnview = scnview;
- intersect_ctx.data = ray_data;
-
- /* Here we go! */
- rtcIntersect1(scnview->rtc_scn, &intersect_ctx.rtc, &ray_hit);
-
- hit_setup(scnview, &ray_hit, hit);
- return RES_OK;
-}
-
-res_T
-s3d_scene_view_trace_rays
- (struct s3d_scene_view* scnview,
- const size_t nrays,
- const int mask,
- const float* origins,
- const float* directions,
- const float* ranges,
- void* rays_data,
- const size_t sizeof_ray_data,
- struct s3d_hit* hits)
-{
- size_t iray;
- size_t iorg, idir, irange, idata;
- size_t org_step, dir_step, range_step, data_step;
- res_T res = RES_OK;
-
- if(!scnview) return RES_BAD_ARG;
- if(!nrays) return RES_OK;
-
- org_step = mask & S3D_RAYS_SINGLE_ORIGIN ? 0 : 3;
- dir_step = mask & S3D_RAYS_SINGLE_DIRECTION ? 0 : 3;
- range_step = mask & S3D_RAYS_SINGLE_RANGE ? 0 : 2;
- data_step = (mask & S3D_RAYS_SINGLE_DATA) || !rays_data ? 0 : sizeof_ray_data;
- iorg = idir = irange = idata = 0;
-
- FOR_EACH(iray, 0, nrays) {
- res = s3d_scene_view_trace_ray(scnview, origins+iorg, directions+idir,
- ranges+irange, (char*)rays_data+idata, hits+iray);
- if(UNLIKELY(res != RES_OK)) break;
- iorg += org_step;
- idir += dir_step;
- irange += range_step;
- idata += data_step;
- }
- return res;
-}
-
-res_T
s3d_scene_view_sample
(struct s3d_scene_view* scnview,
const float u,
@@ -1681,37 +1465,3 @@ scene_view_destroy(struct s3d_scene_view* scnview)
MEM_RM(scnview->scn->dev->allocator, scnview);
}
-/* Wrapper between an Embree and a Star-3D filter function */
-void
-rtc_hit_filter_wrapper(const struct RTCFilterFunctionNArguments* args)
-{
- struct s3d_hit hit;
- struct RTCRayHit ray_hit;
- struct intersect_context* ctx;
- struct geometry* geom;
- struct hit_filter* filter;
- ASSERT(args && args->N == 1 && args->context && args->valid[0] != 0);
-
- rtc_rayN_get_ray(args->ray, args->N, 0, &ray_hit.ray);
- rtc_hitN_get_hit(args->hit, args->N, 0, &ray_hit.hit);
-
- ctx = CONTAINER_OF(args->context, struct intersect_context, rtc);
-
- geom = args->geometryUserPtr;
- switch(geom->type) {
- case GEOM_MESH:
- filter = &geom->data.mesh->filter;
- break;
- case GEOM_SPHERE:
- filter = &geom->data.sphere->filter;
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- ASSERT(filter->func);
-
- hit_setup(ctx->scnview, &ray_hit, &hit);
- if(filter->func(&hit, ctx->ws_org, ctx->ws_dir, ctx->data, filter->data)) {
- args->valid[0] = 0;
- }
-}
-
diff --git a/src/s3d_scene_view_trace_ray.c b/src/s3d_scene_view_trace_ray.c
@@ -0,0 +1,302 @@
+/* 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 "s3d_c.h"
+#include "s3d_device_c.h"
+#include "s3d_instance.h"
+#include "s3d_geometry.h"
+#include "s3d_mesh.h"
+#include "s3d_sphere.h"
+#include "s3d_scene_view_c.h"
+
+#include <rsys/float33.h>
+#include <limits.h>
+
+struct intersect_context {
+ struct RTCIntersectContext rtc;
+ struct s3d_scene_view* scnview;
+ void* data; /* Per ray user defined data */
+ float ws_org[3]; /* World space ray origin */
+ float ws_dir[3]; /* World space ray direction */
+};
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE void
+hit_setup
+ (struct s3d_scene_view* scnview,
+ const struct RTCRayHit* ray_hit,
+ struct s3d_hit* hit)
+{
+ float w;
+ char flip_surface = 0;
+
+ ASSERT(scnview && hit && ray_hit);
+
+ if(ray_hit->hit.geomID == RTC_INVALID_GEOMETRY_ID) { /* No hit */
+ *hit = S3D_HIT_NULL;
+ return;
+ }
+
+ hit->normal[0] = ray_hit->hit.Ng_x;
+ hit->normal[1] = ray_hit->hit.Ng_y;
+ hit->normal[2] = ray_hit->hit.Ng_z;
+ hit->distance = ray_hit->ray.tfar;
+
+ if(ray_hit->hit.instID[0] == RTC_INVALID_GEOMETRY_ID) {
+ struct geometry* geom_shape;
+ geom_shape = scene_view_geometry_from_embree_id(scnview, ray_hit->hit.geomID);
+ hit->prim.shape__ = geom_shape;
+ hit->prim.inst__ = NULL;
+ hit->prim.prim_id = ray_hit->hit.primID;
+ hit->prim.geom_id = geom_shape->name;
+ hit->prim.inst_id = S3D_INVALID_ID;
+ hit->prim.scene_prim_id = /* Compute the "scene space" primitive id */
+ hit->prim.prim_id /* Mesh space */
+ + geom_shape->scene_prim_id_offset; /* Scene space */
+
+ } else { /* The hit shape is instantiated */
+ /* Retrieve the hit instance */
+ struct geometry* geom_inst;
+ struct geometry* geom_shape;
+ float transform[9];
+ geom_inst = scene_view_geometry_from_embree_id
+ (scnview, ray_hit->hit.instID[0]);
+ geom_shape = scene_view_geometry_from_embree_id
+ (geom_inst->data.instance->scnview, ray_hit->hit.geomID);
+ hit->prim.shape__ = geom_shape;
+ hit->prim.inst__ = geom_inst;
+ hit->prim.prim_id = ray_hit->hit.primID;
+ hit->prim.geom_id = geom_shape->name;
+ hit->prim.inst_id = geom_inst->name;
+ hit->prim.scene_prim_id = /* Compute the "scene space" primitive id */
+ hit->prim.prim_id /* Shape space */
+ + geom_shape->scene_prim_id_offset /* Inst space */
+ + geom_inst->scene_prim_id_offset; /* Scene space */
+
+ flip_surface = geom_inst->flip_surface;
+ ASSERT(hit->prim.inst__);
+ ASSERT(((struct geometry*)hit->prim.inst__)->type == GEOM_INSTANCE);
+
+ /* Transform the normal in world space */
+ f33_invtrans(transform, geom_inst->data.instance->transform);
+ f33_mulf3(hit->normal, transform, hit->normal);
+ }
+ ASSERT(hit->prim.shape__);
+ ASSERT(((struct geometry*)hit->prim.shape__)->type == GEOM_MESH
+ ||((struct geometry*)hit->prim.shape__)->type == GEOM_SPHERE);
+
+ hit->uv[0] = ray_hit->hit.u;
+ hit->uv[1] = ray_hit->hit.v;
+
+ if(((struct geometry*)hit->prim.shape__)->type == GEOM_MESH) {
+ w = 1.f - hit->uv[0] - hit->uv[1];
+ ASSERT(w <= 1.f); /* This may not occurs */
+ if(w < 0.f) { /* Handle precision error */
+ if(hit->uv[0] > hit->uv[1]) hit->uv[0] += w;
+ else hit->uv[1] += w;
+ w = 0.f;
+ }
+
+ /* Embree stores on the u and v ray parameters the barycentric coordinates of
+ * the hit with respect to the second and third triangle vertices,
+ * respectively. The following code computes the barycentric coordinates of
+ * the hit for the first and second triangle vertices */
+ hit->uv[1] = hit->uv[0];
+ hit->uv[0] = w;
+
+ /* In Embree3 the normal orientation is flipped wrt to Star-3D convention */
+ #if RTC_VERSION_MAJOR >= 3
+ f3_minus(hit->normal, hit->normal);
+ #endif
+ }
+
+ /* Flip geometric normal with respect to the flip surface flag */
+ flip_surface ^= ((struct geometry*)hit->prim.shape__)->flip_surface;
+ if(flip_surface) f3_minus(hit->normal, hit->normal);
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+s3d_scene_view_trace_ray
+ (struct s3d_scene_view* scnview,
+ const float org[3],
+ const float dir[3],
+ const float range[2],
+ void* ray_data,
+ struct s3d_hit* hit)
+{
+ struct RTCRayHit ray_hit;
+ struct intersect_context intersect_ctx;
+ size_t i;
+
+ if(!scnview || !org || !dir || !range || !hit)
+ return RES_BAD_ARG;
+ if(!f3_is_normalized(dir)) {
+ log_error(scnview->scn->dev,
+ "%s: unnormalized ray direction {%g, %g, %g}.\n",
+ FUNC_NAME, SPLIT3(dir));
+ return RES_BAD_ARG;
+ }
+ if(range[0] < 0) {
+ log_error(scnview->scn->dev,
+ "%s: invalid ray range [%g, %g] - it must be in [0, INF).\n",
+ FUNC_NAME, range[0], range[1]);
+ return RES_BAD_ARG;
+ }
+ if((scnview->mask & S3D_TRACE) == 0) {
+ log_error(scnview->scn->dev,
+ "%s: the S3D_TRACE flag is not active onto the submitted scene view.\n",
+ FUNC_NAME);
+ return RES_BAD_OP;
+ }
+ if(range[0] > range[1]) { /* Degenerated range <=> disabled ray */
+ *hit = S3D_HIT_NULL;
+ return RES_OK;
+ }
+
+ /* Initialise the ray */
+ ray_hit.ray.org_x = org[0];
+ ray_hit.ray.org_y = org[1];
+ ray_hit.ray.org_z = org[2];
+ ray_hit.ray.dir_x = dir[0];
+ ray_hit.ray.dir_y = dir[1];
+ ray_hit.ray.dir_z = dir[2];
+ ray_hit.ray.tnear = range[0];
+ ray_hit.ray.tfar = range[1];
+ ray_hit.ray.time = FLT_MAX; /* Invalid fields */
+ ray_hit.ray.mask = UINT_MAX; /* Invalid fields */
+ ray_hit.ray.id = UINT_MAX; /* Invalid fields */
+ ray_hit.ray.flags = UINT_MAX; /* Invalid fields */
+
+ /* Initialise the hit */
+ ray_hit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
+ FOR_EACH(i, 0, RTC_MAX_INSTANCE_LEVEL_COUNT) {
+ ray_hit.hit.instID[i] = RTC_INVALID_GEOMETRY_ID;
+ }
+
+ /* Initialise the intersect context */
+ rtcInitIntersectContext(&intersect_ctx.rtc);
+ intersect_ctx.ws_org[0] = org[0];
+ intersect_ctx.ws_org[1] = org[1];
+ intersect_ctx.ws_org[2] = org[2];
+ intersect_ctx.ws_dir[0] = dir[0];
+ intersect_ctx.ws_dir[1] = dir[1];
+ intersect_ctx.ws_dir[2] = dir[2];
+ intersect_ctx.scnview = scnview;
+ intersect_ctx.data = ray_data;
+
+ /* Here we go! */
+ rtcIntersect1(scnview->rtc_scn, &intersect_ctx.rtc, &ray_hit);
+
+ hit_setup(scnview, &ray_hit, hit);
+ return RES_OK;
+}
+
+res_T
+s3d_scene_view_trace_rays
+ (struct s3d_scene_view* scnview,
+ const size_t nrays,
+ const int mask,
+ const float* origins,
+ const float* directions,
+ const float* ranges,
+ void* rays_data,
+ const size_t sizeof_ray_data,
+ struct s3d_hit* hits)
+{
+ size_t iray;
+ size_t iorg, idir, irange, idata;
+ size_t org_step, dir_step, range_step, data_step;
+ res_T res = RES_OK;
+
+ if(!scnview) return RES_BAD_ARG;
+ if(!nrays) return RES_OK;
+
+ org_step = mask & S3D_RAYS_SINGLE_ORIGIN ? 0 : 3;
+ dir_step = mask & S3D_RAYS_SINGLE_DIRECTION ? 0 : 3;
+ range_step = mask & S3D_RAYS_SINGLE_RANGE ? 0 : 2;
+ data_step = (mask & S3D_RAYS_SINGLE_DATA) || !rays_data ? 0 : sizeof_ray_data;
+ iorg = idir = irange = idata = 0;
+
+ FOR_EACH(iray, 0, nrays) {
+ res = s3d_scene_view_trace_ray(scnview, origins+iorg, directions+idir,
+ ranges+irange, (char*)rays_data+idata, hits+iray);
+ if(UNLIKELY(res != RES_OK)) break;
+ iorg += org_step;
+ idir += dir_step;
+ irange += range_step;
+ idata += data_step;
+ }
+ return res;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+/* Wrapper between an Embree and a Star-3D filter function */
+void
+rtc_hit_filter_wrapper(const struct RTCFilterFunctionNArguments* args)
+{
+ struct s3d_hit hit;
+ struct RTCRayHit ray_hit;
+ struct intersect_context* ctx;
+ struct geometry* geom;
+ struct hit_filter* filter;
+ ASSERT(args && args->N == 1 && args->context && args->valid[0] != 0);
+
+ rtc_rayN_get_ray(args->ray, args->N, 0, &ray_hit.ray);
+ rtc_hitN_get_hit(args->hit, args->N, 0, &ray_hit.hit);
+
+ ctx = CONTAINER_OF(args->context, struct intersect_context, rtc);
+
+ geom = args->geometryUserPtr;
+ switch(geom->type) {
+ case GEOM_MESH:
+ filter = &geom->data.mesh->filter;
+ break;
+ case GEOM_SPHERE:
+ filter = &geom->data.sphere->filter;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ ASSERT(filter->func);
+
+ hit_setup(ctx->scnview, &ray_hit, &hit);
+ if(filter->func(&hit, ctx->ws_org, ctx->ws_dir, ctx->data, filter->data)) {
+ args->valid[0] = 0;
+ }
+}