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 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:
Mcmake/CMakeLists.txt | 1+
Msrc/s3d_scene_view.c | 252+------------------------------------------------------------------------------
Asrc/s3d_scene_view_trace_ray.c | 302++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; + } +}