From 90b3421a6a6e08dc86a542763dececd1f67a50f4 Mon Sep 17 00:00:00 2001 From: waqar-ukaea Date: Tue, 2 Sep 2025 09:43:49 +0100 Subject: [PATCH 1/3] Switched to embree instancing. Point querying still fails though --- include/xdg/embree/ray_tracer.h | 13 +++++ src/embree/ray_tracer.cpp | 91 ++++++++++++++++----------------- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/include/xdg/embree/ray_tracer.h b/include/xdg/embree/ray_tracer.h index 9c031d8f..cd321d63 100644 --- a/include/xdg/embree/ray_tracer.h +++ b/include/xdg/embree/ray_tracer.h @@ -16,6 +16,12 @@ namespace xdg { +struct EmbreeSurfaceCache { + RTCScene scene {nullptr}; + std::shared_ptr user_data {nullptr}; + std::vector prim_refs; +}; + class EmbreeRayTracer : public RayTracer { // constructors public: @@ -70,6 +76,8 @@ class EmbreeRayTracer : public RayTracer { // Mesh-to-Scene maps std::map surface_to_geometry_map_; //> surface_user_data_map_; std::unordered_map> volume_user_data_map_; @@ -77,6 +85,9 @@ class EmbreeRayTracer : public RayTracer { std::unordered_map surface_volume_tree_to_scene_map_; // Map from SurfaceVolumeTreeID to specific embree scene/tree std::unordered_map element_volume_tree_to_scene_map_; // Map from ElementVolumeTreeID to specific embree scene/tree + // instancing data structures + std::unordered_map surface_cache_map_; //> primitive_ref_storage_; @@ -91,6 +102,8 @@ class EmbreeRayTracer : public RayTracer { }; + + } // namespace xdg diff --git a/src/embree/ray_tracer.cpp b/src/embree/ray_tracer.cpp index a7484ea7..9c68fe2d 100644 --- a/src/embree/ray_tracer.cpp +++ b/src/embree/ray_tracer.cpp @@ -52,41 +52,25 @@ EmbreeRayTracer::create_surface_tree(const std::shared_ptr& mesh_ma { SurfaceTreeID tree = next_surface_tree_id(); surface_trees_.push_back(tree); - auto volume_scene = this->create_embree_scene(); - auto volume_surfaces = mesh_manager->get_volume_surfaces(volume_id); - // allocate total storage for all the primtives in a volume - size_t vol_face_count = 0; - for (auto& surface_id : volume_surfaces) { - if (!surface_to_geometry_map_.count(surface_id)) { - vol_face_count += mesh_manager->get_surface_faces(surface_id).size(); - } - } + RTCScene volume_scene = this->create_embree_scene(); + auto volume_surfaces = mesh_manager->get_volume_surfaces(volume_id); - this->primitive_ref_storage_[volume_scene].resize(vol_face_count); - auto& triangle_storage = this->primitive_ref_storage_[volume_scene]; - PrimitiveRef* tri_ref_ptr = triangle_storage.data(); - auto bump = bounding_box_bump(mesh_manager, volume_id); - int storage_offset = 0; + const double bump = bounding_box_bump(mesh_manager, volume_id); for (auto& surface : volume_surfaces) { - RTCGeometry surface_geometry; - std::shared_ptr surface_data; - - // Check if this surface already has cached geometry information - if (!surface_to_geometry_map_.count(surface)) - { // First visit: Create new RTCGeometry and user data - std::tie(surface_geometry, surface_data) = register_surface(mesh_manager, surface, volume_scene, storage_offset); - surface_data->box_bump = bump; // set the box dilation value - } - else { // Second Visit: Recover existing RTCGeometry and user data - surface_geometry = surface_to_geometry_map_[surface]; - surface_data = surface_user_data_map_.at(surface_geometry); - // set the box dilation value to the larger of the two box bump values for - // the volumes on either side of this surface - surface_data->box_bump = std::max(surface_data->box_bump, bump); - rtcAttachGeometry(volume_scene, surface_geometry); - } + + // attempt to recover surface cache from map. If not default construct empty + auto& surfaceCache = surface_cache_map_[surface]; + + // if cache empty build embree objects and populate + if (!surfaceCache.scene) + surfaceCache = register_surface(mesh_manager, surface); + + auto& [surface_scene, surface_data, prims] = surfaceCache; + + // update bbox bump + surface_data->box_bump = std::max(surface_data->box_bump, bump); // Set the correct parent TreeID auto [forward_parent, reverse_parent] = mesh_manager->surface_senses(surface); @@ -97,41 +81,52 @@ EmbreeRayTracer::create_surface_tree(const std::shared_ptr& mesh_ma } else { fatal_error("Volume {} is not a parent of surface {}", volume_id, surface); } + + // Create an instance in the TLAS pointing to the BLAS + RTCGeometry inst = rtcNewGeometry(device_, RTC_GEOMETRY_TYPE_INSTANCE); + rtcSetGeometryInstancedScene(inst, surface_scene); + rtcSetGeometryUserData(inst, surface_data.get()); + rtcCommitGeometry(inst); + rtcAttachGeometry(volume_scene, inst); + rtcReleaseGeometry(inst); } + // commit volume TLAS rtcCommitScene(volume_scene); surface_volume_tree_to_scene_map_[tree] = volume_scene; return tree; } -std::pair> +EmbreeSurfaceCache EmbreeRayTracer::register_surface(const std::shared_ptr& mesh_manager, - MeshID surface, - RTCScene& volume_scene, - int& storage_offset) -{ - auto& triangle_storage = this->primitive_ref_storage_[volume_scene]; - PrimitiveRef* tri_ref_ptr = triangle_storage.data(); + MeshID surface) +{ + RTCScene surface_scene = create_embree_scene(); auto surface_faces = mesh_manager->get_surface_faces(surface); - size_t surf_face_count = surface_faces.size(); + + std::vector prim_refs; + prim_refs.resize(surface_faces.size()); // fill primitive refs - for (size_t i = 0; i < surf_face_count; ++i) { - triangle_storage[storage_offset + i].primitive_id = surface_faces[i]; + for (size_t i = 0; i < surface_faces.size(); ++i) { + prim_refs[i].primitive_id = surface_faces[i]; } + // create new RTCGeometry for the surface auto surface_geometry = rtcNewGeometry(device_, RTC_GEOMETRY_TYPE_USER); - rtcSetGeometryUserPrimitiveCount(surface_geometry, surf_face_count); - rtcAttachGeometry(volume_scene, surface_geometry); + rtcSetGeometryUserPrimitiveCount(surface_geometry, surface_faces.size()); surface_to_geometry_map_[surface] = surface_geometry; // create new SurfaceUserData for the surface auto surface_data = std::make_shared(); surface_data->surface_id = surface; surface_data->mesh_manager = mesh_manager.get(); - surface_data->prim_ref_buffer = tri_ref_ptr + storage_offset; + surface_data->prim_ref_buffer = prim_refs.data(); surface_user_data_map_[surface_geometry] = surface_data; + surface_data->box_bump = 0.0; // will be set later by volume + + rtcSetGeometryUserData(surface_geometry, surface_data.get()); // Set RTC callbacks @@ -140,10 +135,12 @@ EmbreeRayTracer::register_surface(const std::shared_ptr& mesh_manag rtcSetGeometryOccludedFunction(surface_geometry, (RTCOccludedFunctionN)&TriangleOcclusionFunc); rtcCommitGeometry(surface_geometry); - // increment storage offset by number of faces in this surface - storage_offset += surf_face_count; + rtcCommitGeometry(surface_geometry); + rtcAttachGeometry(surface_scene, surface_geometry); + rtcReleaseGeometry(surface_geometry); + rtcCommitScene(surface_scene); - return {surface_geometry, surface_data}; + return {surface_scene, std::move(surface_data), std::move(prim_refs)}; } ElementTreeID From cb654ba5a2d302e14df244224f8ff7920b78c6c1 Mon Sep 17 00:00:00 2001 From: waqar-ukaea Date: Thu, 23 Oct 2025 16:31:41 +0100 Subject: [PATCH 2/3] Working point queries with embree instancing --- include/xdg/embree/ray_tracer.h | 6 ++---- src/embree/ray_tracer.cpp | 10 ++++++++-- src/triangle_intersect.cpp | 13 ++++++++++--- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/xdg/embree/ray_tracer.h b/include/xdg/embree/ray_tracer.h index cd321d63..bba464ba 100644 --- a/include/xdg/embree/ray_tracer.h +++ b/include/xdg/embree/ray_tracer.h @@ -92,10 +92,8 @@ class EmbreeRayTracer : public RayTracer { std::unordered_map> primitive_ref_storage_; private: - std::pair> register_surface(const std::shared_ptr& mesh_manager, - MeshID surface, - RTCScene& volume_scene, - int& storage_offset); + EmbreeSurfaceCache register_surface(const std::shared_ptr& mesh_manager, + MeshID surface); // Global Tree IDs RTCScene global_surface_scene_ {nullptr}; RTCScene global_element_scene_ {nullptr}; diff --git a/src/embree/ray_tracer.cpp b/src/embree/ray_tracer.cpp index 9c68fe2d..a750d194 100644 --- a/src/embree/ray_tracer.cpp +++ b/src/embree/ray_tracer.cpp @@ -191,8 +191,14 @@ void EmbreeRayTracer::create_global_surface_tree() } global_surface_scene_ = create_embree_scene(); - for(auto& [geom, surface_data] : surface_user_data_map_) { - rtcAttachGeometry(global_surface_scene_, geom); + for (auto& [surface, cache] : surface_cache_map_) { + auto& [surface_scene, surface_data, prims] = cache; + + RTCGeometry inst = rtcNewGeometry(device_, RTC_GEOMETRY_TYPE_INSTANCE); + rtcSetGeometryInstancedScene(inst, surface_scene); + rtcCommitGeometry(inst); + rtcAttachGeometry(global_surface_scene_, inst); + rtcReleaseGeometry(inst); } rtcCommitScene(global_surface_scene_); diff --git a/src/triangle_intersect.cpp b/src/triangle_intersect.cpp index c3bc6905..1ff05885 100644 --- a/src/triangle_intersect.cpp +++ b/src/triangle_intersect.cpp @@ -109,9 +109,16 @@ void TriangleIntersectionFunc(RTCIntersectFunctionNArguments* args) { } bool TriangleClosestFunc(RTCPointQueryFunctionArguments* args) { - RTCGeometry g = rtcGetGeometry(*(RTCScene*)args->userPtr, args->geomID); - // get the array of DblTri's stored on the geometry - const SurfaceUserData* user_data = (const SurfaceUserData*) rtcGetGeometryUserData(g); + // TLAS we passed as userPtr to rtcPointQuery(...) + RTCScene tlas = *(RTCScene*)args->userPtr; + + const unsigned stackSize = args->context->instStackSize; + + // top of instance stack is the current instance geomID in the TLAS + unsigned instGeomID = args->context->instID[stackSize - 1]; + RTCGeometry instGeom = rtcGetGeometry(tlas, instGeomID); + const SurfaceUserData* user_data = (const SurfaceUserData*) rtcGetGeometryUserData(instGeom); + const MeshManager* mesh_manager = user_data->mesh_manager; From fc2ff6e12942d95e621b0d3d3b8449d8c3b5d33d Mon Sep 17 00:00:00 2001 From: waqar-ukaea Date: Fri, 24 Oct 2025 17:24:24 +0100 Subject: [PATCH 3/3] Set surface geometry mask + removed redundant member variables --- include/xdg/embree/ray_tracer.h | 15 ++++----------- src/embree/ray_tracer.cpp | 18 +++++++++++------- src/triangle_intersect.cpp | 1 - 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/include/xdg/embree/ray_tracer.h b/include/xdg/embree/ray_tracer.h index bba464ba..c97c4ba4 100644 --- a/include/xdg/embree/ray_tracer.h +++ b/include/xdg/embree/ray_tracer.h @@ -71,29 +71,22 @@ class EmbreeRayTracer : public RayTracer { // Embree members RTCDevice device_; - std::vector geometries_; // surface_to_geometry_map_; // surface_cache_map_; //> surface_user_data_map_; std::unordered_map> volume_user_data_map_; std::unordered_map surface_volume_tree_to_scene_map_; // Map from SurfaceVolumeTreeID to specific embree scene/tree std::unordered_map element_volume_tree_to_scene_map_; // Map from ElementVolumeTreeID to specific embree scene/tree - // instancing data structures - std::unordered_map surface_cache_map_; //> primitive_ref_storage_; private: EmbreeSurfaceCache register_surface(const std::shared_ptr& mesh_manager, - MeshID surface); + MeshID surface); // Global Tree IDs RTCScene global_surface_scene_ {nullptr}; RTCScene global_element_scene_ {nullptr}; diff --git a/src/embree/ray_tracer.cpp b/src/embree/ray_tracer.cpp index a750d194..e23c78ec 100644 --- a/src/embree/ray_tracer.cpp +++ b/src/embree/ray_tracer.cpp @@ -85,7 +85,15 @@ EmbreeRayTracer::create_surface_tree(const std::shared_ptr& mesh_ma // Create an instance in the TLAS pointing to the BLAS RTCGeometry inst = rtcNewGeometry(device_, RTC_GEOMETRY_TYPE_INSTANCE); rtcSetGeometryInstancedScene(inst, surface_scene); - rtcSetGeometryUserData(inst, surface_data.get()); + + // annoyingly user_data needs to be attached to the instance so it can be accessed in point queries + rtcSetGeometryUserData(inst, surface_data.get()); + + // Set Surface mask + // This will essentially group surfaces into sets of 32 possible masks + // Then during ray traversal + uint32_t mask = 1u << (surface % 32); + rtcSetGeometryMask(inst, mask); rtcCommitGeometry(inst); rtcAttachGeometry(volume_scene, inst); rtcReleaseGeometry(inst); @@ -116,25 +124,21 @@ EmbreeRayTracer::register_surface(const std::shared_ptr& mesh_manag // create new RTCGeometry for the surface auto surface_geometry = rtcNewGeometry(device_, RTC_GEOMETRY_TYPE_USER); rtcSetGeometryUserPrimitiveCount(surface_geometry, surface_faces.size()); - surface_to_geometry_map_[surface] = surface_geometry; // create new SurfaceUserData for the surface auto surface_data = std::make_shared(); surface_data->surface_id = surface; surface_data->mesh_manager = mesh_manager.get(); surface_data->prim_ref_buffer = prim_refs.data(); - surface_user_data_map_[surface_geometry] = surface_data; surface_data->box_bump = 0.0; // will be set later by volume - - rtcSetGeometryUserData(surface_geometry, surface_data.get()); + rtcSetGeometryUserData(surface_geometry, surface_data.get()); // attach user data to BLAS // Set RTC callbacks rtcSetGeometryBoundsFunction(surface_geometry, (RTCBoundsFunction)&TriangleBoundsFunc, nullptr); rtcSetGeometryIntersectFunction(surface_geometry, (RTCIntersectFunctionN)&TriangleIntersectionFunc); rtcSetGeometryOccludedFunction(surface_geometry, (RTCOccludedFunctionN)&TriangleOcclusionFunc); - rtcCommitGeometry(surface_geometry); - + rtcCommitGeometry(surface_geometry); rtcAttachGeometry(surface_scene, surface_geometry); rtcReleaseGeometry(surface_geometry); diff --git a/src/triangle_intersect.cpp b/src/triangle_intersect.cpp index 1ff05885..8ef5642f 100644 --- a/src/triangle_intersect.cpp +++ b/src/triangle_intersect.cpp @@ -119,7 +119,6 @@ bool TriangleClosestFunc(RTCPointQueryFunctionArguments* args) { RTCGeometry instGeom = rtcGetGeometry(tlas, instGeomID); const SurfaceUserData* user_data = (const SurfaceUserData*) rtcGetGeometryUserData(instGeom); - const MeshManager* mesh_manager = user_data->mesh_manager; const PrimitiveRef& primitive_ref = user_data->prim_ref_buffer[args->primID];