embree_rs/
scene.rs

1use std::collections::HashMap;
2use std::marker::PhantomData;
3use std::arch::x86_64;
4use std::mem;
5
6use device::Device;
7use geometry::Geometry;
8use ray::{IntersectContext, Ray, RayHit};
9use ray_packet::{Ray4, RayHit4};
10use ray_stream::{RayN, RayHitN};
11use sys::*;
12
13/// A scene containing various geometry for rendering. Geometry
14/// can be added and removed by attaching and detaching it, after
15/// which the scene BVH can be built via `commit` which will
16/// return a `CommittedScene` which can be used for ray queries.
17pub struct Scene<'a> {
18    pub(crate) handle: RTCScene,
19    /// We don't need to actually keep a reference to the device,
20    /// we just need to track its lifetime for correctness
21    device: PhantomData<&'a Device>,
22    geometry: HashMap<u32, Geometry<'a>>,
23}
24
25impl<'a> Scene<'a> {
26    pub fn new(device: &'a Device) -> Scene {
27        // Set the flush zero and denormals modes from Embrees's perf. recommendations
28        // https://embree.github.io/api.html#performance-recommendations
29        // Though, in Rust I think we just call the below function to do both
30        unsafe {
31            x86_64::_MM_SET_FLUSH_ZERO_MODE(x86_64::_MM_FLUSH_ZERO_ON);
32        }
33        Scene {
34            handle: unsafe { rtcNewScene(device.handle) },
35            device: PhantomData,
36            geometry: HashMap::new(),
37        }
38    }
39    /// Attach a new geometry to the scene. Returns the scene local ID which
40    /// can than be used to find the hit geometry from the ray ID member.
41    /// A geometry can only be attached to one Scene at a time, per the Embree
42    /// documentation. The geometry can be detached from the scene to move
43    /// it to another one.
44    pub fn attach_geometry(&mut self, mesh: Geometry<'a>) -> u32 {
45        let id = unsafe { rtcAttachGeometry(self.handle, mesh.handle()) };
46        self.geometry.insert(id, mesh);
47        id
48    }
49    /// Detach the geometry from the scene
50    pub fn deattach_geometry(&mut self, id: u32) -> Option<Geometry<'a>> {
51        self.geometry.remove(&id)
52    }
53    /// Look up a geometry in the scene by the ID returned from `attach_geometry`
54    pub fn get_geometry(&self, id: u32) -> Option<&Geometry<'a>> {
55        match self.geometry.get(&id) {
56            Some(g) => Some(g),
57            None => None,
58        }
59    }
60    /// Look up a geometry in the scene by the ID returned from `attach_geometry`
61    pub fn get_geometry_mut(&mut self, id: u32) -> Option<&mut Geometry<'a>> {
62        match self.geometry.get_mut(&id) {
63            Some(g) => Some(g),
64            None => None,
65        }
66    }
67    /// Get an iterator over the geometry map
68    pub fn iter(&self) -> std::collections::hash_map::Iter<u32, Geometry<'a>> {
69        self.geometry.iter()
70    }
71    /// Get an iterator over the geometry map
72    pub fn iter_mut(&mut self) -> std::collections::hash_map::IterMut<u32, Geometry<'a>> {
73        self.geometry.iter_mut()
74    }
75    /// Commit the scene to build the BVH on top of the geometry to allow
76    /// for ray tracing the scene. The returned `CommittedScene` can be
77    /// used for intersection and occlusion tests. The `Scene` can't
78    /// be modified while the `CommittedScene` is active.
79    pub fn commit(&'a self) -> CommittedScene<'a> {
80        unsafe {
81            rtcCommitScene(self.handle);
82        }
83        CommittedScene { scene: &self }
84    }
85    /// Get the underlying handle to the scene, e.g. for passing it to
86    /// native code or ISPC kernels.
87    pub unsafe fn handle(&self) -> RTCScene {
88        self.handle
89    }
90}
91
92impl<'a> Drop for Scene<'a> {
93    fn drop(&mut self) {
94        unsafe {
95            rtcReleaseScene(self.handle);
96        }
97    }
98}
99
100unsafe impl<'a> Sync for Scene<'a> {}
101
102/// A committed scene with a BVH built over the geometry
103/// which can be used for ray queries.
104pub struct CommittedScene<'a> {
105    pub (crate) scene: &'a Scene<'a>,
106}
107
108impl<'a> CommittedScene<'a> {
109    pub fn intersect(&self, ctx: &mut IntersectContext, ray: &mut RayHit) {
110        unsafe {
111            rtcIntersect1(
112                self.scene.handle,
113                ctx as *mut RTCIntersectContext,
114                ray as *mut RTCRayHit
115            );
116        }
117    }
118    pub fn occluded(&self, ctx: &mut IntersectContext, ray: &mut Ray) {
119        unsafe {
120            rtcOccluded1(
121                self.scene.handle,
122                ctx as *mut RTCIntersectContext,
123                ray as *mut RTCRay
124            );
125        }
126    }
127    pub fn intersect4(&self, ctx: &mut IntersectContext, ray: &mut RayHit4, valid: &[i32; 4]) {
128        unsafe {
129            rtcIntersect4(
130                valid.as_ptr(),
131                self.scene.handle,
132                ctx as *mut RTCIntersectContext,
133                ray as *mut RTCRayHit4
134            );
135        }
136    }
137    pub fn occluded4(&self, ctx: &mut IntersectContext, ray: &mut Ray4, valid: &[i32; 4]) {
138        unsafe {
139            rtcOccluded4(
140                valid.as_ptr(),
141                self.scene.handle,
142                ctx as *mut RTCIntersectContext,
143                ray as *mut RTCRay4
144            );
145        }
146    }
147    pub fn intersect_stream_aos(&self, ctx: &mut IntersectContext, rays: &mut Vec<RayHit>) {
148        let m = rays.len();
149        unsafe {
150            rtcIntersect1M(
151                self.scene.handle,
152                ctx as *mut RTCIntersectContext,
153                rays.as_mut_ptr(),
154                m as u32,
155                mem::size_of::<RayHit>()
156            );
157        }
158    }
159    pub fn occluded_stream_aos(&self, ctx: &mut IntersectContext, rays: &mut Vec<Ray>) {
160        let m = rays.len();
161        unsafe {
162            rtcOccluded1M(
163                self.scene.handle,
164                ctx as *mut RTCIntersectContext,
165                rays.as_mut_ptr(),
166                m as u32,
167                mem::size_of::<Ray>()
168            );
169        }
170    }
171    pub fn intersect_stream_soa(&self, ctx: &mut IntersectContext, rays: &mut RayHitN) {
172        let n = rays.len();
173        unsafe {
174            let mut rayhit = rays.as_rayhitnp();
175            rtcIntersectNp(
176                self.scene.handle,
177                ctx as *mut RTCIntersectContext,
178                &mut rayhit as *mut RTCRayHitNp,
179                n as u32
180            );
181        }
182    }
183    pub fn occluded_stream_soa(&self, ctx: &mut IntersectContext, rays: &mut RayN) {
184        let n = rays.len();
185        unsafe {
186            let mut r = rays.as_raynp();
187            rtcOccludedNp(
188                self.scene.handle,
189                ctx as *mut RTCIntersectContext,
190                &mut r as *mut RTCRayNp,
191                n as u32
192            );
193        }
194    }
195    pub fn bounds(&self) -> RTCBounds {
196        let mut bounds = RTCBounds {
197            lower_x: 0.0,
198            upper_x: 0.0,
199            lower_y: 0.0,
200            upper_y: 0.0,
201            lower_z: 0.0,
202            upper_z: 0.0,
203            align0: 0.0,
204            align1: 0.0,
205        };
206        unsafe {
207            rtcGetSceneBounds(self.handle(), &mut bounds as *mut RTCBounds);
208        }
209        bounds
210    }
211    /// Get the underlying handle to the scene, e.g. for passing it to
212    /// native code or ISPC kernels.
213    pub unsafe fn handle(&self) -> RTCScene {
214        self.scene.handle
215    }
216}
217
218unsafe impl<'a> Sync for CommittedScene<'a> {}
219