// ======================================================================== // // Copyright 2009-2017 Intel Corporation // // // // Licensed under the Apache License, Version 2.0 (the "License"); // // you may not use this file except in compliance with the License. // // You may obtain a copy of the License at // // // // http://www.apache.org/licenses/LICENSE-2.0 // // // // Unless required by applicable law or agreed to in writing, software // // distributed under the License is distributed on an "AS IS" BASIS, // // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // // limitations under the License. // // ======================================================================== // #pragma once #include "triangle.h" #include "trianglev.h" #include "trianglev_mb.h" #include "intersector_epilog.h" /*! Modified Pluecker ray/triangle intersector. The test first shifts * the ray origin into the origin of the coordinate system and then * uses Pluecker coordinates for the intersection. Due to the shift, * the Pluecker coordinate calculation simplifies and the tests get * numerically stable. The edge equations are watertight along the * edge for neighboring triangles. */ namespace embree { namespace isa { template struct PlueckerHitM { __forceinline PlueckerHitM(const vfloat& U, const vfloat& V, const vfloat& T, const vfloat& den, const Vec3>& Ng, const UVMapper& mapUV) : U(U), V(V), T(T), den(den), mapUV(mapUV), vNg(Ng) {} __forceinline void finalize() { const vfloat rcpDen = rcp(den); vt = T * rcpDen; vu = U * rcpDen; vv = V * rcpDen; mapUV(vu,vv); } __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); } __forceinline float t (const size_t i) const { return vt[i]; } __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); } private: const vfloat U; const vfloat V; const vfloat T; const vfloat den; const UVMapper& mapUV; public: vfloat vu; vfloat vv; vfloat vt; Vec3> vNg; }; template struct PlueckerIntersector1 { __forceinline PlueckerIntersector1() {} __forceinline PlueckerIntersector1(const Ray& ray, const void* ptr) {} template __forceinline bool intersect(Ray& ray, const Vec3>& tri_v0, const Vec3>& tri_v1, const Vec3>& tri_v2, const UVMapper& mapUV, const Epilog& epilog) const { /* calculate vertices relative to ray origin */ typedef Vec3> Vec3vfM; const Vec3vfM O = Vec3vfM(ray.org); const Vec3vfM D = Vec3vfM(ray.dir); const Vec3vfM v0 = tri_v0-O; const Vec3vfM v1 = tri_v1-O; const Vec3vfM v2 = tri_v2-O; /* calculate triangle edges */ const Vec3vfM e0 = v2-v0; const Vec3vfM e1 = v0-v1; const Vec3vfM e2 = v1-v2; /* perform edge tests */ const vfloat U = dot(cross(v2+v0,e0),D); const vfloat V = dot(cross(v0+v1,e1),D); const vfloat W = dot(cross(v1+v2,e2),D); #if defined(EMBREE_BACKFACE_CULLING) const vfloat maxUVW = max(U,V,W); vbool valid = maxUVW <= 0.0f; #else const vfloat minUVW = min(U,V,W); const vfloat maxUVW = max(U,V,W); vbool valid = (minUVW >= 0.0f) | (maxUVW <= 0.0f); #endif if (unlikely(none(valid))) return false; /* calculate geometry normal and denominator */ const Vec3vfM Ng = stable_triangle_normal(e2,e1,e0); const vfloat den = twice(dot(Ng,D)); const vfloat absDen = abs(den); const vfloat sgnDen = signmsk(den); /* perform depth test */ const vfloat T = twice(dot(v0,Ng)); valid &= ((T^sgnDen) >= absDen*vfloat(ray.tnear)); valid &=(absDen*vfloat(ray.tfar) >= (T^sgnDen)); if (unlikely(none(valid))) return false; /* avoid division by 0 */ valid &= den != vfloat(zero); if (unlikely(none(valid))) return false; /* update hit information */ PlueckerHitM hit(U,V,T,den,Ng,mapUV); return epilog(valid,hit); } }; template struct PlueckerHitK { __forceinline PlueckerHitK(const vfloat& U, const vfloat& V, const vfloat& T, const vfloat& den, const Vec3>& Ng, const UVMapper& mapUV) : U(U), V(V), T(T), den(den), Ng(Ng), mapUV(mapUV) {} __forceinline std::tuple,vfloat,vfloat,Vec3>> operator() () const { const vfloat rcpDen = rcp(den); const vfloat t = T * rcpDen; vfloat u = U * rcpDen; vfloat v = V * rcpDen; mapUV(u,v); return std::make_tuple(u,v,t,Ng); } private: const vfloat U; const vfloat V; const vfloat T; const vfloat den; const Vec3> Ng; const UVMapper& mapUV; }; template struct PlueckerIntersectorK { __forceinline PlueckerIntersectorK(const vbool& valid, const RayK& ray) {} /*! Intersects K rays with one of M triangles. */ template __forceinline vbool intersectK(const vbool& valid0, RayK& ray, const Vec3>& tri_v0, const Vec3>& tri_v1, const Vec3>& tri_v2, const UVMapper& mapUV, const Epilog& epilog) const { /* calculate vertices relative to ray origin */ typedef Vec3> Vec3vfK; vbool valid = valid0; const Vec3vfK O = ray.org; const Vec3vfK D = ray.dir; const Vec3vfK v0 = tri_v0-O; const Vec3vfK v1 = tri_v1-O; const Vec3vfK v2 = tri_v2-O; /* calculate triangle edges */ const Vec3vfK e0 = v2-v0; const Vec3vfK e1 = v0-v1; const Vec3vfK e2 = v1-v2; /* perform edge tests */ const vfloat U = dot(Vec3vfK(cross(v2+v0,e0)),D); const vfloat V = dot(Vec3vfK(cross(v0+v1,e1)),D); const vfloat W = dot(Vec3vfK(cross(v1+v2,e2)),D); #if defined(EMBREE_BACKFACE_CULLING) const vfloat maxUVW = max(U,V,W); valid &= maxUVW <= 0.0f; #else const vfloat minUVW = min(U,V,W); const vfloat maxUVW = max(U,V,W); valid &= (minUVW >= 0.0f) | (maxUVW <= 0.0f); #endif if (unlikely(none(valid))) return false; /* calculate geometry normal and denominator */ const Vec3vfK Ng = stable_triangle_normal(e2,e1,e0); const vfloat den = twice(dot(Vec3vfK(Ng),D)); const vfloat absDen = abs(den); const vfloat sgnDen = signmsk(den); /* perform depth test */ const vfloat T = twice(dot(v0,Vec3vfK(Ng))); valid &= ((T^sgnDen) >= absDen*ray.tnear); valid &= (absDen*ray.tfar >= (T^sgnDen)); if (unlikely(none(valid))) return false; /* avoid division by 0 */ valid &= den != vfloat(zero); if (unlikely(none(valid))) return false; /* calculate hit information */ PlueckerHitK hit(U,V,T,den,Ng,mapUV); return epilog(valid,hit); } /*! Intersect k'th ray from ray packet of size K with M triangles. */ template __forceinline bool intersect(RayK& ray, size_t k, const Vec3>& tri_v0, const Vec3>& tri_v1, const Vec3>& tri_v2, const UVMapper& mapUV, const Epilog& epilog) const { /* calculate vertices relative to ray origin */ typedef Vec3> Vec3vfM; const Vec3vfM O = broadcast>(ray.org,k); const Vec3vfM D = broadcast>(ray.dir,k); const Vec3vfM v0 = tri_v0-O; const Vec3vfM v1 = tri_v1-O; const Vec3vfM v2 = tri_v2-O; /* calculate triangle edges */ const Vec3vfM e0 = v2-v0; const Vec3vfM e1 = v0-v1; const Vec3vfM e2 = v1-v2; /* perform edge tests */ const vfloat U = dot(cross(v2+v0,e0),D); const vfloat V = dot(cross(v0+v1,e1),D); const vfloat W = dot(cross(v1+v2,e2),D); #if defined(EMBREE_BACKFACE_CULLING) const vfloat maxUVW = max(U,V,W); vbool valid = maxUVW <= 0.0f; #else const vfloat minUVW = min(U,V,W); const vfloat maxUVW = max(U,V,W); vbool valid = (minUVW >= 0.0f) | (maxUVW <= 0.0f); #endif if (unlikely(none(valid))) return false; /* calculate geometry normal and denominator */ const Vec3vfM Ng = stable_triangle_normal(e2,e1,e0); const vfloat den = twice(dot(Ng,D)); const vfloat absDen = abs(den); const vfloat sgnDen = signmsk(den); /* perform depth test */ const vfloat T = twice(dot(v0,Ng)); valid &= ((T^sgnDen) >= absDen*vfloat(ray.tnear[k])); valid &= (absDen*vfloat(ray.tfar[k]) >= (T^sgnDen)); if (unlikely(none(valid))) return false; /* avoid division by 0 */ valid &= den != vfloat(zero); if (unlikely(none(valid))) return false; /* calculate hit information */ PlueckerHitM hit(U,V,T,den,Ng,mapUV); return epilog(valid,hit); } }; } }