1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #include "instance_intersector.h"
5 #include "../common/scene.h"
6 #include "../common/instance_stack.h"
7 
8 namespace embree
9 {
10   namespace isa
11   {
12 
13     /* Push an instance to the stack. */
pushInstance(RTCPointQueryContext * context,unsigned int instanceId,AffineSpace3fa const & w2i,AffineSpace3fa const & i2w)14     RTC_FORCEINLINE bool pushInstance(RTCPointQueryContext* context,
15                       unsigned int instanceId,
16                       AffineSpace3fa const& w2i,
17                       AffineSpace3fa const& i2w)
18     {
19       assert(context);
20       const size_t stackSize = context->instStackSize;
21       assert(stackSize < RTC_MAX_INSTANCE_LEVEL_COUNT);
22       context->instID[stackSize] = instanceId;
23 
24       AffineSpace3fa_store_unaligned(w2i,(AffineSpace3fa*)context->world2inst[stackSize]);
25       AffineSpace3fa_store_unaligned(i2w,(AffineSpace3fa*)context->inst2world[stackSize]);
26 
27       if (unlikely(stackSize > 0))
28       {
29         const AffineSpace3fa world2inst = AffineSpace3fa_load_unaligned((AffineSpace3fa*)context->world2inst[stackSize  ])
30                                         * AffineSpace3fa_load_unaligned((AffineSpace3fa*)context->world2inst[stackSize-1]);
31         const AffineSpace3fa inst2world = AffineSpace3fa_load_unaligned((AffineSpace3fa*)context->inst2world[stackSize-1])
32                                         * AffineSpace3fa_load_unaligned((AffineSpace3fa*)context->inst2world[stackSize  ]);
33         AffineSpace3fa_store_unaligned(world2inst,(AffineSpace3fa*)context->world2inst[stackSize]);
34         AffineSpace3fa_store_unaligned(inst2world,(AffineSpace3fa*)context->inst2world[stackSize]);
35       }
36       context->instStackSize++;
37       return true;
38     }
39 
40     /* Pop the last instance pushed to the stack. Do not call on an empty stack. */
popInstance(RTCPointQueryContext * context)41     RTC_FORCEINLINE void popInstance(RTCPointQueryContext* context)
42     {
43       assert(context && context->instStackSize > 0);
44       context->instID[--context->instStackSize] = RTC_INVALID_GEOMETRY_ID;
45     }
46 
intersect(const Precalculations & pre,RayHit & ray,IntersectContext * context,const InstancePrimitive & prim)47     void InstanceIntersector1::intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const InstancePrimitive& prim)
48     {
49       const Instance* instance = prim.instance;
50 
51       /* perform ray mask test */
52 #if defined(EMBREE_RAY_MASK)
53       if ((ray.mask & instance->mask) == 0)
54         return;
55 #endif
56 
57       RTCIntersectContext* user_context = context->user;
58       if (likely(instance_id_stack::push(user_context, prim.instID_)))
59       {
60         const AffineSpace3fa world2local = instance->getWorld2Local();
61         const Vec3ff ray_org = ray.org;
62         const Vec3ff ray_dir = ray.dir;
63         ray.org = Vec3ff(xfmPoint(world2local, ray_org), ray.tnear());
64         ray.dir = Vec3ff(xfmVector(world2local, ray_dir), ray.time());
65         IntersectContext newcontext((Scene*)instance->object, user_context);
66         instance->object->intersectors.intersect((RTCRayHit&)ray, &newcontext);
67         ray.org = ray_org;
68         ray.dir = ray_dir;
69         instance_id_stack::pop(user_context);
70       }
71     }
72 
occluded(const Precalculations & pre,Ray & ray,IntersectContext * context,const InstancePrimitive & prim)73     bool InstanceIntersector1::occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const InstancePrimitive& prim)
74     {
75       const Instance* instance = prim.instance;
76 
77       /* perform ray mask test */
78 #if defined(EMBREE_RAY_MASK)
79       if ((ray.mask & instance->mask) == 0)
80         return false;
81 #endif
82 
83       RTCIntersectContext* user_context = context->user;
84       bool occluded = false;
85       if (likely(instance_id_stack::push(user_context, prim.instID_)))
86       {
87         const AffineSpace3fa world2local = instance->getWorld2Local();
88         const Vec3ff ray_org = ray.org;
89         const Vec3ff ray_dir = ray.dir;
90         ray.org = Vec3ff(xfmPoint(world2local, ray_org), ray.tnear());
91         ray.dir = Vec3ff(xfmVector(world2local, ray_dir), ray.time());
92         IntersectContext newcontext((Scene*)instance->object, user_context);
93         instance->object->intersectors.occluded((RTCRay&)ray, &newcontext);
94         ray.org = ray_org;
95         ray.dir = ray_dir;
96         occluded = ray.tfar < 0.0f;
97         instance_id_stack::pop(user_context);
98       }
99       return occluded;
100     }
101 
pointQuery(PointQuery * query,PointQueryContext * context,const InstancePrimitive & prim)102     bool InstanceIntersector1::pointQuery(PointQuery* query, PointQueryContext* context, const InstancePrimitive& prim)
103     {
104       const Instance* instance = prim.instance;
105 
106       const AffineSpace3fa local2world = instance->getLocal2World();
107       const AffineSpace3fa world2local = instance->getWorld2Local();
108       float similarityScale = 0.f;
109       const bool similtude = context->query_type == POINT_QUERY_TYPE_SPHERE
110                            && similarityTransform(world2local, &similarityScale);
111       assert((similtude && similarityScale > 0) || !similtude);
112 
113       if (likely(pushInstance(context->userContext, prim.instID_, world2local, local2world)))
114       {
115         PointQuery query_inst;
116         query_inst.time = query->time;
117         query_inst.p = xfmPoint(world2local, query->p);
118         query_inst.radius = query->radius * similarityScale;
119 
120         PointQueryContext context_inst(
121           (Scene*)instance->object,
122           context->query_ws,
123           similtude ? POINT_QUERY_TYPE_SPHERE : POINT_QUERY_TYPE_AABB,
124           context->func,
125           context->userContext,
126           similarityScale,
127           context->userPtr);
128 
129         bool changed = instance->object->intersectors.pointQuery(&query_inst, &context_inst);
130         popInstance(context->userContext);
131         return changed;
132       }
133       return false;
134     }
135 
intersect(const Precalculations & pre,RayHit & ray,IntersectContext * context,const InstancePrimitive & prim)136     void InstanceIntersector1MB::intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const InstancePrimitive& prim)
137     {
138       const Instance* instance = prim.instance;
139 
140       /* perform ray mask test */
141 #if defined(EMBREE_RAY_MASK)
142       if ((ray.mask & instance->mask) == 0)
143         return;
144 #endif
145 
146       RTCIntersectContext* user_context = context->user;
147       if (likely(instance_id_stack::push(user_context, prim.instID_)))
148       {
149         const AffineSpace3fa world2local = instance->getWorld2Local(ray.time());
150         const Vec3ff ray_org = ray.org;
151         const Vec3ff ray_dir = ray.dir;
152         ray.org = Vec3ff(xfmPoint(world2local, ray_org), ray.tnear());
153         ray.dir = Vec3ff(xfmVector(world2local, ray_dir), ray.time());
154         IntersectContext newcontext((Scene*)instance->object, user_context);
155         instance->object->intersectors.intersect((RTCRayHit&)ray, &newcontext);
156         ray.org = ray_org;
157         ray.dir = ray_dir;
158         instance_id_stack::pop(user_context);
159       }
160     }
161 
occluded(const Precalculations & pre,Ray & ray,IntersectContext * context,const InstancePrimitive & prim)162     bool InstanceIntersector1MB::occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const InstancePrimitive& prim)
163     {
164       const Instance* instance = prim.instance;
165 
166       /* perform ray mask test */
167 #if defined(EMBREE_RAY_MASK)
168       if ((ray.mask & instance->mask) == 0)
169         return false;
170 #endif
171 
172       RTCIntersectContext* user_context = context->user;
173       bool occluded = false;
174       if (likely(instance_id_stack::push(user_context, prim.instID_)))
175       {
176         const AffineSpace3fa world2local = instance->getWorld2Local(ray.time());
177         const Vec3ff ray_org = ray.org;
178         const Vec3ff ray_dir = ray.dir;
179         ray.org = Vec3ff(xfmPoint(world2local, ray_org), ray.tnear());
180         ray.dir = Vec3ff(xfmVector(world2local, ray_dir), ray.time());
181         IntersectContext newcontext((Scene*)instance->object, user_context);
182         instance->object->intersectors.occluded((RTCRay&)ray, &newcontext);
183         ray.org = ray_org;
184         ray.dir = ray_dir;
185         occluded = ray.tfar < 0.0f;
186         instance_id_stack::pop(user_context);
187       }
188       return occluded;
189     }
190 
pointQuery(PointQuery * query,PointQueryContext * context,const InstancePrimitive & prim)191     bool InstanceIntersector1MB::pointQuery(PointQuery* query, PointQueryContext* context, const InstancePrimitive& prim)
192     {
193       const Instance* instance = prim.instance;
194 
195       const AffineSpace3fa local2world = instance->getLocal2World(query->time);
196       const AffineSpace3fa world2local = instance->getWorld2Local(query->time);
197       float similarityScale = 0.f;
198       const bool similtude = context->query_type == POINT_QUERY_TYPE_SPHERE
199                            && similarityTransform(world2local, &similarityScale);
200 
201       if (likely(pushInstance(context->userContext, prim.instID_, world2local, local2world)))
202       {
203         PointQuery query_inst;
204         query_inst.time = query->time;
205         query_inst.p = xfmPoint(world2local, query->p);
206         query_inst.radius = query->radius * similarityScale;
207 
208         PointQueryContext context_inst(
209           (Scene*)instance->object,
210           context->query_ws,
211           similtude ? POINT_QUERY_TYPE_SPHERE : POINT_QUERY_TYPE_AABB,
212           context->func,
213           context->userContext,
214           similarityScale,
215           context->userPtr);
216 
217         bool changed = instance->object->intersectors.pointQuery(&query_inst, &context_inst);
218         popInstance(context->userContext);
219         return changed;
220       }
221       return false;
222     }
223 
224     template<int K>
intersect(const vbool<K> & valid_i,const Precalculations & pre,RayHitK<K> & ray,IntersectContext * context,const InstancePrimitive & prim)225     void InstanceIntersectorK<K>::intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const InstancePrimitive& prim)
226     {
227       vbool<K> valid = valid_i;
228       const Instance* instance = prim.instance;
229       //ray.geomID = 10;
230 
231       /* perform ray mask test */
232 #if defined(EMBREE_RAY_MASK)
233       valid &= (ray.mask & instance->mask) != 0;
234       if (none(valid)) return;
235 #endif
236 
237       RTCIntersectContext* user_context = context->user;
238       if (likely(instance_id_stack::push(user_context, prim.instID_)))
239       {
240         AffineSpace3vf<K> world2local = instance->getWorld2Local();
241         const Vec3vf<K> ray_org = ray.org;
242         const Vec3vf<K> ray_dir = ray.dir;
243         ray.org = xfmPoint(world2local, ray_org);
244         ray.dir = xfmVector(world2local, ray_dir);
245         IntersectContext newcontext((Scene*)instance->object, user_context);
246         instance->object->intersectors.intersect(valid, ray, &newcontext);
247         ray.org = ray_org;
248         ray.dir = ray_dir;
249         instance_id_stack::pop(user_context);
250       }
251     }
252 
253     template<int K>
occluded(const vbool<K> & valid_i,const Precalculations & pre,RayK<K> & ray,IntersectContext * context,const InstancePrimitive & prim)254     vbool<K> InstanceIntersectorK<K>::occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const InstancePrimitive& prim)
255     {
256       vbool<K> valid = valid_i;
257       const Instance* instance = prim.instance;
258 
259       /* perform ray mask test */
260 #if defined(EMBREE_RAY_MASK)
261       valid &= (ray.mask & instance->mask) != 0;
262       if (none(valid)) return false;
263 #endif
264 
265       RTCIntersectContext* user_context = context->user;
266       vbool<K> occluded = false;
267       if (likely(instance_id_stack::push(user_context, prim.instID_)))
268       {
269         AffineSpace3vf<K> world2local = instance->getWorld2Local();
270         const Vec3vf<K> ray_org = ray.org;
271         const Vec3vf<K> ray_dir = ray.dir;
272         ray.org = xfmPoint(world2local, ray_org);
273         ray.dir = xfmVector(world2local, ray_dir);
274         IntersectContext newcontext((Scene*)instance->object, user_context);
275         instance->object->intersectors.occluded(valid, ray, &newcontext);
276         ray.org = ray_org;
277         ray.dir = ray_dir;
278         occluded = ray.tfar < 0.0f;
279         instance_id_stack::pop(user_context);
280       }
281       return occluded;
282     }
283 
284     template<int K>
intersect(const vbool<K> & valid_i,const Precalculations & pre,RayHitK<K> & ray,IntersectContext * context,const InstancePrimitive & prim)285     void InstanceIntersectorKMB<K>::intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const InstancePrimitive& prim)
286     {
287       vbool<K> valid = valid_i;
288       const Instance* instance = prim.instance;
289 
290       /* perform ray mask test */
291 #if defined(EMBREE_RAY_MASK)
292       valid &= (ray.mask & instance->mask) != 0;
293       if (none(valid)) return;
294 #endif
295 
296       RTCIntersectContext* user_context = context->user;
297       if (likely(instance_id_stack::push(user_context, prim.instID_)))
298       {
299         AffineSpace3vf<K> world2local = instance->getWorld2Local<K>(valid, ray.time());
300         const Vec3vf<K> ray_org = ray.org;
301         const Vec3vf<K> ray_dir = ray.dir;
302         ray.org = xfmPoint(world2local, ray_org);
303         ray.dir = xfmVector(world2local, ray_dir);
304         IntersectContext newcontext((Scene*)instance->object, user_context);
305         instance->object->intersectors.intersect(valid, ray, &newcontext);
306         ray.org = ray_org;
307         ray.dir = ray_dir;
308         instance_id_stack::pop(user_context);
309       }
310     }
311 
312     template<int K>
occluded(const vbool<K> & valid_i,const Precalculations & pre,RayK<K> & ray,IntersectContext * context,const InstancePrimitive & prim)313     vbool<K> InstanceIntersectorKMB<K>::occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const InstancePrimitive& prim)
314     {
315       vbool<K> valid = valid_i;
316       const Instance* instance = prim.instance;
317 
318       /* perform ray mask test */
319 #if defined(EMBREE_RAY_MASK)
320       valid &= (ray.mask & instance->mask) != 0;
321       if (none(valid)) return false;
322 #endif
323 
324       RTCIntersectContext* user_context = context->user;
325       vbool<K> occluded = false;
326       if (likely(instance_id_stack::push(user_context, prim.instID_)))
327       {
328         AffineSpace3vf<K> world2local = instance->getWorld2Local<K>(valid, ray.time());
329         const Vec3vf<K> ray_org = ray.org;
330         const Vec3vf<K> ray_dir = ray.dir;
331         ray.org = xfmPoint(world2local, ray_org);
332         ray.dir = xfmVector(world2local, ray_dir);
333         IntersectContext newcontext((Scene*)instance->object, user_context);
334         instance->object->intersectors.occluded(valid, ray, &newcontext);
335         ray.org = ray_org;
336         ray.dir = ray_dir;
337         occluded = ray.tfar < 0.0f;
338         instance_id_stack::pop(user_context);
339       }
340       return occluded;
341     }
342 
343 #if defined(__SSE__)
344     template struct InstanceIntersectorK<4>;
345     template struct InstanceIntersectorKMB<4>;
346 #endif
347 
348 #if defined(__AVX__)
349     template struct InstanceIntersectorK<8>;
350     template struct InstanceIntersectorKMB<8>;
351 #endif
352 
353 #if defined(__AVX512F__)
354     template struct InstanceIntersectorK<16>;
355     template struct InstanceIntersectorKMB<16>;
356 #endif
357   }
358 }
359