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 695c9179ef4c54fe26b7690c373dc21f981e3698
parent 8e782af7a7bef563c739a67806fec29bb643d92a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue,  1 Oct 2019 09:37:44 +0200

Add the s3d_scene_view_create2 function

This function provides a new parameter that allow to configure the
quality and the properties of the acceleration structure used by the
ray-tracing procedure.

Diffstat:
Msrc/s3d.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Msrc/s3d_geometry.c | 1+
Msrc/s3d_geometry.h | 1+
Msrc/s3d_scene_view.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/s3d_scene_view_c.h | 2++
5 files changed, 161 insertions(+), 16 deletions(-)

diff --git a/src/s3d.h b/src/s3d.h @@ -169,6 +169,42 @@ enum s3d_scene_view_flag { * intersects a shape or not */ #define S3D_HIT_NONE(Hit) ((Hit)->distance >= FLT_MAX) +/* Quality of the partitioning data structure used tu accelerate the + * ray-tracing procedure. The lowest the structure quality is, the fastest it + * is built. On the counterpart, a weak structure quality means that the + * partitioning of the geometry is sub-optimal, leading to lower ray-tracing + * performances. */ +enum s3d_rt_accel_struct_quality { + S3D_RT_ACCEL_STRUCT_QUALITY_LOW, + S3D_RT_ACCEL_STRUCT_QUALITY_MEDIUM, + S3D_RT_ACCEL_STRUCT_QUALITY_HIGH +}; + +/* Define the properties of the partitioning data structure used to accelerate + * the ray-tracing procedure. */ +enum s3d_rt_accel_struct_flag { + /* Avoid optimisations that reduce arithmetic accuracy */ + S3D_RT_ACCEL_STRUCT_FLAG_ROBUST = BIT(0), + /* Improve the building performances of the acceleration structure for + * dynamic scenes */ + S3D_RT_ACCEL_STRUCT_FLAG_DYNAMIC = BIT(1), + /* Reduce the memory consumption of the acceleration structure */ + S3D_RT_ACCEL_STRUCT_FLAG_COMPACT = BIT(2) +}; + +/* Configuration of the acceleration data structure used to accelerate the + * ray-tracing procedure */ +struct s3d_rt_accel_struct_conf { + enum s3d_rt_accel_struct_quality quality; + int mask; /* combination of s3d_rt_accel_struct_flag */ +}; +#define S3D_RT_ACCEL_STRUCT_CONF_DEFAULT__ { \ + S3D_RT_ACCEL_STRUCT_QUALITY_MEDIUM, \ + S3D_RT_ACCEL_STRUCT_FLAG_ROBUST \ +} +static const struct s3d_rt_accel_struct_conf S3D_RT_ACCEL_STRUCT_CONF_DEFAULT = + S3D_RT_ACCEL_STRUCT_CONF_DEFAULT__; + /* Filter function data type. One can define such function to discard * intersections along a ray with respect to user defined criteria, e.g.: * masked/transparent primitive, etc. Return 0 or the intersection is not @@ -283,6 +319,15 @@ s3d_scene_view_create struct s3d_scene_view** scnview); S3D_API res_T +s3d_scene_view_create2 + (struct s3d_scene* scn, + const int mask, /* Combination of s3d_scene_view_flag */ + /* Ignored if (mask & S3D_TRACE) == 0 + * NULL <=> use S3D_RT_ACCEL_STRUCT_CONF_DEFAULT */ + const struct s3d_rt_accel_struct_conf* cfg, + struct s3d_scene_view** scnview); + +S3D_API res_T s3d_scene_view_ref_get (struct s3d_scene_view* scnview); diff --git a/src/s3d_geometry.c b/src/s3d_geometry.c @@ -167,6 +167,7 @@ geometry_create geom->data.mesh = NULL; geom->rtc = NULL; geom->rtc_id = RTC_INVALID_GEOMETRY_ID; + geom->rtc_build_quality = RTC_BUILD_QUALITY_MEDIUM; exit: *out_geom = geom; diff --git a/src/s3d_geometry.h b/src/s3d_geometry.h @@ -58,6 +58,7 @@ enum embree_attrib { struct geometry { unsigned name; /* Client side identifier */ RTCGeometry rtc; /* Embree geometry */ + enum RTCBuildQuality rtc_build_quality; /* BVH build quality */ unsigned rtc_id; /* Embree geometry identifier */ unsigned scene_prim_id_offset; /* Offset from local to scene prim_id */ diff --git a/src/s3d_scene_view.c b/src/s3d_scene_view.c @@ -232,21 +232,72 @@ hit_setup if(flip_surface) f3_minus(hit->normal, hit->normal); } +static INLINE enum RTCBuildQuality +rt_accel_struct_quality_to_rtc_build_quality + (enum s3d_rt_accel_struct_quality quality) +{ + enum RTCBuildQuality rtc_quality = RTC_BUILD_QUALITY_MEDIUM; + switch(quality) { + case S3D_RT_ACCEL_STRUCT_QUALITY_LOW: + rtc_quality = RTC_BUILD_QUALITY_LOW; + break; + case S3D_RT_ACCEL_STRUCT_QUALITY_MEDIUM: + rtc_quality = RTC_BUILD_QUALITY_MEDIUM; + break; + case S3D_RT_ACCEL_STRUCT_QUALITY_HIGH: + rtc_quality = RTC_BUILD_QUALITY_HIGH; + break; + default: FATAL("Unreachable code\n"); break; + } + return rtc_quality; +} + +static INLINE int +rt_accel_struct_mask_to_rtc_scene_flags(const int mask) +{ + int rtc_scene_flags = 0; + if(mask & S3D_RT_ACCEL_STRUCT_FLAG_ROBUST) + rtc_scene_flags |= RTC_SCENE_FLAG_ROBUST; + if(mask & S3D_RT_ACCEL_STRUCT_FLAG_DYNAMIC) + rtc_scene_flags |= RTC_SCENE_FLAG_DYNAMIC; + if(mask & S3D_RT_ACCEL_STRUCT_FLAG_COMPACT) + rtc_scene_flags |= RTC_SCENE_FLAG_COMPACT; + return rtc_scene_flags; +} + static res_T embree_geometry_register (struct s3d_scene_view* scnview, - struct geometry* geom) + struct geometry* geom, + const struct s3d_rt_accel_struct_conf* rt_accel_struct_conf) { - ASSERT(scnview && geom); + enum RTCBuildQuality rtc_build_quality = RTC_BUILD_QUALITY_MEDIUM; + ASSERT(scnview && geom && rt_accel_struct_conf); + + rtc_build_quality = rt_accel_struct_quality_to_rtc_build_quality + (rt_accel_struct_conf->quality); /* Create the Embree geometry if it is not valid */ if(geom->rtc != NULL) { - if(geom->type == GEOM_INSTANCE) { - /* If the geometry is an instance one have to update it if the - * instantiated geometry was updated. Currently, we have no simple way to - * know if the geometry was upd or not so we simply force the update. */ - rtcCommitGeometry(geom->rtc); - scnview->rtc_scn_update = 1; + switch(geom->type) { + case GEOM_MESH: + if(geom->rtc_build_quality != rtc_build_quality) { + /* Update the build quality of the geometry */ + rtcSetGeometryBuildQuality(geom->rtc, rtc_build_quality); + rtcCommitGeometry(geom->rtc); + geom->rtc_build_quality = rtc_build_quality; + scnview->rtc_scn_update = 1; + } + break; + case GEOM_INSTANCE: + /* If the geometry is an instance one have to update it if the + * instantiated geometry was updated. Currently, we have no simple way to + * know if the geometry was upd or not so we simply force the update. */ + rtcCommitGeometry(geom->rtc); + scnview->rtc_scn_update = 1; + break; + case GEOM_SPHERE: /* Do nothing */ break; + default: FATAL("Unreachable code\n"); break; } } else { switch(geom->type) { @@ -273,6 +324,12 @@ embree_geometry_register if(geom->rtc == NULL) return RES_UNKNOWN_ERR; + if(geom->type == GEOM_MESH) { + /* Set the build quality of the geometry */ + rtcSetGeometryBuildQuality(geom->rtc, rtc_build_quality); + geom->rtc_build_quality = rtc_build_quality; + } + /* Set the Star-3D representation of the geometry to the Embree geometry */ rtcSetGeometryUserData(geom->rtc, geom); @@ -385,13 +442,22 @@ embree_geometry_setup_transform } static INLINE res_T -scene_view_setup_embree(struct s3d_scene_view* scnview) +scene_view_setup_embree + (struct s3d_scene_view* scnview, + const struct s3d_rt_accel_struct_conf* rt_accel_struct_conf) { struct htable_geom_iterator it, end; int rtc_outdated = 0; + int rtc_scn_flags = 0; + enum RTCBuildQuality rtc_scn_build_quality = 0; res_T res = RES_OK; ASSERT(scnview); + rtc_scn_flags = rt_accel_struct_mask_to_rtc_scene_flags + (rt_accel_struct_conf->mask); + rtc_scn_build_quality = rt_accel_struct_quality_to_rtc_build_quality + (rt_accel_struct_conf->quality); + /* The rtc_scn could be already allocated since the scene views are cached */ if(!scnview->rtc_scn) { scnview->rtc_scn = rtcNewScene(scnview->scn->dev->rtc); @@ -399,8 +465,20 @@ scene_view_setup_embree(struct s3d_scene_view* scnview) res = rtc_error_to_res_T(rtcGetDeviceError(scnview->scn->dev->rtc)); goto error; } - rtcSetSceneFlags - (scnview->rtc_scn, RTC_SCENE_FLAG_ROBUST | RTC_SCENE_FLAG_DYNAMIC); + rtcSetSceneFlags(scnview->rtc_scn, rtc_scn_flags); + scnview->rtc_scn_flags = rtc_scn_flags; + rtc_outdated = 1; + } + + /* Check if the scene flags were updated */ + if(scnview->rtc_scn_flags != rtc_scn_flags) { + rtcSetSceneFlags(scnview->rtc_scn, rtc_scn_flags); + rtc_outdated = 1; + } + + /* Check if the build quality was updated */ + if(scnview->rtc_scn_build_quality != rtc_scn_build_quality) { + rtcSetSceneBuildQuality(scnview->rtc_scn, rtc_scn_build_quality); rtc_outdated = 1; } @@ -419,7 +497,7 @@ scene_view_setup_embree(struct s3d_scene_view* scnview) rtc_outdated = 1; /* Register the embree geometry */ - res = embree_geometry_register(scnview, geom); + res = embree_geometry_register(scnview, geom, rt_accel_struct_conf); if(res != RES_OK) goto error; /* Flush the embree geometry states */ @@ -936,12 +1014,13 @@ scene_view_compute_volume static res_T scene_view_sync (struct s3d_scene_view* scnview, - const int mask) + const int mask, + const struct s3d_rt_accel_struct_conf* rt_accel_struct_conf) { struct htable_shape_iterator it, end; res_T res = RES_OK; - ASSERT(scnview); + ASSERT(scnview && rt_accel_struct_conf); ASSERT((mask & (S3D_TRACE|S3D_SAMPLE|S3D_GET_PRIMITIVE)) != 0); /* Commit the scene shape to the scnview */ @@ -971,7 +1050,7 @@ scene_view_sync /* Setup the scene for the S3D_TRACE scnview */ if((mask & S3D_TRACE) != 0) { - res = scene_view_setup_embree(scnview); + res = scene_view_setup_embree(scnview, rt_accel_struct_conf); if(res != RES_OK) goto error; } /* Setup the scene for the S3D_SAMPLE scnview */ @@ -1019,6 +1098,7 @@ scene_view_create(struct s3d_scene* scn, struct s3d_scene_view** out_scnview) f3_splat(scnview->lower, FLT_MAX); f3_splat(scnview->upper,-FLT_MAX); ref_init(&scnview->ref); + scnview->rtc_scn_build_quality = RTC_BUILD_QUALITY_MEDIUM; CLBK_INIT(&scnview->on_shape_detach_cb); CLBK_SETUP(&scnview->on_shape_detach_cb, on_shape_detach, scnview); @@ -1104,7 +1184,19 @@ s3d_scene_view_create const int mask, struct s3d_scene_view** out_scnview) { + return s3d_scene_view_create2 + (scn, mask, &S3D_RT_ACCEL_STRUCT_CONF_DEFAULT, out_scnview); +} + +res_T +s3d_scene_view_create2 + (struct s3d_scene* scn, + const int mask, + const struct s3d_rt_accel_struct_conf* cfg, + struct s3d_scene_view** out_scnview) +{ struct s3d_scene_view* scnview = NULL; + const struct s3d_rt_accel_struct_conf* rt_accel_struct_conf = cfg; res_T res = RES_OK; if(!scn || !out_scnview) { @@ -1112,6 +1204,10 @@ s3d_scene_view_create goto error; } + if(!rt_accel_struct_conf && (mask & S3D_TRACE)) { + rt_accel_struct_conf = &S3D_RT_ACCEL_STRUCT_CONF_DEFAULT; + } + if(!(mask & S3D_TRACE) && !(mask & S3D_SAMPLE) && !(mask & S3D_GET_PRIMITIVE)) { @@ -1123,7 +1219,7 @@ s3d_scene_view_create res = scene_view_create(scn, &scnview); if(res != RES_OK) goto error; - res = scene_view_sync(scnview, mask); + res = scene_view_sync(scnview, mask, rt_accel_struct_conf); if(res != RES_OK) goto error; exit: diff --git a/src/s3d_scene_view_c.h b/src/s3d_scene_view_c.h @@ -91,6 +91,8 @@ struct s3d_scene_view { int mask; /* Combination of enum s3d_scene_view_flag */ int rtc_scn_update; /* Define if Embree geometries were deleted/added */ int rtc_commit; /* Define whether or not the Embree scene was committed */ + int rtc_scn_flags; /* Flags used to configure the Embree scene */ + enum RTCBuildQuality rtc_scn_build_quality; /* Build quality of the BVH */ RTCScene rtc_scn; /* Embree scene */ ref_T ref;