cone.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include "../common/ray.h"
  5. namespace embree
  6. {
  7. namespace isa
  8. {
  9. struct Cone
  10. {
  11. const Vec3fa p0; //!< start position of cone
  12. const Vec3fa p1; //!< end position of cone
  13. const float r0; //!< start radius of cone
  14. const float r1; //!< end radius of cone
  15. __forceinline Cone(const Vec3fa& p0, const float r0, const Vec3fa& p1, const float r1)
  16. : p0(p0), p1(p1), r0(r0), r1(r1) {}
  17. __forceinline bool intersect(const Vec3fa& org, const Vec3fa& dir,
  18. BBox1f& t_o,
  19. float& u0_o, Vec3fa& Ng0_o,
  20. float& u1_o, Vec3fa& Ng1_o) const
  21. {
  22. /* calculate quadratic equation to solve */
  23. const Vec3fa v0 = p0-org;
  24. const Vec3fa v1 = p1-org;
  25. const float rl = rcp_length(v1-v0);
  26. const Vec3fa P0 = v0, dP = (v1-v0)*rl;
  27. const float dr = (r1-r0)*rl;
  28. const Vec3fa O = -P0, dO = dir;
  29. const float dOdO = dot(dO,dO);
  30. const float OdO = dot(dO,O);
  31. const float OO = dot(O,O);
  32. const float dOz = dot(dP,dO);
  33. const float Oz = dot(dP,O);
  34. const float R = r0 + Oz*dr;
  35. const float A = dOdO - sqr(dOz) * (1.0f+sqr(dr));
  36. const float B = 2.0f * (OdO - dOz*(Oz + R*dr));
  37. const float C = OO - (sqr(Oz) + sqr(R));
  38. /* we miss the cone if determinant is smaller than zero */
  39. const float D = B*B - 4.0f*A*C;
  40. if (D < 0.0f) return false;
  41. /* special case for rays that are "parallel" to the cone */
  42. const float eps = float(1<<8)*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
  43. if (unlikely(abs(A) < eps))
  44. {
  45. /* cylinder case */
  46. if (abs(dr) < 16.0f*float(ulp)) {
  47. if (C <= 0.0f) { t_o = BBox1f(neg_inf,pos_inf); return true; }
  48. else { t_o = BBox1f(pos_inf,neg_inf); return false; }
  49. }
  50. /* cone case */
  51. else
  52. {
  53. /* if we hit the negative cone there cannot be a hit */
  54. const float t = -C/B;
  55. const float z0 = Oz+t*dOz;
  56. const float z0r = r0+z0*dr;
  57. if (z0r < 0.0f) return false;
  58. /* test if we start inside or outside the cone */
  59. if (dOz*dr > 0.0f) t_o = BBox1f(t,pos_inf);
  60. else t_o = BBox1f(neg_inf,t);
  61. }
  62. }
  63. /* standard case for "non-parallel" rays */
  64. else
  65. {
  66. const float Q = sqrt(D);
  67. const float rcp_2A = rcp(2.0f*A);
  68. t_o.lower = (-B-Q)*rcp_2A;
  69. t_o.upper = (-B+Q)*rcp_2A;
  70. /* standard case where both hits are on same cone */
  71. if (likely(A > 0.0f)) {
  72. const float z0 = Oz+t_o.lower*dOz;
  73. const float z0r = r0+z0*dr;
  74. if (z0r < 0.0f) return false;
  75. }
  76. /* special case where the hits are on the positive and negative cone */
  77. else
  78. {
  79. /* depending on the ray direction and the open direction
  80. * of the cone we have a hit from inside or outside the
  81. * cone */
  82. if (dOz*dr > 0) t_o.upper = pos_inf;
  83. else t_o.lower = neg_inf;
  84. }
  85. }
  86. /* calculates u and Ng for near hit */
  87. {
  88. u0_o = (Oz+t_o.lower*dOz)*rl;
  89. const Vec3fa Pr = t_o.lower*dir;
  90. const Vec3fa Pl = v0 + u0_o*(v1-v0);
  91. const Vec3fa R = normalize(Pr-Pl);
  92. const Vec3fa U = (p1-p0)+(r1-r0)*R;
  93. const Vec3fa V = cross(p1-p0,R);
  94. Ng0_o = cross(V,U);
  95. }
  96. /* calculates u and Ng for far hit */
  97. {
  98. u1_o = (Oz+t_o.upper*dOz)*rl;
  99. const Vec3fa Pr = t_o.upper*dir;
  100. const Vec3fa Pl = v0 + u1_o*(v1-v0);
  101. const Vec3fa R = normalize(Pr-Pl);
  102. const Vec3fa U = (p1-p0)+(r1-r0)*R;
  103. const Vec3fa V = cross(p1-p0,R);
  104. Ng1_o = cross(V,U);
  105. }
  106. return true;
  107. }
  108. __forceinline bool intersect(const Vec3fa& org, const Vec3fa& dir, BBox1f& t_o) const
  109. {
  110. float u0_o; Vec3fa Ng0_o; float u1_o; Vec3fa Ng1_o;
  111. return intersect(org,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
  112. }
  113. static bool verify(const size_t id, const Cone& cone, const Ray& ray, bool shouldhit, const float t0, const float t1)
  114. {
  115. float eps = 0.001f;
  116. BBox1f t; bool hit;
  117. hit = cone.intersect(ray.org,ray.dir,t);
  118. bool failed = hit != shouldhit;
  119. if (shouldhit) failed |= std::isinf(t0) ? t0 != t.lower : (t0 == -1E6) ? t.lower > -1E6f : abs(t0-t.lower) > eps;
  120. if (shouldhit) failed |= std::isinf(t1) ? t1 != t.upper : (t1 == +1E6) ? t.upper < +1E6f : abs(t1-t.upper) > eps;
  121. if (!failed) return true;
  122. embree_cout << "Cone test " << id << " failed: cone = " << cone << ", ray = " << ray << ", hit = " << hit << ", t = " << t << embree_endl;
  123. return false;
  124. }
  125. /* verify cone class */
  126. static bool verify()
  127. {
  128. bool passed = true;
  129. const Cone cone0(Vec3fa(0.0f,0.0f,0.0f),0.0f,Vec3fa(1.0f,0.0f,0.0f),1.0f);
  130. passed &= verify(0,cone0,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,3.0f,pos_inf);
  131. passed &= verify(1,cone0,Ray(Vec3fa(+2.0f,1.0f,0.0f),Vec3fa(-1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,1.0f);
  132. passed &= verify(2,cone0,Ray(Vec3fa(-1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),false,0.0f,0.0f);
  133. passed &= verify(3,cone0,Ray(Vec3fa(+1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,1.0f,3.0f);
  134. passed &= verify(4,cone0,Ray(Vec3fa(-1.0f,0.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,1.0f,pos_inf);
  135. passed &= verify(5,cone0,Ray(Vec3fa(+1.0f,0.0f,0.0f),Vec3fa(-1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,1.0f);
  136. passed &= verify(6,cone0,Ray(Vec3fa(+0.0f,0.0f,1.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,1.0f,1.0f);
  137. passed &= verify(7,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(-1.0f,-1.0f,+0.0f),0.0f,float(inf)),false,0.0f,0.0f);
  138. passed &= verify(8,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(+1.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.5f,+1E6);
  139. passed &= verify(9,cone0,Ray(Vec3fa(+0.0f,1.0f,0.0f),Vec3fa(-1.0f,+1.0f,+0.0f),0.0f,float(inf)),true,-1E6,-0.5f);
  140. const Cone cone1(Vec3fa(0.0f,0.0f,0.0f),1.0f,Vec3fa(1.0f,0.0f,0.0f),0.0f);
  141. passed &= verify(10,cone1,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa(+1.0f,+0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,2.0f);
  142. passed &= verify(11,cone1,Ray(Vec3fa(-1.0f,0.0f,2.0f),Vec3fa(+0.0f,+0.0f,-1.0f),0.0f,float(inf)),true,0.0f,4.0f);
  143. const Cone cylinder(Vec3fa(0.0f,0.0f,0.0f),1.0f,Vec3fa(1.0f,0.0f,0.0f),1.0f);
  144. passed &= verify(12,cylinder,Ray(Vec3fa(-2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
  145. passed &= verify(13,cylinder,Ray(Vec3fa(+2.0f,1.0f,0.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),true,0.0f,2.0f);
  146. passed &= verify(14,cylinder,Ray(Vec3fa(+2.0f,1.0f,2.0f),Vec3fa( 0.0f,-1.0f,+0.0f),0.0f,float(inf)),false,0.0f,0.0f);
  147. passed &= verify(15,cylinder,Ray(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
  148. passed &= verify(16,cylinder,Ray(Vec3fa(+0.0f,0.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),true,neg_inf,pos_inf);
  149. passed &= verify(17,cylinder,Ray(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa( 1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
  150. passed &= verify(18,cylinder,Ray(Vec3fa(+0.0f,2.0f,0.0f),Vec3fa(-1.0f, 0.0f,+0.0f),0.0f,float(inf)),false,pos_inf,neg_inf);
  151. return passed;
  152. }
  153. /*! output operator */
  154. friend __forceinline embree_ostream operator<<(embree_ostream cout, const Cone& c) {
  155. return cout << "Cone { p0 = " << c.p0 << ", r0 = " << c.r0 << ", p1 = " << c.p1 << ", r1 = " << c.r1 << "}";
  156. }
  157. };
  158. template<int N>
  159. struct ConeN
  160. {
  161. typedef Vec3<vfloat<N>> Vec3vfN;
  162. const Vec3vfN p0; //!< start position of cone
  163. const Vec3vfN p1; //!< end position of cone
  164. const vfloat<N> r0; //!< start radius of cone
  165. const vfloat<N> r1; //!< end radius of cone
  166. __forceinline ConeN(const Vec3vfN& p0, const vfloat<N>& r0, const Vec3vfN& p1, const vfloat<N>& r1)
  167. : p0(p0), p1(p1), r0(r0), r1(r1) {}
  168. __forceinline Cone operator[] (const size_t i) const
  169. {
  170. assert(i<N);
  171. return Cone(Vec3fa(p0.x[i],p0.y[i],p0.z[i]),r0[i],Vec3fa(p1.x[i],p1.y[i],p1.z[i]),r1[i]);
  172. }
  173. __forceinline vbool<N> intersect(const Vec3fa& org, const Vec3fa& dir,
  174. BBox<vfloat<N>>& t_o,
  175. vfloat<N>& u0_o, Vec3vfN& Ng0_o,
  176. vfloat<N>& u1_o, Vec3vfN& Ng1_o) const
  177. {
  178. /* calculate quadratic equation to solve */
  179. const Vec3vfN v0 = p0-Vec3vfN(org);
  180. const Vec3vfN v1 = p1-Vec3vfN(org);
  181. const vfloat<N> rl = rcp_length(v1-v0);
  182. const Vec3vfN P0 = v0, dP = (v1-v0)*rl;
  183. const vfloat<N> dr = (r1-r0)*rl;
  184. const Vec3vfN O = -P0, dO = dir;
  185. const vfloat<N> dOdO = dot(dO,dO);
  186. const vfloat<N> OdO = dot(dO,O);
  187. const vfloat<N> OO = dot(O,O);
  188. const vfloat<N> dOz = dot(dP,dO);
  189. const vfloat<N> Oz = dot(dP,O);
  190. const vfloat<N> R = r0 + Oz*dr;
  191. const vfloat<N> A = dOdO - sqr(dOz) * (vfloat<N>(1.0f)+sqr(dr));
  192. const vfloat<N> B = 2.0f * (OdO - dOz*(Oz + R*dr));
  193. const vfloat<N> C = OO - (sqr(Oz) + sqr(R));
  194. /* we miss the cone if determinant is smaller than zero */
  195. const vfloat<N> D = B*B - 4.0f*A*C;
  196. vbool<N> valid = D >= 0.0f;
  197. if (none(valid)) return valid;
  198. /* special case for rays that are "parallel" to the cone */
  199. const vfloat<N> eps = float(1<<8)*float(ulp)*max(abs(dOdO),abs(sqr(dOz)));
  200. const vbool<N> validt = valid & (abs(A) < eps);
  201. const vbool<N> validf = valid & !(abs(A) < eps);
  202. if (unlikely(any(validt)))
  203. {
  204. const vboolx validtt = validt & (abs(dr) < 16.0f*float(ulp));
  205. const vboolx validtf = validt & (abs(dr) >= 16.0f*float(ulp));
  206. /* cylinder case */
  207. if (unlikely(any(validtt)))
  208. {
  209. t_o.lower = select(validtt, select(C <= 0.0f, vfloat<N>(neg_inf), vfloat<N>(pos_inf)), t_o.lower);
  210. t_o.upper = select(validtt, select(C <= 0.0f, vfloat<N>(pos_inf), vfloat<N>(neg_inf)), t_o.upper);
  211. valid &= !validtt | C <= 0.0f;
  212. }
  213. /* cone case */
  214. if (any(validtf))
  215. {
  216. /* if we hit the negative cone there cannot be a hit */
  217. const vfloat<N> t = -C/B;
  218. const vfloat<N> z0 = Oz+t*dOz;
  219. const vfloat<N> z0r = r0+z0*dr;
  220. valid &= !validtf | z0r >= 0.0f;
  221. /* test if we start inside or outside the cone */
  222. t_o.lower = select(validtf, select(dOz*dr > 0.0f, t, vfloat<N>(neg_inf)), t_o.lower);
  223. t_o.upper = select(validtf, select(dOz*dr > 0.0f, vfloat<N>(pos_inf), t), t_o.upper);
  224. }
  225. }
  226. /* standard case for "non-parallel" rays */
  227. if (likely(any(validf)))
  228. {
  229. const vfloat<N> Q = sqrt(D);
  230. const vfloat<N> rcp_2A = 0.5f*rcp(A);
  231. t_o.lower = select(validf, (-B-Q)*rcp_2A, t_o.lower);
  232. t_o.upper = select(validf, (-B+Q)*rcp_2A, t_o.upper);
  233. /* standard case where both hits are on same cone */
  234. const vbool<N> validft = validf & A>0.0f;
  235. const vbool<N> validff = validf & !(A>0.0f);
  236. if (any(validft)) {
  237. const vfloat<N> z0 = Oz+t_o.lower*dOz;
  238. const vfloat<N> z0r = r0+z0*dr;
  239. valid &= !validft | z0r >= 0.0f;
  240. }
  241. /* special case where the hits are on the positive and negative cone */
  242. if (any(validff)) {
  243. /* depending on the ray direction and the open direction
  244. * of the cone we have a hit from inside or outside the
  245. * cone */
  246. t_o.lower = select(validff, select(dOz*dr > 0.0f, t_o.lower, float(neg_inf)), t_o.lower);
  247. t_o.upper = select(validff, select(dOz*dr > 0.0f, float(pos_inf), t_o.upper), t_o.upper);
  248. }
  249. }
  250. /* calculates u and Ng for near hit */
  251. {
  252. u0_o = (Oz+t_o.lower*dOz)*rl;
  253. const Vec3vfN Pr = t_o.lower*Vec3vfN(dir);
  254. const Vec3vfN Pl = v0 + u0_o*(v1-v0);
  255. const Vec3vfN R = normalize(Pr-Pl);
  256. const Vec3vfN U = (p1-p0)+(r1-r0)*R;
  257. const Vec3vfN V = cross(p1-p0,R);
  258. Ng0_o = cross(V,U);
  259. }
  260. /* calculates u and Ng for far hit */
  261. {
  262. u1_o = (Oz+t_o.upper*dOz)*rl;
  263. const Vec3vfN Pr = t_o.lower*Vec3vfN(dir);
  264. const Vec3vfN Pl = v0 + u1_o*(v1-v0);
  265. const Vec3vfN R = normalize(Pr-Pl);
  266. const Vec3vfN U = (p1-p0)+(r1-r0)*R;
  267. const Vec3vfN V = cross(p1-p0,R);
  268. Ng1_o = cross(V,U);
  269. }
  270. return valid;
  271. }
  272. __forceinline vbool<N> intersect(const Vec3fa& org, const Vec3fa& dir, BBox<vfloat<N>>& t_o) const
  273. {
  274. vfloat<N> u0_o; Vec3vfN Ng0_o; vfloat<N> u1_o; Vec3vfN Ng1_o;
  275. return intersect(org,dir,t_o,u0_o,Ng0_o,u1_o,Ng1_o);
  276. }
  277. };
  278. }
  279. }