| 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 |  |