IntrOrientedBox3Frustum3.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/TIQuery.h>
  9. #include <Mathematics/Frustum3.h>
  10. #include <Mathematics/OrientedBox.h>
  11. // The test-intersection query uses the method of separating axes.
  12. // https://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
  13. // The potential separating axes include the 3 box face normals, the 5
  14. // distinct frustum normals (near and far plane have the same normal), and
  15. // cross products of normals, one from the box and one from the frustum.
  16. namespace WwiseGTE
  17. {
  18. template <typename Real>
  19. class TIQuery<Real, OrientedBox3<Real>, Frustum3<Real>>
  20. {
  21. public:
  22. struct Result
  23. {
  24. bool intersect;
  25. };
  26. Result operator()(OrientedBox3<Real> const& box, Frustum3<Real> const& frustum)
  27. {
  28. Result result;
  29. // Convenience variables.
  30. Vector3<Real> const* axis = &box.axis[0];
  31. Vector3<Real> const& extent = box.extent;
  32. Vector3<Real> diff = box.center - frustum.origin; // C-E
  33. Real A[3]; // Dot(R,A[i])
  34. Real B[3]; // Dot(U,A[i])
  35. Real C[3]; // Dot(D,A[i])
  36. Real D[3]; // (Dot(R,C-E),Dot(U,C-E),Dot(D,C-E))
  37. Real NA[3]; // dmin*Dot(R,A[i])
  38. Real NB[3]; // dmin*Dot(U,A[i])
  39. Real NC[3]; // dmin*Dot(D,A[i])
  40. Real ND[3]; // dmin*(Dot(R,C-E),Dot(U,C-E),?)
  41. Real RC[3]; // rmax*Dot(D,A[i])
  42. Real RD[3]; // rmax*(?,?,Dot(D,C-E))
  43. Real UC[3]; // umax*Dot(D,A[i])
  44. Real UD[3]; // umax*(?,?,Dot(D,C-E))
  45. Real NApRC[3]; // dmin*Dot(R,A[i]) + rmax*Dot(D,A[i])
  46. Real NAmRC[3]; // dmin*Dot(R,A[i]) - rmax*Dot(D,A[i])
  47. Real NBpUC[3]; // dmin*Dot(U,A[i]) + umax*Dot(D,A[i])
  48. Real NBmUC[3]; // dmin*Dot(U,A[i]) - umax*Dot(D,A[i])
  49. Real RBpUA[3]; // rmax*Dot(U,A[i]) + umax*Dot(R,A[i])
  50. Real RBmUA[3]; // rmax*Dot(U,A[i]) - umax*Dot(R,A[i])
  51. Real DdD, radius, p, fmin, fmax, MTwoUF, MTwoRF, tmp;
  52. int i, j;
  53. // M = D
  54. D[2] = Dot(diff, frustum.dVector);
  55. for (i = 0; i < 3; ++i)
  56. {
  57. C[i] = Dot(axis[i], frustum.dVector);
  58. }
  59. radius =
  60. extent[0] * std::fabs(C[0]) +
  61. extent[1] * std::fabs(C[1]) +
  62. extent[2] * std::fabs(C[2]);
  63. if (D[2] + radius < frustum.dMin
  64. || D[2] - radius > frustum.dMax)
  65. {
  66. result.intersect = false;
  67. return result;
  68. }
  69. // M = n*R - r*D
  70. for (i = 0; i < 3; ++i)
  71. {
  72. A[i] = Dot(axis[i], frustum.rVector);
  73. RC[i] = frustum.rBound * C[i];
  74. NA[i] = frustum.dMin * A[i];
  75. NAmRC[i] = NA[i] - RC[i];
  76. }
  77. D[0] = Dot(diff, frustum.rVector);
  78. radius =
  79. extent[0] * std::fabs(NAmRC[0]) +
  80. extent[1] * std::fabs(NAmRC[1]) +
  81. extent[2] * std::fabs(NAmRC[2]);
  82. ND[0] = frustum.dMin * D[0];
  83. RD[2] = frustum.rBound * D[2];
  84. DdD = ND[0] - RD[2];
  85. MTwoRF = frustum.GetMTwoRF();
  86. if (DdD + radius < MTwoRF || DdD > radius)
  87. {
  88. result.intersect = false;
  89. return result;
  90. }
  91. // M = -n*R - r*D
  92. for (i = 0; i < 3; ++i)
  93. {
  94. NApRC[i] = NA[i] + RC[i];
  95. }
  96. radius =
  97. extent[0] * std::fabs(NApRC[0]) +
  98. extent[1] * std::fabs(NApRC[1]) +
  99. extent[2] * std::fabs(NApRC[2]);
  100. DdD = -(ND[0] + RD[2]);
  101. if (DdD + radius < MTwoRF || DdD > radius)
  102. {
  103. result.intersect = false;
  104. return result;
  105. }
  106. // M = n*U - u*D
  107. for (i = 0; i < 3; ++i)
  108. {
  109. B[i] = Dot(axis[i], frustum.uVector);
  110. UC[i] = frustum.uBound * C[i];
  111. NB[i] = frustum.dMin * B[i];
  112. NBmUC[i] = NB[i] - UC[i];
  113. }
  114. D[1] = Dot(diff, frustum.uVector);
  115. radius =
  116. extent[0] * std::fabs(NBmUC[0]) +
  117. extent[1] * std::fabs(NBmUC[1]) +
  118. extent[2] * std::fabs(NBmUC[2]);
  119. ND[1] = frustum.dMin * D[1];
  120. UD[2] = frustum.uBound * D[2];
  121. DdD = ND[1] - UD[2];
  122. MTwoUF = frustum.GetMTwoUF();
  123. if (DdD + radius < MTwoUF || DdD > radius)
  124. {
  125. result.intersect = false;
  126. return result;
  127. }
  128. // M = -n*U - u*D
  129. for (i = 0; i < 3; ++i)
  130. {
  131. NBpUC[i] = NB[i] + UC[i];
  132. }
  133. radius =
  134. extent[0] * std::fabs(NBpUC[0]) +
  135. extent[1] * std::fabs(NBpUC[1]) +
  136. extent[2] * std::fabs(NBpUC[2]);
  137. DdD = -(ND[1] + UD[2]);
  138. if (DdD + radius < MTwoUF || DdD > radius)
  139. {
  140. result.intersect = false;
  141. return result;
  142. }
  143. // M = A[i]
  144. for (i = 0; i < 3; ++i)
  145. {
  146. p = frustum.rBound * std::fabs(A[i]) +
  147. frustum.uBound * std::fabs(B[i]);
  148. NC[i] = frustum.dMin * C[i];
  149. fmin = NC[i] - p;
  150. if (fmin < (Real)0)
  151. {
  152. fmin *= frustum.GetDRatio();
  153. }
  154. fmax = NC[i] + p;
  155. if (fmax > (Real)0)
  156. {
  157. fmax *= frustum.GetDRatio();
  158. }
  159. DdD = A[i] * D[0] + B[i] * D[1] + C[i] * D[2];
  160. if (DdD + extent[i] < fmin || DdD - extent[i] > fmax)
  161. {
  162. result.intersect = false;
  163. return result;
  164. }
  165. }
  166. // M = Cross(R,A[i])
  167. for (i = 0; i < 3; ++i)
  168. {
  169. p = frustum.uBound * std::fabs(C[i]);
  170. fmin = -NB[i] - p;
  171. if (fmin < (Real)0)
  172. {
  173. fmin *= frustum.GetDRatio();
  174. }
  175. fmax = -NB[i] + p;
  176. if (fmax > (Real)0)
  177. {
  178. fmax *= frustum.GetDRatio();
  179. }
  180. DdD = C[i] * D[1] - B[i] * D[2];
  181. radius =
  182. extent[0] * std::fabs(B[i] * C[0] - B[0] * C[i]) +
  183. extent[1] * std::fabs(B[i] * C[1] - B[1] * C[i]) +
  184. extent[2] * std::fabs(B[i] * C[2] - B[2] * C[i]);
  185. if (DdD + radius < fmin || DdD - radius > fmax)
  186. {
  187. result.intersect = false;
  188. return result;
  189. }
  190. }
  191. // M = Cross(U,A[i])
  192. for (i = 0; i < 3; ++i)
  193. {
  194. p = frustum.rBound * std::fabs(C[i]);
  195. fmin = NA[i] - p;
  196. if (fmin < (Real)0)
  197. {
  198. fmin *= frustum.GetDRatio();
  199. }
  200. fmax = NA[i] + p;
  201. if (fmax > (Real)0)
  202. {
  203. fmax *= frustum.GetDRatio();
  204. }
  205. DdD = -C[i] * D[0] + A[i] * D[2];
  206. radius =
  207. extent[0] * std::fabs(A[i] * C[0] - A[0] * C[i]) +
  208. extent[1] * std::fabs(A[i] * C[1] - A[1] * C[i]) +
  209. extent[2] * std::fabs(A[i] * C[2] - A[2] * C[i]);
  210. if (DdD + radius < fmin || DdD - radius > fmax)
  211. {
  212. result.intersect = false;
  213. return result;
  214. }
  215. }
  216. // M = Cross(n*D+r*R+u*U,A[i])
  217. for (i = 0; i < 3; ++i)
  218. {
  219. Real fRB = frustum.rBound * B[i];
  220. Real fUA = frustum.uBound * A[i];
  221. RBpUA[i] = fRB + fUA;
  222. RBmUA[i] = fRB - fUA;
  223. }
  224. for (i = 0; i < 3; ++i)
  225. {
  226. p = frustum.rBound * std::fabs(NBmUC[i]) +
  227. frustum.uBound * std::fabs(NAmRC[i]);
  228. tmp = -frustum.dMin * RBmUA[i];
  229. fmin = tmp - p;
  230. if (fmin < (Real)0)
  231. {
  232. fmin *= frustum.GetDRatio();
  233. }
  234. fmax = tmp + p;
  235. if (fmax > (Real)0)
  236. {
  237. fmax *= frustum.GetDRatio();
  238. }
  239. DdD = D[0] * NBmUC[i] - D[1] * NAmRC[i] - D[2] * RBmUA[i];
  240. radius = (Real)0;
  241. for (j = 0; j < 3; j++)
  242. {
  243. radius += extent[j] * std::fabs(A[j] * NBmUC[i] -
  244. B[j] * NAmRC[i] - C[j] * RBmUA[i]);
  245. }
  246. if (DdD + radius < fmin || DdD - radius > fmax)
  247. {
  248. result.intersect = false;
  249. return result;
  250. }
  251. }
  252. // M = Cross(n*D+r*R-u*U,A[i])
  253. for (i = 0; i < 3; ++i)
  254. {
  255. p = frustum.rBound * std::fabs(NBpUC[i]) +
  256. frustum.uBound * std::fabs(NAmRC[i]);
  257. tmp = -frustum.dMin * RBpUA[i];
  258. fmin = tmp - p;
  259. if (fmin < (Real)0)
  260. {
  261. fmin *= frustum.GetDRatio();
  262. }
  263. fmax = tmp + p;
  264. if (fmax > (Real)0)
  265. {
  266. fmax *= frustum.GetDRatio();
  267. }
  268. DdD = D[0] * NBpUC[i] - D[1] * NAmRC[i] - D[2] * RBpUA[i];
  269. radius = (Real)0;
  270. for (j = 0; j < 3; ++j)
  271. {
  272. radius += extent[j] * std::fabs(A[j] * NBpUC[i] -
  273. B[j] * NAmRC[i] - C[j] * RBpUA[i]);
  274. }
  275. if (DdD + radius < fmin || DdD - radius > fmax)
  276. {
  277. result.intersect = false;
  278. return result;
  279. }
  280. }
  281. // M = Cross(n*D-r*R+u*U,A[i])
  282. for (i = 0; i < 3; ++i)
  283. {
  284. p = frustum.rBound * std::fabs(NBmUC[i]) +
  285. frustum.uBound * std::fabs(NApRC[i]);
  286. tmp = frustum.dMin * RBpUA[i];
  287. fmin = tmp - p;
  288. if (fmin < (Real)0)
  289. {
  290. fmin *= frustum.GetDRatio();
  291. }
  292. fmax = tmp + p;
  293. if (fmax > (Real)0)
  294. {
  295. fmax *= frustum.GetDRatio();
  296. }
  297. DdD = D[0] * NBmUC[i] - D[1] * NApRC[i] + D[2] * RBpUA[i];
  298. radius = (Real)0;
  299. for (j = 0; j < 3; ++j)
  300. {
  301. radius += extent[j] * std::fabs(A[j] * NBmUC[i] -
  302. B[j] * NApRC[i] + C[j] * RBpUA[i]);
  303. }
  304. if (DdD + radius < fmin || DdD - radius > fmax)
  305. {
  306. result.intersect = false;
  307. return result;
  308. }
  309. }
  310. // M = Cross(n*D-r*R-u*U,A[i])
  311. for (i = 0; i < 3; ++i)
  312. {
  313. p = frustum.rBound * std::fabs(NBpUC[i]) +
  314. frustum.uBound * std::fabs(NApRC[i]);
  315. tmp = frustum.dMin * RBmUA[i];
  316. fmin = tmp - p;
  317. if (fmin < (Real)0)
  318. {
  319. fmin *= frustum.GetDRatio();
  320. }
  321. fmax = tmp + p;
  322. if (fmax > (Real)0)
  323. {
  324. fmax *= frustum.GetDRatio();
  325. }
  326. DdD = D[0] * NBpUC[i] - D[1] * NApRC[i] + D[2] * RBmUA[i];
  327. radius = (Real)0;
  328. for (j = 0; j < 3; ++j)
  329. {
  330. radius += extent[j] * std::fabs(A[j] * NBpUC[i] -
  331. B[j] * NApRC[i] + C[j] * RBmUA[i]);
  332. }
  333. if (DdD + radius < fmin || DdD - radius > fmax)
  334. {
  335. result.intersect = false;
  336. return result;
  337. }
  338. }
  339. result.intersect = true;
  340. return result;
  341. }
  342. };
  343. }