767e374dce
Since Embree v3.13.0 supports AARCH64, switch back to the official repo instead of using Embree-aarch64. `thirdparty/embree/patches/godot-changes.patch` should now contain an accurate diff of the changes done to the library.
980 lines
32 KiB
C++
980 lines
32 KiB
C++
// 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;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline Intersect1Epilog1(RayHit& ray,
|
|
IntersectContext* 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);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template<bool filter>
|
|
struct Occluded1Epilog1
|
|
{
|
|
Ray& ray;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline Occluded1Epilog1(Ray& ray,
|
|
IntersectContext* 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;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline Intersect1KEpilog1(RayHitK<K>& ray, size_t k,
|
|
IntersectContext* 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);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template<int K, bool filter>
|
|
struct Occluded1KEpilog1
|
|
{
|
|
RayK<K>& ray;
|
|
size_t k;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline Occluded1KEpilog1(RayK<K>& ray, size_t k,
|
|
IntersectContext* 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;
|
|
IntersectContext* context;
|
|
const vuint<M>& geomIDs;
|
|
const vuint<M>& primIDs;
|
|
|
|
__forceinline Intersect1EpilogM(RayHit& ray,
|
|
IntersectContext* 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);
|
|
return true;
|
|
|
|
}
|
|
};
|
|
|
|
template<int M, bool filter>
|
|
struct Occluded1EpilogM
|
|
{
|
|
Ray& ray;
|
|
IntersectContext* context;
|
|
const vuint<M>& geomIDs;
|
|
const vuint<M>& primIDs;
|
|
|
|
__forceinline Occluded1EpilogM(Ray& ray,
|
|
IntersectContext* 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;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline Intersect1EpilogMU(RayHit& ray,
|
|
IntersectContext* 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);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template<int M, bool filter>
|
|
struct Occluded1EpilogMU
|
|
{
|
|
Ray& ray;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline Occluded1EpilogMU(Ray& ray,
|
|
IntersectContext* 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;
|
|
IntersectContext* context;
|
|
const vuint<M>& geomIDs;
|
|
const vuint<M>& primIDs;
|
|
const size_t i;
|
|
|
|
__forceinline IntersectKEpilogM(RayHitK<K>& ray,
|
|
IntersectContext* 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);
|
|
return valid;
|
|
}
|
|
};
|
|
|
|
template<int M, int K, bool filter>
|
|
struct OccludedKEpilogM
|
|
{
|
|
vbool<K>& valid0;
|
|
RayK<K>& ray;
|
|
IntersectContext* context;
|
|
const vuint<M>& geomIDs;
|
|
const vuint<M>& primIDs;
|
|
const size_t i;
|
|
|
|
__forceinline OccludedKEpilogM(vbool<K>& valid0,
|
|
RayK<K>& ray,
|
|
IntersectContext* 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;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline IntersectKEpilogMU(RayHitK<K>& ray,
|
|
IntersectContext* 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);
|
|
return valid;
|
|
}
|
|
};
|
|
|
|
template<int M, int K, bool filter>
|
|
struct OccludedKEpilogMU
|
|
{
|
|
vbool<K>& valid0;
|
|
RayK<K>& ray;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline OccludedKEpilogMU(vbool<K>& valid0,
|
|
RayK<K>& ray,
|
|
IntersectContext* 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;
|
|
IntersectContext* context;
|
|
const vuint<M>& geomIDs;
|
|
const vuint<M>& primIDs;
|
|
|
|
__forceinline Intersect1KEpilogM(RayHitK<K>& ray, size_t k,
|
|
IntersectContext* 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);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template<int M, int K, bool filter>
|
|
struct Occluded1KEpilogM
|
|
{
|
|
RayK<K>& ray;
|
|
size_t k;
|
|
IntersectContext* context;
|
|
const vuint<M>& geomIDs;
|
|
const vuint<M>& primIDs;
|
|
|
|
__forceinline Occluded1KEpilogM(RayK<K>& ray, size_t k,
|
|
IntersectContext* 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;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline Intersect1KEpilogMU(RayHitK<K>& ray, size_t k,
|
|
IntersectContext* 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);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
template<int M, int K, bool filter>
|
|
struct Occluded1KEpilogMU
|
|
{
|
|
RayK<K>& ray;
|
|
size_t k;
|
|
IntersectContext* context;
|
|
const unsigned int geomID;
|
|
const unsigned int primID;
|
|
|
|
__forceinline Occluded1KEpilogMU(RayK<K>& ray, size_t k,
|
|
IntersectContext* 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;
|
|
}
|
|
};
|
|
}
|
|
}
|