// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once #include "../common/ray.h" #include "../common/context.h" #include "filter.h" namespace embree { namespace isa { template<int M> struct UVIdentity { __forceinline void operator() (vfloat<M>& u, vfloat<M>& v, Vec3vf<M>& Ng) const {} }; template<bool filter> struct Intersect1Epilog1 { RayHit& ray; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1Epilog1(RayHit& ray, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline bool operator() (Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask) == 0) return false; #endif hit.finalize(); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng); const float old_t = ray.tfar; ray.tfar = hit.t; bool found = runIntersectionFilter1(geometry,ray,context,h); if (!found) ray.tfar = old_t; return found; } } #endif /* update hit information */ ray.tfar = hit.t; ray.Ng = hit.Ng; ray.u = hit.u; ray.v = hit.v; ray.primID = primID; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); #if defined(RTC_GEOMETRY_INSTANCE_ARRAY) instance_id_stack::copy_UU(context->user->instPrimID, ray.instPrimID); #endif return true; } }; template<bool filter> struct Occluded1Epilog1 { Ray& ray; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1Epilog1(Ray& ray, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline bool operator() (Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask) == 0) return false; #endif hit.finalize(); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { HitK<1> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng); const float old_t = ray.tfar; ray.tfar = hit.t; const bool found = runOcclusionFilter1(geometry,ray,context,h); if (!found) ray.tfar = old_t; return found; } } #endif return true; } }; template<int K, bool filter> struct Intersect1KEpilog1 { RayHitK<K>& ray; size_t k; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1KEpilog1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline bool operator() (Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask[k]) == 0) return false; #endif hit.finalize(); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { HitK<K> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t; const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h)); if (!found) ray.tfar[k] = old_t; return found; } } #endif /* update hit information */ ray.tfar[k] = hit.t; ray.Ng.x[k] = hit.Ng.x; ray.Ng.y[k] = hit.Ng.y; ray.Ng.z[k] = hit.Ng.z; ray.u[k] = hit.u; ray.v[k] = hit.v; ray.primID[k] = primID; ray.geomID[k] = geomID; instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k); #if defined(RTC_GEOMETRY_INSTANCE_ARRAY) instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, k); #endif return true; } }; template<int K, bool filter> struct Occluded1KEpilog1 { RayK<K>& ray; size_t k; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1KEpilog1(RayK<K>& ray, size_t k, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline bool operator() (Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask[k]) == 0) return false; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { hit.finalize(); HitK<K> h(context->user,geomID,primID,hit.u,hit.v,hit.Ng); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t; const bool found = any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h)); if (!found) ray.tfar[k] = old_t; return found; } } #endif return true; } }; template<int M, bool filter> struct Intersect1EpilogM { RayHit& ray; RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; __forceinline Intersect1EpilogM(RayHit& ray, RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs) : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {} template<typename Hit> __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; vbool<M> valid = valid_i; hit.finalize(); size_t i = select_min(valid,hit.vt); unsigned int geomID = geomIDs[i]; /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK) bool foundhit = false; goto entry; while (true) { if (unlikely(none(valid))) return foundhit; i = select_min(valid,hit.vt); geomID = geomIDs[i]; entry: Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* goto next hit if mask test fails */ if ((geometry->mask & ray.mask) == 0) { clear(valid,i); continue; } #endif #if defined(EMBREE_FILTER_FUNCTION) /* call intersection filter function */ if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { const Vec2f uv = hit.uv(i); HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i)); const float old_t = ray.tfar; ray.tfar = hit.t(i); const bool found = runIntersectionFilter1(geometry,ray,context,h); if (!found) ray.tfar = old_t; foundhit |= found; clear(valid,i); valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value continue; } } #endif break; } #endif /* update hit information */ const Vec2f uv = hit.uv(i); ray.tfar = hit.vt[i]; ray.Ng.x = hit.vNg.x[i]; ray.Ng.y = hit.vNg.y[i]; ray.Ng.z = hit.vNg.z[i]; ray.u = uv.x; ray.v = uv.y; ray.primID = primIDs[i]; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); #if defined(RTC_GEOMETRY_INSTANCE_ARRAY) instance_id_stack::copy_UU(context->user->instPrimID, ray.instPrimID); #endif return true; } }; template<int M, bool filter> struct Occluded1EpilogM { Ray& ray; RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; __forceinline Occluded1EpilogM(Ray& ray, RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs) : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {} template<typename Hit> __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK) if (unlikely(filter)) hit.finalize(); /* called only once */ vbool<M> valid = valid_i; size_t m=movemask(valid); goto entry; while (true) { if (unlikely(m == 0)) return false; entry: size_t i=bsf(m); const unsigned int geomID = geomIDs[i]; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* goto next hit if mask test fails */ if ((geometry->mask & ray.mask) == 0) { m=btc(m,i); continue; } #endif #if defined(EMBREE_FILTER_FUNCTION) /* if we have no filter then the test passed */ if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { const Vec2f uv = hit.uv(i); HitK<1> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i)); const float old_t = ray.tfar; ray.tfar = hit.t(i); if (runOcclusionFilter1(geometry,ray,context,h)) return true; ray.tfar = old_t; m=btc(m,i); continue; } } #endif break; } #endif return true; } }; template<int M, bool filter> struct Intersect1EpilogMU { RayHit& ray; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1EpilogMU(RayHit& ray, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask) == 0) return false; #endif vbool<M> valid = valid_i; hit.finalize(); size_t i = select_min(valid,hit.vt); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { bool foundhit = false; while (true) { /* call intersection filter function */ Vec2f uv = hit.uv(i); const float old_t = ray.tfar; ray.tfar = hit.t(i); HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i)); const bool found = runIntersectionFilter1(geometry,ray,context,h); if (!found) ray.tfar = old_t; foundhit |= found; clear(valid,i); valid &= hit.vt <= ray.tfar; // intersection filters may modify tfar value if (unlikely(none(valid))) break; i = select_min(valid,hit.vt); } return foundhit; } #endif /* update hit information */ const Vec2f uv = hit.uv(i); const Vec3fa Ng = hit.Ng(i); ray.tfar = hit.t(i); ray.Ng.x = Ng.x; ray.Ng.y = Ng.y; ray.Ng.z = Ng.z; ray.u = uv.x; ray.v = uv.y; ray.primID = primID; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); #if defined(RTC_GEOMETRY_INSTANCE_ARRAY) instance_id_stack::copy_UU(context->user->instPrimID, ray.instPrimID); #endif return true; } }; template<int M, bool filter> struct Occluded1EpilogMU { Ray& ray; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1EpilogMU(Ray& ray, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline bool operator() (const vbool<M>& valid, Hit& hit) const { /* ray mask test */ Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) if ((geometry->mask & ray.mask) == 0) return false; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { hit.finalize(); for (size_t m=movemask(valid), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) { const Vec2f uv = hit.uv(i); const float old_t = ray.tfar; ray.tfar = hit.t(i); HitK<1> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i)); if (runOcclusionFilter1(geometry,ray,context,h)) return true; ray.tfar = old_t; } return false; } #endif return true; } }; template<int M, int K, bool filter> struct IntersectKEpilogM { RayHitK<K>& ray; RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; const size_t i; __forceinline IntersectKEpilogM(RayHitK<K>& ray, RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs, size_t i) : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {} template<typename Hit> __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; vfloat<K> u, v, t; Vec3vf<K> Ng; vbool<K> valid = valid_i; std::tie(u,v,t,Ng) = hit(); const unsigned int geomID = geomIDs[i]; const unsigned int primID = primIDs[i]; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); /* ray masking test */ #if defined(EMBREE_RAY_MASK) valid &= (geometry->mask & ray.mask) != 0; if (unlikely(none(valid))) return false; #endif /* occlusion filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { HitK<K> h(context->user,geomID,primID,u,v,Ng); const vfloat<K> old_t = ray.tfar; ray.tfar = select(valid,t,ray.tfar); const vbool<K> m_accept = runIntersectionFilter(valid,geometry,ray,context,h); ray.tfar = select(m_accept,ray.tfar,old_t); return m_accept; } } #endif /* update hit information */ vfloat<K>::store(valid,&ray.tfar,t); vfloat<K>::store(valid,&ray.Ng.x,Ng.x); vfloat<K>::store(valid,&ray.Ng.y,Ng.y); vfloat<K>::store(valid,&ray.Ng.z,Ng.z); vfloat<K>::store(valid,&ray.u,u); vfloat<K>::store(valid,&ray.v,v); vuint<K>::store(valid,&ray.primID,primID); vuint<K>::store(valid,&ray.geomID,geomID); instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid); #if defined(RTC_GEOMETRY_INSTANCE_ARRAY) instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, valid); #endif return valid; } }; template<int M, int K, bool filter> struct OccludedKEpilogM { vbool<K>& valid0; RayK<K>& ray; RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; const size_t i; __forceinline OccludedKEpilogM(vbool<K>& valid0, RayK<K>& ray, RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs, size_t i) : valid0(valid0), ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs), i(i) {} template<typename Hit> __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const { vbool<K> valid = valid_i; /* ray masking test */ Scene* scene MAYBE_UNUSED = context->scene; const unsigned int geomID MAYBE_UNUSED = geomIDs[i]; const unsigned int primID MAYBE_UNUSED = primIDs[i]; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) valid &= (geometry->mask & ray.mask) != 0; if (unlikely(none(valid))) return valid; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { vfloat<K> u, v, t; Vec3vf<K> Ng; std::tie(u,v,t,Ng) = hit(); HitK<K> h(context->user,geomID,primID,u,v,Ng); const vfloat<K> old_t = ray.tfar; ray.tfar = select(valid,t,ray.tfar); valid = runOcclusionFilter(valid,geometry,ray,context,h); ray.tfar = select(valid,ray.tfar,old_t); } } #endif /* update occlusion */ valid0 = valid0 & !valid; return valid; } }; template<int M, int K, bool filter> struct IntersectKEpilogMU { RayHitK<K>& ray; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline IntersectKEpilogMU(RayHitK<K>& ray, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline vbool<K> operator() (const vbool<K>& valid_org, const Hit& hit) const { vbool<K> valid = valid_org; vfloat<K> u, v, t; Vec3vf<K> Ng; std::tie(u,v,t,Ng) = hit(); Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); /* ray masking test */ #if defined(EMBREE_RAY_MASK) valid &= (geometry->mask & ray.mask) != 0; if (unlikely(none(valid))) return false; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { HitK<K> h(context->user,geomID,primID,u,v,Ng); const vfloat<K> old_t = ray.tfar; ray.tfar = select(valid,t,ray.tfar); const vbool<K> m_accept = runIntersectionFilter(valid,geometry,ray,context,h); ray.tfar = select(m_accept,ray.tfar,old_t); return m_accept; } } #endif /* update hit information */ vfloat<K>::store(valid,&ray.tfar,t); vfloat<K>::store(valid,&ray.Ng.x,Ng.x); vfloat<K>::store(valid,&ray.Ng.y,Ng.y); vfloat<K>::store(valid,&ray.Ng.z,Ng.z); vfloat<K>::store(valid,&ray.u,u); vfloat<K>::store(valid,&ray.v,v); vuint<K>::store(valid,&ray.primID,primID); vuint<K>::store(valid,&ray.geomID,geomID); instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid); #if defined(RTC_GEOMETRY_INSTANCE_ARRAY) instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, valid); #endif return valid; } }; template<int M, int K, bool filter> struct OccludedKEpilogMU { vbool<K>& valid0; RayK<K>& ray; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline OccludedKEpilogMU(vbool<K>& valid0, RayK<K>& ray, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : valid0(valid0), ray(ray), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline vbool<K> operator() (const vbool<K>& valid_i, const Hit& hit) const { vbool<K> valid = valid_i; Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) valid &= (geometry->mask & ray.mask) != 0; if (unlikely(none(valid))) return false; #endif /* occlusion filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { vfloat<K> u, v, t; Vec3vf<K> Ng; std::tie(u,v,t,Ng) = hit(); HitK<K> h(context->user,geomID,primID,u,v,Ng); const vfloat<K> old_t = ray.tfar; ray.tfar = select(valid,t,ray.tfar); valid = runOcclusionFilter(valid,geometry,ray,context,h); ray.tfar = select(valid,ray.tfar,old_t); } } #endif /* update occlusion */ valid0 = valid0 & !valid; return valid; } }; template<int M, int K, bool filter> struct Intersect1KEpilogM { RayHitK<K>& ray; size_t k; RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; __forceinline Intersect1KEpilogM(RayHitK<K>& ray, size_t k, RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs) : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {} template<typename Hit> __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; vbool<M> valid = valid_i; hit.finalize(); size_t i = select_min(valid,hit.vt); assert(i<M); unsigned int geomID = geomIDs[i]; /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK) bool foundhit = false; goto entry; while (true) { if (unlikely(none(valid))) return foundhit; i = select_min(valid,hit.vt); assert(i<M); geomID = geomIDs[i]; entry: Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* goto next hit if mask test fails */ if ((geometry->mask & ray.mask[k]) == 0) { clear(valid,i); continue; } #endif #if defined(EMBREE_FILTER_FUNCTION) /* call intersection filter function */ if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { assert(i<M); const Vec2f uv = hit.uv(i); HitK<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i)); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t(i); const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h)); if (!found) ray.tfar[k] = old_t; foundhit = foundhit | found; clear(valid,i); valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value continue; } } #endif break; } #endif assert(i<M); /* update hit information */ const Vec2f uv = hit.uv(i); ray.tfar[k] = hit.t(i); ray.Ng.x[k] = hit.vNg.x[i]; ray.Ng.y[k] = hit.vNg.y[i]; ray.Ng.z[k] = hit.vNg.z[i]; ray.u[k] = uv.x; ray.v[k] = uv.y; ray.primID[k] = primIDs[i]; ray.geomID[k] = geomID; instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k); #if defined(RTC_GEOMETRY_INSTANCE_ARRAY) instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, k); #endif return true; } }; template<int M, int K, bool filter> struct Occluded1KEpilogM { RayK<K>& ray; size_t k; RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; __forceinline Occluded1KEpilogM(RayK<K>& ray, size_t k, RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs) : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {} template<typename Hit> __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) || defined(EMBREE_RAY_MASK) if (unlikely(filter)) hit.finalize(); /* called only once */ vbool<M> valid = valid_i; size_t m=movemask(valid); goto entry; while (true) { if (unlikely(m == 0)) return false; entry: size_t i=bsf(m); const unsigned int geomID = geomIDs[i]; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* goto next hit if mask test fails */ if ((geometry->mask & ray.mask[k]) == 0) { m=btc(m,i); continue; } #endif #if defined(EMBREE_FILTER_FUNCTION) /* execute occlusion filer */ if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { const Vec2f uv = hit.uv(i); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t(i); HitK<K> h(context->user,geomID,primIDs[i],uv.x,uv.y,hit.Ng(i)); if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true; ray.tfar[k] = old_t; m=btc(m,i); continue; } } #endif break; } #endif return true; } }; template<int M, int K, bool filter> struct Intersect1KEpilogMU { RayHitK<K>& ray; size_t k; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1KEpilogMU(RayHitK<K>& ray, size_t k, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* ray mask test */ if ((geometry->mask & ray.mask[k]) == 0) return false; #endif /* finalize hit calculation */ vbool<M> valid = valid_i; hit.finalize(); size_t i = select_min(valid,hit.vt); /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter())) { bool foundhit = false; while (true) { const Vec2f uv = hit.uv(i); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t(i); HitK<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i)); const bool found = any(runIntersectionFilter(vbool<K>(1<<k),geometry,ray,context,h)); if (!found) ray.tfar[k] = old_t; foundhit = foundhit | found; clear(valid,i); valid &= hit.vt <= ray.tfar[k]; // intersection filters may modify tfar value if (unlikely(none(valid))) break; i = select_min(valid,hit.vt); } return foundhit; } } #endif /* update hit information */ const Vec2f uv = hit.uv(i); const Vec3fa Ng = hit.Ng(i); ray.tfar[k] = hit.t(i); ray.Ng.x[k] = Ng.x; ray.Ng.y[k] = Ng.y; ray.Ng.z[k] = Ng.z; ray.u[k] = uv.x; ray.v[k] = uv.y; ray.primID[k] = primID; ray.geomID[k] = geomID; instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k); #if defined(RTC_GEOMETRY_INSTANCE_ARRAY) instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, k); #endif return true; } }; template<int M, int K, bool filter> struct Occluded1KEpilogMU { RayK<K>& ray; size_t k; RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1KEpilogMU(RayK<K>& ray, size_t k, RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} template<typename Hit> __forceinline bool operator() (const vbool<M>& valid_i, Hit& hit) const { Scene* scene MAYBE_UNUSED = context->scene; Geometry* geometry MAYBE_UNUSED = scene->get(geomID); #if defined(EMBREE_RAY_MASK) /* ray mask test */ if ((geometry->mask & ray.mask[k]) == 0) return false; #endif /* intersection filter test */ #if defined(EMBREE_FILTER_FUNCTION) if (filter) { if (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter())) { hit.finalize(); for (size_t m=movemask(valid_i), i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) { const Vec2f uv = hit.uv(i); const float old_t = ray.tfar[k]; ray.tfar[k] = hit.t(i); HitK<K> h(context->user,geomID,primID,uv.x,uv.y,hit.Ng(i)); if (any(runOcclusionFilter(vbool<K>(1<<k),geometry,ray,context,h))) return true; ray.tfar[k] = old_t; } return false; } } #endif return true; } }; } }