quad_intersector_pluecker.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include "quad_intersector_moeller.h"
  5. /*! Modified Pluecker ray/triangle intersector. The test first shifts
  6. * the ray origin into the origin of the coordinate system and then
  7. * uses Pluecker coordinates for the intersection. Due to the shift,
  8. * the Pluecker coordinate calculation simplifies and the tests get
  9. * numerically stable. The edge equations are watertight along the
  10. * edge for neighboring triangles. */
  11. namespace embree
  12. {
  13. namespace isa
  14. {
  15. template<int M>
  16. struct QuadHitPlueckerM
  17. {
  18. __forceinline QuadHitPlueckerM() {}
  19. __forceinline QuadHitPlueckerM(const vbool<M>& valid,
  20. const vfloat<M>& U,
  21. const vfloat<M>& V,
  22. const vfloat<M>& UVW,
  23. const vfloat<M>& t,
  24. const Vec3vf<M>& Ng,
  25. const vbool<M>& flags)
  26. : U(U), V(V), UVW(UVW), tri_Ng(Ng), valid(valid), vt(t), flags(flags) {}
  27. __forceinline void finalize()
  28. {
  29. const vbool<M> invalid = abs(UVW) < min_rcp_input;
  30. const vfloat<M> rcpUVW = select(invalid,vfloat<M>(0.0f),rcp(UVW));
  31. const vfloat<M> u = min(U * rcpUVW,1.0f);
  32. const vfloat<M> v = min(V * rcpUVW,1.0f);
  33. const vfloat<M> u1 = vfloat<M>(1.0f) - u;
  34. const vfloat<M> v1 = vfloat<M>(1.0f) - v;
  35. #if !defined(__AVX__) || defined(EMBREE_BACKFACE_CULLING)
  36. vu = select(flags,u1,u);
  37. vv = select(flags,v1,v);
  38. vNg = Vec3vf<M>(tri_Ng.x,tri_Ng.y,tri_Ng.z);
  39. #else
  40. const vfloat<M> flip = select(flags,vfloat<M>(-1.0f),vfloat<M>(1.0f));
  41. vv = select(flags,u1,v);
  42. vu = select(flags,v1,u);
  43. vNg = Vec3vf<M>(flip*tri_Ng.x,flip*tri_Ng.y,flip*tri_Ng.z);
  44. #endif
  45. }
  46. __forceinline Vec2f uv(const size_t i)
  47. {
  48. const float u = vu[i];
  49. const float v = vv[i];
  50. return Vec2f(u,v);
  51. }
  52. __forceinline float t(const size_t i) { return vt[i]; }
  53. __forceinline Vec3fa Ng(const size_t i) { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
  54. private:
  55. vfloat<M> U;
  56. vfloat<M> V;
  57. vfloat<M> UVW;
  58. Vec3vf<M> tri_Ng;
  59. public:
  60. vbool<M> valid;
  61. vfloat<M> vu;
  62. vfloat<M> vv;
  63. vfloat<M> vt;
  64. Vec3vf<M> vNg;
  65. public:
  66. const vbool<M> flags;
  67. };
  68. template<int K>
  69. struct QuadHitPlueckerK
  70. {
  71. __forceinline QuadHitPlueckerK(const vfloat<K>& U,
  72. const vfloat<K>& V,
  73. const vfloat<K>& UVW,
  74. const vfloat<K>& t,
  75. const Vec3vf<K>& Ng,
  76. const vbool<K>& flags)
  77. : U(U), V(V), UVW(UVW), t(t), flags(flags), tri_Ng(Ng) {}
  78. __forceinline std::tuple<vfloat<K>,vfloat<K>,vfloat<K>,Vec3vf<K>> operator() () const
  79. {
  80. const vbool<K> invalid = abs(UVW) < min_rcp_input;
  81. const vfloat<K> rcpUVW = select(invalid,vfloat<K>(0.0f),rcp(UVW));
  82. const vfloat<K> u0 = min(U * rcpUVW,1.0f);
  83. const vfloat<K> v0 = min(V * rcpUVW,1.0f);
  84. const vfloat<K> u1 = vfloat<K>(1.0f) - u0;
  85. const vfloat<K> v1 = vfloat<K>(1.0f) - v0;
  86. const vfloat<K> u = select(flags,u1,u0);
  87. const vfloat<K> v = select(flags,v1,v0);
  88. const Vec3vf<K> Ng(tri_Ng.x,tri_Ng.y,tri_Ng.z);
  89. return std::make_tuple(u,v,t,Ng);
  90. }
  91. private:
  92. const vfloat<K> U;
  93. const vfloat<K> V;
  94. const vfloat<K> UVW;
  95. const vfloat<K> t;
  96. const vbool<K> flags;
  97. const Vec3vf<K> tri_Ng;
  98. };
  99. struct PlueckerIntersectorTriangle1
  100. {
  101. template<int M, typename Epilog>
  102. static __forceinline bool intersect(Ray& ray,
  103. const Vec3vf<M>& tri_v0,
  104. const Vec3vf<M>& tri_v1,
  105. const Vec3vf<M>& tri_v2,
  106. const vbool<M>& flags,
  107. const Epilog& epilog)
  108. {
  109. /* calculate vertices relative to ray origin */
  110. const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org);
  111. const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir);
  112. const Vec3vf<M> v0 = tri_v0-O;
  113. const Vec3vf<M> v1 = tri_v1-O;
  114. const Vec3vf<M> v2 = tri_v2-O;
  115. /* calculate triangle edges */
  116. const Vec3vf<M> e0 = v2-v0;
  117. const Vec3vf<M> e1 = v0-v1;
  118. const Vec3vf<M> e2 = v1-v2;
  119. /* perform edge tests */
  120. const vfloat<M> U = dot(cross(e0,v2+v0),D);
  121. const vfloat<M> V = dot(cross(e1,v0+v1),D);
  122. const vfloat<M> W = dot(cross(e2,v1+v2),D);
  123. const vfloat<M> UVW = U+V+W;
  124. const vfloat<M> eps = float(ulp)*abs(UVW);
  125. #if defined(EMBREE_BACKFACE_CULLING)
  126. vbool<M> valid = max(U,V,W) <= eps;
  127. #else
  128. vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
  129. #endif
  130. if (unlikely(none(valid))) return false;
  131. /* calculate geometry normal and denominator */
  132. const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
  133. const vfloat<M> den = twice(dot(Ng,D));
  134. /* perform depth test */
  135. const vfloat<M> T = twice(dot(v0,Ng));
  136. const vfloat<M> t = rcp(den)*T;
  137. valid &= vfloat<M>(ray.tnear()) <= t & t <= vfloat<M>(ray.tfar);
  138. valid &= den != vfloat<M>(zero);
  139. if (unlikely(none(valid))) return false;
  140. /* update hit information */
  141. QuadHitPlueckerM<M> hit(valid,U,V,UVW,t,Ng,flags);
  142. return epilog(valid,hit);
  143. }
  144. };
  145. /*! Intersects M quads with 1 ray */
  146. template<int M, bool filter>
  147. struct QuadMIntersector1Pluecker
  148. {
  149. __forceinline QuadMIntersector1Pluecker() {}
  150. __forceinline QuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
  151. __forceinline void intersect(RayHit& ray, RayQueryContext* context,
  152. const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
  153. const vuint<M>& geomID, const vuint<M>& primID) const
  154. {
  155. Intersect1EpilogM<M,filter> epilog(ray,context,geomID,primID);
  156. PlueckerIntersectorTriangle1::intersect<M>(ray,v0,v1,v3,vbool<M>(false),epilog);
  157. PlueckerIntersectorTriangle1::intersect<M>(ray,v2,v3,v1,vbool<M>(true),epilog);
  158. }
  159. __forceinline bool occluded(Ray& ray, RayQueryContext* context,
  160. const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
  161. const vuint<M>& geomID, const vuint<M>& primID) const
  162. {
  163. Occluded1EpilogM<M,filter> epilog(ray,context,geomID,primID);
  164. if (PlueckerIntersectorTriangle1::intersect<M>(ray,v0,v1,v3,vbool<M>(false),epilog)) return true;
  165. if (PlueckerIntersectorTriangle1::intersect<M>(ray,v2,v3,v1,vbool<M>(true ),epilog)) return true;
  166. return false;
  167. }
  168. };
  169. #if defined(__AVX__)
  170. /*! Intersects 4 quads with 1 ray using AVX */
  171. template<bool filter>
  172. struct QuadMIntersector1Pluecker<4,filter>
  173. {
  174. __forceinline QuadMIntersector1Pluecker() {}
  175. __forceinline QuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {}
  176. template<typename Epilog>
  177. __forceinline bool intersect(Ray& ray, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
  178. {
  179. const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
  180. #if !defined(EMBREE_BACKFACE_CULLING)
  181. const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
  182. const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
  183. #else
  184. const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
  185. const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
  186. #endif
  187. const vbool8 flags(0,0,0,0,1,1,1,1);
  188. return PlueckerIntersectorTriangle1::intersect<8>(ray,vtx0,vtx1,vtx2,flags,epilog);
  189. }
  190. __forceinline bool intersect(RayHit& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
  191. const vuint4& geomID, const vuint4& primID) const
  192. {
  193. return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
  194. }
  195. __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
  196. const vuint4& geomID, const vuint4& primID) const
  197. {
  198. return intersect(ray,v0,v1,v2,v3,Occluded1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID)));
  199. }
  200. };
  201. #endif
  202. /* ----------------------------- */
  203. /* -- ray packet intersectors -- */
  204. /* ----------------------------- */
  205. struct PlueckerIntersector1KTriangleM
  206. {
  207. /*! Intersect k'th ray from ray packet of size K with M triangles. */
  208. template<int M, int K, typename Epilog>
  209. static __forceinline bool intersect1(RayK<K>& ray,
  210. size_t k,
  211. const Vec3vf<M>& tri_v0,
  212. const Vec3vf<M>& tri_v1,
  213. const Vec3vf<M>& tri_v2,
  214. const vbool<M>& flags,
  215. const Epilog& epilog)
  216. {
  217. /* calculate vertices relative to ray origin */
  218. const Vec3vf<M> O = broadcast<vfloat<M>>(ray.org,k);
  219. const Vec3vf<M> D = broadcast<vfloat<M>>(ray.dir,k);
  220. const Vec3vf<M> v0 = tri_v0-O;
  221. const Vec3vf<M> v1 = tri_v1-O;
  222. const Vec3vf<M> v2 = tri_v2-O;
  223. /* calculate triangle edges */
  224. const Vec3vf<M> e0 = v2-v0;
  225. const Vec3vf<M> e1 = v0-v1;
  226. const Vec3vf<M> e2 = v1-v2;
  227. /* perform edge tests */
  228. const vfloat<M> U = dot(cross(e0,v2+v0),D);
  229. const vfloat<M> V = dot(cross(e1,v0+v1),D);
  230. const vfloat<M> W = dot(cross(e2,v1+v2),D);
  231. const vfloat<M> UVW = U+V+W;
  232. const vfloat<M> eps = float(ulp)*abs(UVW);
  233. #if defined(EMBREE_BACKFACE_CULLING)
  234. vbool<M> valid = max(U,V,W) <= eps;
  235. #else
  236. vbool<M> valid = (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
  237. #endif
  238. if (unlikely(none(valid))) return false;
  239. /* calculate geometry normal and denominator */
  240. const Vec3vf<M> Ng = stable_triangle_normal(e0,e1,e2);
  241. const vfloat<M> den = twice(dot(Ng,D));
  242. /* perform depth test */
  243. const vfloat<M> T = twice(dot(v0,Ng));
  244. const vfloat<M> t = rcp(den)*T;
  245. valid &= vfloat<M>(ray.tnear()[k]) <= t & t <= vfloat<M>(ray.tfar[k]);
  246. if (unlikely(none(valid))) return false;
  247. /* avoid division by 0 */
  248. valid &= den != vfloat<M>(zero);
  249. if (unlikely(none(valid))) return false;
  250. /* update hit information */
  251. QuadHitPlueckerM<M> hit(valid,U,V,UVW,t,Ng,flags);
  252. return epilog(valid,hit);
  253. }
  254. };
  255. template<int M, int K, bool filter>
  256. struct QuadMIntersectorKPlueckerBase
  257. {
  258. __forceinline QuadMIntersectorKPlueckerBase(const vbool<K>& valid, const RayK<K>& ray) {}
  259. /*! Intersects K rays with one of M triangles. */
  260. template<typename Epilog>
  261. __forceinline vbool<K> intersectK(const vbool<K>& valid0,
  262. RayK<K>& ray,
  263. const Vec3vf<K>& tri_v0,
  264. const Vec3vf<K>& tri_v1,
  265. const Vec3vf<K>& tri_v2,
  266. const vbool<K>& flags,
  267. const Epilog& epilog) const
  268. {
  269. /* calculate vertices relative to ray origin */
  270. vbool<K> valid = valid0;
  271. const Vec3vf<K> O = ray.org;
  272. const Vec3vf<K> D = ray.dir;
  273. const Vec3vf<K> v0 = tri_v0-O;
  274. const Vec3vf<K> v1 = tri_v1-O;
  275. const Vec3vf<K> v2 = tri_v2-O;
  276. /* calculate triangle edges */
  277. const Vec3vf<K> e0 = v2-v0;
  278. const Vec3vf<K> e1 = v0-v1;
  279. const Vec3vf<K> e2 = v1-v2;
  280. /* perform edge tests */
  281. const vfloat<K> U = dot(Vec3vf<K>(cross(e0,v2+v0)),D);
  282. const vfloat<K> V = dot(Vec3vf<K>(cross(e1,v0+v1)),D);
  283. const vfloat<K> W = dot(Vec3vf<K>(cross(e2,v1+v2)),D);
  284. const vfloat<K> UVW = U+V+W;
  285. const vfloat<K> eps = float(ulp)*abs(UVW);
  286. #if defined(EMBREE_BACKFACE_CULLING)
  287. valid &= max(U,V,W) <= eps;
  288. #else
  289. valid &= (min(U,V,W) >= -eps) | (max(U,V,W) <= eps);
  290. #endif
  291. if (unlikely(none(valid))) return false;
  292. /* calculate geometry normal and denominator */
  293. const Vec3vf<K> Ng = stable_triangle_normal(e0,e1,e2);
  294. const vfloat<K> den = twice(dot(Vec3vf<K>(Ng),D));
  295. /* perform depth test */
  296. const vfloat<K> T = twice(dot(v0,Vec3vf<K>(Ng)));
  297. const vfloat<K> t = rcp(den)*T;
  298. valid &= ray.tnear() <= t & t <= ray.tfar;
  299. valid &= den != vfloat<K>(zero);
  300. if (unlikely(none(valid))) return false;
  301. /* calculate hit information */
  302. QuadHitPlueckerK<K> hit(U,V,UVW,t,Ng,flags);
  303. return epilog(valid,hit);
  304. }
  305. /*! Intersects K rays with one of M quads. */
  306. template<typename Epilog>
  307. __forceinline bool intersectK(const vbool<K>& valid0,
  308. RayK<K>& ray,
  309. const Vec3vf<K>& v0,
  310. const Vec3vf<K>& v1,
  311. const Vec3vf<K>& v2,
  312. const Vec3vf<K>& v3,
  313. const Epilog& epilog) const
  314. {
  315. intersectK(valid0,ray,v0,v1,v3,vbool<K>(false),epilog);
  316. if (none(valid0)) return true;
  317. intersectK(valid0,ray,v2,v3,v1,vbool<K>(true ),epilog);
  318. return none(valid0);
  319. }
  320. };
  321. template<int M, int K, bool filter>
  322. struct QuadMIntersectorKPluecker : public QuadMIntersectorKPlueckerBase<M,K,filter>
  323. {
  324. __forceinline QuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
  325. : QuadMIntersectorKPlueckerBase<M,K,filter>(valid,ray) {}
  326. __forceinline void intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context,
  327. const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
  328. const vuint<M>& geomID, const vuint<M>& primID) const
  329. {
  330. Intersect1KEpilogM<M,K,filter> epilog(ray,k,context,geomID,primID);
  331. PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v0,v1,v3,vbool<M>(false),epilog);
  332. PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v2,v3,v1,vbool<M>(true ),epilog);
  333. }
  334. __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context,
  335. const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3,
  336. const vuint<M>& geomID, const vuint<M>& primID) const
  337. {
  338. Occluded1KEpilogM<M,K,filter> epilog(ray,k,context,geomID,primID);
  339. if (PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v0,v1,v3,vbool<M>(false),epilog)) return true;
  340. if (PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v2,v3,v1,vbool<M>(true ),epilog)) return true;
  341. return false;
  342. }
  343. };
  344. #if defined(__AVX__)
  345. /*! Intersects 4 quads with 1 ray using AVX */
  346. template<int K, bool filter>
  347. struct QuadMIntersectorKPluecker<4,K,filter> : public QuadMIntersectorKPlueckerBase<4,K,filter>
  348. {
  349. __forceinline QuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray)
  350. : QuadMIntersectorKPlueckerBase<4,K,filter>(valid,ray) {}
  351. template<typename Epilog>
  352. __forceinline bool intersect1(RayK<K>& ray, size_t k, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const Epilog& epilog) const
  353. {
  354. const Vec3vf8 vtx0(vfloat8(v0.x,v2.x),vfloat8(v0.y,v2.y),vfloat8(v0.z,v2.z));
  355. const vbool8 flags(0,0,0,0,1,1,1,1);
  356. #if !defined(EMBREE_BACKFACE_CULLING)
  357. const Vec3vf8 vtx1(vfloat8(v1.x),vfloat8(v1.y),vfloat8(v1.z));
  358. const Vec3vf8 vtx2(vfloat8(v3.x),vfloat8(v3.y),vfloat8(v3.z));
  359. #else
  360. const Vec3vf8 vtx1(vfloat8(v1.x,v3.x),vfloat8(v1.y,v3.y),vfloat8(v1.z,v3.z));
  361. const Vec3vf8 vtx2(vfloat8(v3.x,v1.x),vfloat8(v3.y,v1.y),vfloat8(v3.z,v1.z));
  362. #endif
  363. return PlueckerIntersector1KTriangleM::intersect1<8,K>(ray,k,vtx0,vtx1,vtx2,flags,epilog);
  364. }
  365. __forceinline bool intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context,
  366. const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
  367. const vuint4& geomID, const vuint4& primID) const
  368. {
  369. return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
  370. }
  371. __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context,
  372. const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3,
  373. const vuint4& geomID, const vuint4& primID) const
  374. {
  375. return intersect1(ray,k,v0,v1,v2,v3,Occluded1KEpilogM<8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID)));
  376. }
  377. };
  378. #endif
  379. }
  380. }