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 | |
10 | namespace 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(i: 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,hit&: 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(src: context->user->instID, tgt: 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(i: 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,hit&: 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(i: 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(i: 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(i: 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,hit&: 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(src: context->user->instID, tgt: 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(v: m); |
326 | |
327 | const unsigned int geomID = geomIDs[i]; |
328 | Geometry* geometry MAYBE_UNUSED = scene->get(i: 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,hit&: h)) return true; |
348 | ray.tfar = old_t; |
349 | m=btc(v: 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(i: 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,hit&: 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(src: context->user->instID, tgt: 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(i: 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(v: m); m!=0; m=btc(v: m,i), i=bsf(v: 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,hit&: 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(i: 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(i: 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(i: 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(i: 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(i: 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(v: m); |
823 | |
824 | const unsigned int geomID = geomIDs[i]; |
825 | Geometry* geometry MAYBE_UNUSED = scene->get(i: 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(v: 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(i: 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(i: 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(v: m); m!=0; m=btc(v: m,i), i=bsf(v: 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 | |