1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6#include "../common/ray.h"
7#include "../common/context.h"
8#include "filter.h"
9
10namespace embree
11{
12 namespace isa
13 {
14 template<int M>
15 struct UVIdentity {
16 __forceinline void operator() (vfloat<M>& u, vfloat<M>& v, Vec3vf<M>& Ng) const {}
17 };
18
19
20 template<bool filter>
21 struct Intersect1Epilog1
22 {
23 RayHit& ray;
24 IntersectContext* context;
25 const unsigned int geomID;
26 const unsigned int primID;
27
28 __forceinline Intersect1Epilog1(RayHit& ray,
29 IntersectContext* context,
30 const unsigned int geomID,
31 const unsigned int primID)
32 : ray(ray), context(context), geomID(geomID), primID(primID) {}
33
34 template<typename Hit>
35 __forceinline bool operator() (Hit& hit) const
36 {
37 /* ray mask test */
38 Scene* scene MAYBE_UNUSED = context->scene;
39 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
40#if defined(EMBREE_RAY_MASK)
41 if ((geometry->mask & ray.mask) == 0) return false;
42#endif
43 hit.finalize();
44
45 /* intersection filter test */
46#if defined(EMBREE_FILTER_FUNCTION)
47 if (filter) {
48 if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
49 HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
50 const float old_t = ray.tfar;
51 ray.tfar = hit.t;
52 bool found = runIntersectionFilter1(geometry,ray,context,h);
53 if (!found) ray.tfar = old_t;
54 return found;
55 }
56 }
57#endif
58
59 /* update hit information */
60 ray.tfar = hit.t;
61 ray.Ng = hit.Ng;
62 ray.u = hit.u;
63 ray.v = hit.v;
64 ray.primID = primID;
65 ray.geomID = geomID;
66 instance_id_stack::copy_UU(context->user->instID, ray.instID);
67 return true;
68 }
69 };
70
71 template<bool filter>
72 struct Occluded1Epilog1
73 {
74 Ray& ray;
75 IntersectContext* context;
76 const unsigned int geomID;
77 const unsigned int primID;
78
79 __forceinline Occluded1Epilog1(Ray& ray,
80 IntersectContext* context,
81 const unsigned int geomID,
82 const unsigned int primID)
83 : ray(ray), context(context), geomID(geomID), primID(primID) {}
84
85 template<typename Hit>
86 __forceinline bool operator() (Hit& hit) const
87 {
88 /* ray mask test */
89 Scene* scene MAYBE_UNUSED = context->scene;
90 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
91
92
93#if defined(EMBREE_RAY_MASK)
94 if ((geometry->mask & ray.mask) == 0) return false;
95#endif
96 hit.finalize();
97
98 /* intersection filter test */
99#if defined(EMBREE_FILTER_FUNCTION)
100 if (filter) {
101 if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) {
102 HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
103 const float old_t = ray.tfar;
104 ray.tfar = hit.t;
105 const bool found = runOcclusionFilter1(geometry,ray,context,h);
106 if (!found) ray.tfar = old_t;
107 return found;
108 }
109 }
110#endif
111 return true;
112 }
113 };
114
115 template<int K, bool filter>
116 struct Intersect1KEpilog1
117 {
118 RayHitK<K>& ray;
119 size_t k;
120 IntersectContext* context;
121 const unsigned int geomID;
122 const unsigned int primID;
123
124 __forceinline Intersect1KEpilog1(RayHitK<K>& ray, size_t k,
125 IntersectContext* context,
126 const unsigned int geomID,
127 const unsigned int primID)
128 : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
129
130 template<typename Hit>
131 __forceinline bool operator() (Hit& hit) const
132 {
133 /* ray mask test */
134 Scene* scene MAYBE_UNUSED = context->scene;
135 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
136#if defined(EMBREE_RAY_MASK)
137 if ((geometry->mask & ray.mask[k]) == 0)
138 return false;
139#endif
140 hit.finalize();
141
142 /* intersection filter test */
143#if defined(EMBREE_FILTER_FUNCTION)
144 if (filter) {
145 if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
146 HitK<K> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
147 const float old_t = ray.tfar[k];
148 ray.tfar[k] = hit.t;
149 const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
150 if (!found) ray.tfar[k] = old_t;
151 return found;
152 }
153 }
154#endif
155
156 /* update hit information */
157 ray.tfar[k] = hit.t;
158 ray.Ng.x[k] = hit.Ng.x;
159 ray.Ng.y[k] = hit.Ng.y;
160 ray.Ng.z[k] = hit.Ng.z;
161 ray.u[k] = hit.u;
162 ray.v[k] = hit.v;
163 ray.primID[k] = primID;
164 ray.geomID[k] = geomID;
165 instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
166 return true;
167 }
168 };
169
170 template<int K, bool filter>
171 struct Occluded1KEpilog1
172 {
173 RayK<K>& ray;
174 size_t k;
175 IntersectContext* context;
176 const unsigned int geomID;
177 const unsigned int primID;
178
179 __forceinline Occluded1KEpilog1(RayK<K>& ray, size_t k,
180 IntersectContext* context,
181 const unsigned int geomID,
182 const unsigned int primID)
183 : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
184
185 template<typename Hit>
186 __forceinline bool operator() (Hit& hit) const
187 {
188 /* ray mask test */
189 Scene* scene MAYBE_UNUSED = context->scene;
190 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
191#if defined(EMBREE_RAY_MASK)
192 if ((geometry->mask & ray.mask[k]) == 0)
193 return false;
194#endif
195
196 /* intersection filter test */
197#if defined(EMBREE_FILTER_FUNCTION)
198 if (filter) {
199 if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) {
200 hit.finalize();
201 HitK<K> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng);
202 const float old_t = ray.tfar[k];
203 ray.tfar[k] = hit.t;
204 const bool found = any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h));
205 if (!found) ray.tfar[k] = old_t;
206 return found;
207 }
208 }
209#endif
210 return true;
211 }
212 };
213
214 template<int M, bool filter>
215 struct Intersect1EpilogM
216 {
217 RayHit& ray;
218 IntersectContext* context;
219 const vuint<M>& geomIDs;
220 const vuint<M>& primIDs;
221
222 __forceinline Intersect1EpilogM(RayHit& ray,
223 IntersectContext* context,
224 const vuint<M>& geomIDs,
225 const vuint<M>& primIDs)
226 : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
227
228 template<typename Hit>
229 __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
230 {
231 Scene* scene MAYBE_UNUSED = context->scene;
232 vbool<M> valid = valid_i;
233 hit.finalize();
234 size_t i = select_min(valid,hit.vt);
235 unsigned int geomID = geomIDs[i];
236
237 /* intersection filter test */
238#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
239 bool foundhit = false;
240 goto entry;
241 while (true)
242 {
243 if (unlikely(none(valid))) return foundhit;
244 i = select_min(valid,hit.vt);
245
246 geomID = geomIDs[i];
247 entry:
248 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
249
250#if defined(EMBREE_RAY_MASK)
251 /* goto next hit if mask test fails */
252 if ((geometry->mask & ray.mask) == 0) {
253 clear(valid,i);
254 continue;
255 }
256#endif
257
258#if defined(EMBREE_FILTER_FUNCTION)
259 /* call intersection filter function */
260 if (filter) {
261 if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
262 const Vec2f uv = hit.uv(i);
263 HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
264 const float old_t = ray.tfar;
265 ray.tfar = hit.t(i);
266 const bool found = runIntersectionFilter1(geometry,ray,context,h);
267 if (!found) ray.tfar = old_t;
268 foundhit |= found;
269 clear(valid,i);
270 valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value
271 continue;
272 }
273 }
274#endif
275 break;
276 }
277#endif
278
279 /* update hit information */
280 const Vec2f uv = hit.uv(i);
281 ray.tfar = hit.vt[i];
282 ray.Ng.x = hit.vNg.x[i];
283 ray.Ng.y = hit.vNg.y[i];
284 ray.Ng.z = hit.vNg.z[i];
285 ray.u = uv.x;
286 ray.v = uv.y;
287 ray.primID = primIDs[i];
288 ray.geomID = geomID;
289 instance_id_stack::copy_UU(context->user->instID, ray.instID);
290 return true;
291
292 }
293 };
294
295 template<int M, bool filter>
296 struct Occluded1EpilogM
297 {
298 Ray& ray;
299 IntersectContext* context;
300 const vuint<M>& geomIDs;
301 const vuint<M>& primIDs;
302
303 __forceinline Occluded1EpilogM(Ray& ray,
304 IntersectContext* context,
305 const vuint<M>& geomIDs,
306 const vuint<M>& primIDs)
307 : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
308
309 template<typename Hit>
310 __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
311 {
312 Scene* scene MAYBE_UNUSED = context->scene;
313 /* intersection filter test */
314#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
315 if (unlikely(filter))
316 hit.finalize(); /* called only once */
317
318 vbool<M> valid = valid_i;
319 size_t m=movemask(valid);
320 goto entry;
321 while (true)
322 {
323 if (unlikely(m == 0)) return false;
324 entry:
325 size_t i=bsf(m);
326
327 const unsigned int geomID = geomIDs[i];
328 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
329
330#if defined(EMBREE_RAY_MASK)
331 /* goto next hit if mask test fails */
332 if ((geometry->mask & ray.mask) == 0) {
333 m=btc(m,i);
334 continue;
335 }
336#endif
337
338#if defined(EMBREE_FILTER_FUNCTION)
339 /* if we have no filter then the test passed */
340 if (filter) {
341 if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
342 {
343 const Vec2f uv = hit.uv(i);
344 HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
345 const float old_t = ray.tfar;
346 ray.tfar = hit.t(i);
347 if (runOcclusionFilter1(geometry,ray,context,h)) return true;
348 ray.tfar = old_t;
349 m=btc(m,i);
350 continue;
351 }
352 }
353#endif
354 break;
355 }
356#endif
357
358 return true;
359 }
360 };
361
362 template<int M, bool filter>
363 struct Intersect1EpilogMU
364 {
365 RayHit& ray;
366 IntersectContext* context;
367 const unsigned int geomID;
368 const unsigned int primID;
369
370 __forceinline Intersect1EpilogMU(RayHit& ray,
371 IntersectContext* context,
372 const unsigned int geomID,
373 const unsigned int primID)
374 : ray(ray), context(context), geomID(geomID), primID(primID) {}
375
376 template<typename Hit>
377 __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
378 {
379 /* ray mask test */
380 Scene* scene MAYBE_UNUSED = context->scene;
381 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
382#if defined(EMBREE_RAY_MASK)
383 if ((geometry->mask & ray.mask) == 0) return false;
384#endif
385
386 vbool<M> valid = valid_i;
387 hit.finalize();
388
389 size_t i = select_min(valid,hit.vt);
390
391 /* intersection filter test */
392#if defined(EMBREE_FILTER_FUNCTION)
393 if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter()))
394 {
395 bool foundhit = false;
396 while (true)
397 {
398 /* call intersection filter function */
399 Vec2f uv = hit.uv(i);
400 const float old_t = ray.tfar;
401 ray.tfar = hit.t(i);
402 HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
403 const bool found = runIntersectionFilter1(geometry,ray,context,h);
404 if (!found) ray.tfar = old_t;
405 foundhit |= found;
406 clear(valid,i);
407 valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value
408 if (unlikely(none(valid))) break;
409 i = select_min(valid,hit.vt);
410 }
411 return foundhit;
412 }
413#endif
414
415 /* update hit information */
416 const Vec2f uv = hit.uv(i);
417 const Vec3fa Ng = hit.Ng(i);
418 ray.tfar = hit.t(i);
419 ray.Ng.x = Ng.x;
420 ray.Ng.y = Ng.y;
421 ray.Ng.z = Ng.z;
422 ray.u = uv.x;
423 ray.v = uv.y;
424 ray.primID = primID;
425 ray.geomID = geomID;
426 instance_id_stack::copy_UU(context->user->instID, ray.instID);
427 return true;
428 }
429 };
430
431 template<int M, bool filter>
432 struct Occluded1EpilogMU
433 {
434 Ray& ray;
435 IntersectContext* context;
436 const unsigned int geomID;
437 const unsigned int primID;
438
439 __forceinline Occluded1EpilogMU(Ray& ray,
440 IntersectContext* context,
441 const unsigned int geomID,
442 const unsigned int primID)
443 : ray(ray), context(context), geomID(geomID), primID(primID) {}
444
445 template<typename Hit>
446 __forceinline bool operator() (const vbool<M>& valid, Hit& hit) const
447 {
448 /* ray mask test */
449 Scene* scene MAYBE_UNUSED = context->scene;
450 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
451#if defined(EMBREE_RAY_MASK)
452 if ((geometry->mask & ray.mask) == 0) return false;
453#endif
454
455 /* intersection filter test */
456#if defined(EMBREE_FILTER_FUNCTION)
457 if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
458 {
459 hit.finalize();
460 for (size_t m=movemask(valid), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m))
461 {
462 const Vec2f uv = hit.uv(i);
463 const float old_t = ray.tfar;
464 ray.tfar = hit.t(i);
465 HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
466 if (runOcclusionFilter1(geometry,ray,context,h)) return true;
467 ray.tfar = old_t;
468 }
469 return false;
470 }
471#endif
472 return true;
473 }
474 };
475
476 template<int M, int K, bool filter>
477 struct IntersectKEpilogM
478 {
479 RayHitK<K>& ray;
480 IntersectContext* context;
481 const vuint<M>& geomIDs;
482 const vuint<M>& primIDs;
483 const size_t i;
484
485 __forceinline IntersectKEpilogM(RayHitK<K>& ray,
486 IntersectContext* context,
487 const vuint<M>& geomIDs,
488 const vuint<M>& primIDs,
489 size_t i)
490 : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {}
491
492 template<typename Hit>
493 __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
494 {
495 Scene* scene MAYBE_UNUSED = context->scene;
496
497 vfloat<K> u, v, t;
498 Vec3vf<K> Ng;
499 vbool<K> valid = valid_i;
500
501 std::tie(u,v,t,Ng) = hit();
502
503 const unsigned int geomID = geomIDs[i];
504 const unsigned int primID = primIDs[i];
505 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
506
507 /* ray masking test */
508#if defined(EMBREE_RAY_MASK)
509 valid &= (geometry->mask & ray.mask) != 0;
510 if (unlikely(none(valid))) return false;
511#endif
512
513 /* occlusion filter test */
514#if defined(EMBREE_FILTER_FUNCTION)
515 if (filter) {
516 if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
517 HitK<K> h(context->user,geomID,primID,u,v,Ng);
518 const vfloat<K> old_t = ray.tfar;
519 ray.tfar = select(valid,t,ray.tfar);
520 const vbool<K> m_accept = runIntersectionFilter(valid,geometry,ray,context,h);
521 ray.tfar = select(m_accept,ray.tfar,old_t);
522 return m_accept;
523 }
524 }
525#endif
526
527 /* update hit information */
528 vfloat<K>::store(valid,&ray.tfar,t);
529 vfloat<K>::store(valid,&ray.Ng.x,Ng.x);
530 vfloat<K>::store(valid,&ray.Ng.y,Ng.y);
531 vfloat<K>::store(valid,&ray.Ng.z,Ng.z);
532 vfloat<K>::store(valid,&ray.u,u);
533 vfloat<K>::store(valid,&ray.v,v);
534 vuint<K>::store(valid,&ray.primID,primID);
535 vuint<K>::store(valid,&ray.geomID,geomID);
536 instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid);
537 return valid;
538 }
539 };
540
541 template<int M, int K, bool filter>
542 struct OccludedKEpilogM
543 {
544 vbool<K>& valid0;
545 RayK<K>& ray;
546 IntersectContext* context;
547 const vuint<M>& geomIDs;
548 const vuint<M>& primIDs;
549 const size_t i;
550
551 __forceinline OccludedKEpilogM(vbool<K>& valid0,
552 RayK<K>& ray,
553 IntersectContext* context,
554 const vuint<M>& geomIDs,
555 const vuint<M>& primIDs,
556 size_t i)
557 : valid0(valid0), ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {}
558
559 template<typename Hit>
560 __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
561 {
562 vbool<K> valid = valid_i;
563
564 /* ray masking test */
565 Scene* scene MAYBE_UNUSED = context->scene;
566 const unsigned int geomID MAYBE_UNUSED = geomIDs[i];
567 const unsigned int primID MAYBE_UNUSED = primIDs[i];
568 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
569#if defined(EMBREE_RAY_MASK)
570 valid &= (geometry->mask & ray.mask) != 0;
571 if (unlikely(none(valid))) return valid;
572#endif
573
574 /* intersection filter test */
575#if defined(EMBREE_FILTER_FUNCTION)
576 if (filter) {
577 if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
578 {
579 vfloat<K> u, v, t;
580 Vec3vf<K> Ng;
581 std::tie(u,v,t,Ng) = hit();
582 HitK<K> h(context->user,geomID,primID,u,v,Ng);
583 const vfloat<K> old_t = ray.tfar;
584 ray.tfar = select(valid,t,ray.tfar);
585 valid = runOcclusionFilter(valid,geometry,ray,context,h);
586 ray.tfar = select(valid,ray.tfar,old_t);
587 }
588 }
589#endif
590
591 /* update occlusion */
592 valid0 = valid0 & !valid;
593 return valid;
594 }
595 };
596
597 template<int M, int K, bool filter>
598 struct IntersectKEpilogMU
599 {
600 RayHitK<K>& ray;
601 IntersectContext* context;
602 const unsigned int geomID;
603 const unsigned int primID;
604
605 __forceinline IntersectKEpilogMU(RayHitK<K>& ray,
606 IntersectContext* context,
607 const unsigned int geomID,
608 const unsigned int primID)
609 : ray(ray), context(context), geomID(geomID), primID(primID) {}
610
611 template<typename Hit>
612 __forceinline vbool<K> operator() (const vbool<K>& valid_org, const Hit& hit) const
613 {
614 vbool<K> valid = valid_org;
615 vfloat<K> u, v, t;
616 Vec3vf<K> Ng;
617 std::tie(u,v,t,Ng) = hit();
618
619 Scene* scene MAYBE_UNUSED = context->scene;
620 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
621
622 /* ray masking test */
623#if defined(EMBREE_RAY_MASK)
624 valid &= (geometry->mask & ray.mask) != 0;
625 if (unlikely(none(valid))) return false;
626#endif
627
628 /* intersection filter test */
629#if defined(EMBREE_FILTER_FUNCTION)
630 if (filter) {
631 if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
632 HitK<K> h(context->user,geomID,primID,u,v,Ng);
633 const vfloat<K> old_t = ray.tfar;
634 ray.tfar = select(valid,t,ray.tfar);
635 const vbool<K> m_accept = runIntersectionFilter(valid,geometry,ray,context,h);
636 ray.tfar = select(m_accept,ray.tfar,old_t);
637 return m_accept;
638 }
639 }
640#endif
641
642 /* update hit information */
643 vfloat<K>::store(valid,&ray.tfar,t);
644 vfloat<K>::store(valid,&ray.Ng.x,Ng.x);
645 vfloat<K>::store(valid,&ray.Ng.y,Ng.y);
646 vfloat<K>::store(valid,&ray.Ng.z,Ng.z);
647 vfloat<K>::store(valid,&ray.u,u);
648 vfloat<K>::store(valid,&ray.v,v);
649 vuint<K>::store(valid,&ray.primID,primID);
650 vuint<K>::store(valid,&ray.geomID,geomID);
651 instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid);
652 return valid;
653 }
654 };
655
656 template<int M, int K, bool filter>
657 struct OccludedKEpilogMU
658 {
659 vbool<K>& valid0;
660 RayK<K>& ray;
661 IntersectContext* context;
662 const unsigned int geomID;
663 const unsigned int primID;
664
665 __forceinline OccludedKEpilogMU(vbool<K>& valid0,
666 RayK<K>& ray,
667 IntersectContext* context,
668 const unsigned int geomID,
669 const unsigned int primID)
670 : valid0(valid0), ray(ray), context(context), geomID(geomID), primID(primID) {}
671
672 template<typename Hit>
673 __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const
674 {
675 vbool<K> valid = valid_i;
676 Scene* scene MAYBE_UNUSED = context->scene;
677 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
678
679#if defined(EMBREE_RAY_MASK)
680 valid &= (geometry->mask & ray.mask) != 0;
681 if (unlikely(none(valid))) return false;
682#endif
683
684 /* occlusion filter test */
685#if defined(EMBREE_FILTER_FUNCTION)
686 if (filter) {
687 if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
688 {
689 vfloat<K> u, v, t;
690 Vec3vf<K> Ng;
691 std::tie(u,v,t,Ng) = hit();
692 HitK<K> h(context->user,geomID,primID,u,v,Ng);
693 const vfloat<K> old_t = ray.tfar;
694 ray.tfar = select(valid,t,ray.tfar);
695 valid = runOcclusionFilter(valid,geometry,ray,context,h);
696 ray.tfar = select(valid,ray.tfar,old_t);
697 }
698 }
699#endif
700
701 /* update occlusion */
702 valid0 = valid0 & !valid;
703 return valid;
704 }
705 };
706
707 template<int M, int K, bool filter>
708 struct Intersect1KEpilogM
709 {
710 RayHitK<K>& ray;
711 size_t k;
712 IntersectContext* context;
713 const vuint<M>& geomIDs;
714 const vuint<M>& primIDs;
715
716 __forceinline Intersect1KEpilogM(RayHitK<K>& ray, size_t k,
717 IntersectContext* context,
718 const vuint<M>& geomIDs,
719 const vuint<M>& primIDs)
720 : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
721
722 template<typename Hit>
723 __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
724 {
725 Scene* scene MAYBE_UNUSED = context->scene;
726 vbool<M> valid = valid_i;
727 hit.finalize();
728 size_t i = select_min(valid,hit.vt);
729 assert(i<M);
730 unsigned int geomID = geomIDs[i];
731
732 /* intersection filter test */
733#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
734 bool foundhit = false;
735 goto entry;
736 while (true)
737 {
738 if (unlikely(none(valid))) return foundhit;
739 i = select_min(valid,hit.vt);
740 assert(i<M);
741 geomID = geomIDs[i];
742 entry:
743 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
744
745#if defined(EMBREE_RAY_MASK)
746 /* goto next hit if mask test fails */
747 if ((geometry->mask & ray.mask[k]) == 0) {
748 clear(valid,i);
749 continue;
750 }
751#endif
752
753#if defined(EMBREE_FILTER_FUNCTION)
754 /* call intersection filter function */
755 if (filter) {
756 if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) {
757 assert(i<M);
758 const Vec2f uv = hit.uv(i);
759 HitK<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
760 const float old_t = ray.tfar[k];
761 ray.tfar[k] = hit.t(i);
762 const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
763 if (!found) ray.tfar[k] = old_t;
764 foundhit = foundhit | found;
765 clear(valid,i);
766 valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value
767 continue;
768 }
769 }
770#endif
771 break;
772 }
773#endif
774 assert(i<M);
775 /* update hit information */
776 const Vec2f uv = hit.uv(i);
777 ray.tfar[k] = hit.t(i);
778 ray.Ng.x[k] = hit.vNg.x[i];
779 ray.Ng.y[k] = hit.vNg.y[i];
780 ray.Ng.z[k] = hit.vNg.z[i];
781 ray.u[k] = uv.x;
782 ray.v[k] = uv.y;
783 ray.primID[k] = primIDs[i];
784 ray.geomID[k] = geomID;
785 instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
786 return true;
787 }
788 };
789
790 template<int M, int K, bool filter>
791 struct Occluded1KEpilogM
792 {
793 RayK<K>& ray;
794 size_t k;
795 IntersectContext* context;
796 const vuint<M>& geomIDs;
797 const vuint<M>& primIDs;
798
799 __forceinline Occluded1KEpilogM(RayK<K>& ray, size_t k,
800 IntersectContext* context,
801 const vuint<M>& geomIDs,
802 const vuint<M>& primIDs)
803 : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {}
804
805 template<typename Hit>
806 __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
807 {
808 Scene* scene MAYBE_UNUSED = context->scene;
809
810 /* intersection filter test */
811#if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK)
812 if (unlikely(filter))
813 hit.finalize(); /* called only once */
814
815 vbool<M> valid = valid_i;
816 size_t m=movemask(valid);
817 goto entry;
818 while (true)
819 {
820 if (unlikely(m == 0)) return false;
821 entry:
822 size_t i=bsf(m);
823
824 const unsigned int geomID = geomIDs[i];
825 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
826
827#if defined(EMBREE_RAY_MASK)
828 /* goto next hit if mask test fails */
829 if ((geometry->mask & ray.mask[k]) == 0) {
830 m=btc(m,i);
831 continue;
832 }
833#endif
834
835#if defined(EMBREE_FILTER_FUNCTION)
836 /* execute occlusion filer */
837 if (filter) {
838 if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
839 {
840 const Vec2f uv = hit.uv(i);
841 const float old_t = ray.tfar[k];
842 ray.tfar[k] = hit.t(i);
843 HitK<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i));
844 if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true;
845 ray.tfar[k] = old_t;
846 m=btc(m,i);
847 continue;
848 }
849 }
850#endif
851 break;
852 }
853#endif
854 return true;
855 }
856 };
857
858 template<int M, int K, bool filter>
859 struct Intersect1KEpilogMU
860 {
861 RayHitK<K>& ray;
862 size_t k;
863 IntersectContext* context;
864 const unsigned int geomID;
865 const unsigned int primID;
866
867 __forceinline Intersect1KEpilogMU(RayHitK<K>& ray, size_t k,
868 IntersectContext* context,
869 const unsigned int geomID,
870 const unsigned int primID)
871 : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
872
873 template<typename Hit>
874 __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
875 {
876 Scene* scene MAYBE_UNUSED = context->scene;
877 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
878#if defined(EMBREE_RAY_MASK)
879 /* ray mask test */
880 if ((geometry->mask & ray.mask[k]) == 0)
881 return false;
882#endif
883
884 /* finalize hit calculation */
885 vbool<M> valid = valid_i;
886 hit.finalize();
887 size_t i = select_min(valid,hit.vt);
888
889 /* intersection filter test */
890#if defined(EMBREE_FILTER_FUNCTION)
891 if (filter) {
892 if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter()))
893 {
894 bool foundhit = false;
895 while (true)
896 {
897 const Vec2f uv = hit.uv(i);
898 const float old_t = ray.tfar[k];
899 ray.tfar[k] = hit.t(i);
900 HitK<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
901 const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h));
902 if (!found) ray.tfar[k] = old_t;
903 foundhit = foundhit | found;
904 clear(valid,i);
905 valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value
906 if (unlikely(none(valid))) break;
907 i = select_min(valid,hit.vt);
908 }
909 return foundhit;
910 }
911 }
912#endif
913
914 /* update hit information */
915 const Vec2f uv = hit.uv(i);
916 const Vec3fa Ng = hit.Ng(i);
917 ray.tfar[k] = hit.t(i);
918 ray.Ng.x[k] = Ng.x;
919 ray.Ng.y[k] = Ng.y;
920 ray.Ng.z[k] = Ng.z;
921 ray.u[k] = uv.x;
922 ray.v[k] = uv.y;
923 ray.primID[k] = primID;
924 ray.geomID[k] = geomID;
925 instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k);
926 return true;
927 }
928 };
929
930 template<int M, int K, bool filter>
931 struct Occluded1KEpilogMU
932 {
933 RayK<K>& ray;
934 size_t k;
935 IntersectContext* context;
936 const unsigned int geomID;
937 const unsigned int primID;
938
939 __forceinline Occluded1KEpilogMU(RayK<K>& ray, size_t k,
940 IntersectContext* context,
941 const unsigned int geomID,
942 const unsigned int primID)
943 : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {}
944
945 template<typename Hit>
946 __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const
947 {
948 Scene* scene MAYBE_UNUSED = context->scene;
949 Geometry* geometry MAYBE_UNUSED = scene->get(geomID);
950#if defined(EMBREE_RAY_MASK)
951 /* ray mask test */
952 if ((geometry->mask & ray.mask[k]) == 0)
953 return false;
954#endif
955
956 /* intersection filter test */
957#if defined(EMBREE_FILTER_FUNCTION)
958 if (filter) {
959 if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))
960 {
961 hit.finalize();
962 for (size_t m=movemask(valid_i), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m))
963 {
964 const Vec2f uv = hit.uv(i);
965 const float old_t = ray.tfar[k];
966 ray.tfar[k] = hit.t(i);
967 HitK<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i));
968 if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true;
969 ray.tfar[k] = old_t;
970 }
971 return false;
972 }
973 }
974#endif
975 return true;
976 }
977 };
978 }
979}
980