OPC_LSSAABBOverlap.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. // Following code from Magic-Software (http://www.magic-software.com/)
  2. // A bit modified for Opcode
  3. inline_ float OPC_PointAABBSqrDist(const Point& point, const Point& center, const Point& extents)
  4. {
  5. // Compute coordinates of point in box coordinate system
  6. Point Closest = point - center;
  7. float SqrDistance = 0.0f;
  8. if(Closest.x < -extents.x)
  9. {
  10. float Delta = Closest.x + extents.x;
  11. SqrDistance += Delta*Delta;
  12. }
  13. else if(Closest.x > extents.x)
  14. {
  15. float Delta = Closest.x - extents.x;
  16. SqrDistance += Delta*Delta;
  17. }
  18. if(Closest.y < -extents.y)
  19. {
  20. float Delta = Closest.y + extents.y;
  21. SqrDistance += Delta*Delta;
  22. }
  23. else if(Closest.y > extents.y)
  24. {
  25. float Delta = Closest.y - extents.y;
  26. SqrDistance += Delta*Delta;
  27. }
  28. if(Closest.z < -extents.z)
  29. {
  30. float Delta = Closest.z + extents.z;
  31. SqrDistance += Delta*Delta;
  32. }
  33. else if(Closest.z > extents.z)
  34. {
  35. float Delta = Closest.z - extents.z;
  36. SqrDistance += Delta*Delta;
  37. }
  38. return SqrDistance;
  39. }
  40. static void Face(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, const Point& rkPmE, float* pfLParam, float& rfSqrDistance)
  41. {
  42. Point kPpE;
  43. float fLSqr, fInv, fTmp, fParam, fT, fDelta;
  44. kPpE[i1] = rkPnt[i1] + extents[i1];
  45. kPpE[i2] = rkPnt[i2] + extents[i2];
  46. if(rkDir[i0]*kPpE[i1] >= rkDir[i1]*rkPmE[i0])
  47. {
  48. if(rkDir[i0]*kPpE[i2] >= rkDir[i2]*rkPmE[i0])
  49. {
  50. // v[i1] >= -e[i1], v[i2] >= -e[i2] (distance = 0)
  51. if(pfLParam)
  52. {
  53. rkPnt[i0] = extents[i0];
  54. fInv = 1.0f/rkDir[i0];
  55. rkPnt[i1] -= rkDir[i1]*rkPmE[i0]*fInv;
  56. rkPnt[i2] -= rkDir[i2]*rkPmE[i0]*fInv;
  57. *pfLParam = -rkPmE[i0]*fInv;
  58. }
  59. }
  60. else
  61. {
  62. // v[i1] >= -e[i1], v[i2] < -e[i2]
  63. fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i2]*rkDir[i2];
  64. fTmp = fLSqr*kPpE[i1] - rkDir[i1]*(rkDir[i0]*rkPmE[i0] + rkDir[i2]*kPpE[i2]);
  65. if(fTmp <= 2.0f*fLSqr*extents[i1])
  66. {
  67. fT = fTmp/fLSqr;
  68. fLSqr += rkDir[i1]*rkDir[i1];
  69. fTmp = kPpE[i1] - fT;
  70. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*fTmp + rkDir[i2]*kPpE[i2];
  71. fParam = -fDelta/fLSqr;
  72. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + fTmp*fTmp + kPpE[i2]*kPpE[i2] + fDelta*fParam;
  73. if(pfLParam)
  74. {
  75. *pfLParam = fParam;
  76. rkPnt[i0] = extents[i0];
  77. rkPnt[i1] = fT - extents[i1];
  78. rkPnt[i2] = -extents[i2];
  79. }
  80. }
  81. else
  82. {
  83. fLSqr += rkDir[i1]*rkDir[i1];
  84. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*rkPmE[i1] + rkDir[i2]*kPpE[i2];
  85. fParam = -fDelta/fLSqr;
  86. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + rkPmE[i1]*rkPmE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam;
  87. if(pfLParam)
  88. {
  89. *pfLParam = fParam;
  90. rkPnt[i0] = extents[i0];
  91. rkPnt[i1] = extents[i1];
  92. rkPnt[i2] = -extents[i2];
  93. }
  94. }
  95. }
  96. }
  97. else
  98. {
  99. if ( rkDir[i0]*kPpE[i2] >= rkDir[i2]*rkPmE[i0] )
  100. {
  101. // v[i1] < -e[i1], v[i2] >= -e[i2]
  102. fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1];
  103. fTmp = fLSqr*kPpE[i2] - rkDir[i2]*(rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1]);
  104. if(fTmp <= 2.0f*fLSqr*extents[i2])
  105. {
  106. fT = fTmp/fLSqr;
  107. fLSqr += rkDir[i2]*rkDir[i2];
  108. fTmp = kPpE[i2] - fT;
  109. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*fTmp;
  110. fParam = -fDelta/fLSqr;
  111. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + fTmp*fTmp + fDelta*fParam;
  112. if(pfLParam)
  113. {
  114. *pfLParam = fParam;
  115. rkPnt[i0] = extents[i0];
  116. rkPnt[i1] = -extents[i1];
  117. rkPnt[i2] = fT - extents[i2];
  118. }
  119. }
  120. else
  121. {
  122. fLSqr += rkDir[i2]*rkDir[i2];
  123. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*rkPmE[i2];
  124. fParam = -fDelta/fLSqr;
  125. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + rkPmE[i2]*rkPmE[i2] + fDelta*fParam;
  126. if(pfLParam)
  127. {
  128. *pfLParam = fParam;
  129. rkPnt[i0] = extents[i0];
  130. rkPnt[i1] = -extents[i1];
  131. rkPnt[i2] = extents[i2];
  132. }
  133. }
  134. }
  135. else
  136. {
  137. // v[i1] < -e[i1], v[i2] < -e[i2]
  138. fLSqr = rkDir[i0]*rkDir[i0]+rkDir[i2]*rkDir[i2];
  139. fTmp = fLSqr*kPpE[i1] - rkDir[i1]*(rkDir[i0]*rkPmE[i0] + rkDir[i2]*kPpE[i2]);
  140. if(fTmp >= 0.0f)
  141. {
  142. // v[i1]-edge is closest
  143. if ( fTmp <= 2.0f*fLSqr*extents[i1] )
  144. {
  145. fT = fTmp/fLSqr;
  146. fLSqr += rkDir[i1]*rkDir[i1];
  147. fTmp = kPpE[i1] - fT;
  148. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*fTmp + rkDir[i2]*kPpE[i2];
  149. fParam = -fDelta/fLSqr;
  150. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + fTmp*fTmp + kPpE[i2]*kPpE[i2] + fDelta*fParam;
  151. if(pfLParam)
  152. {
  153. *pfLParam = fParam;
  154. rkPnt[i0] = extents[i0];
  155. rkPnt[i1] = fT - extents[i1];
  156. rkPnt[i2] = -extents[i2];
  157. }
  158. }
  159. else
  160. {
  161. fLSqr += rkDir[i1]*rkDir[i1];
  162. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*rkPmE[i1] + rkDir[i2]*kPpE[i2];
  163. fParam = -fDelta/fLSqr;
  164. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + rkPmE[i1]*rkPmE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam;
  165. if(pfLParam)
  166. {
  167. *pfLParam = fParam;
  168. rkPnt[i0] = extents[i0];
  169. rkPnt[i1] = extents[i1];
  170. rkPnt[i2] = -extents[i2];
  171. }
  172. }
  173. return;
  174. }
  175. fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1];
  176. fTmp = fLSqr*kPpE[i2] - rkDir[i2]*(rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1]);
  177. if(fTmp >= 0.0f)
  178. {
  179. // v[i2]-edge is closest
  180. if(fTmp <= 2.0f*fLSqr*extents[i2])
  181. {
  182. fT = fTmp/fLSqr;
  183. fLSqr += rkDir[i2]*rkDir[i2];
  184. fTmp = kPpE[i2] - fT;
  185. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*fTmp;
  186. fParam = -fDelta/fLSqr;
  187. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + fTmp*fTmp + fDelta*fParam;
  188. if(pfLParam)
  189. {
  190. *pfLParam = fParam;
  191. rkPnt[i0] = extents[i0];
  192. rkPnt[i1] = -extents[i1];
  193. rkPnt[i2] = fT - extents[i2];
  194. }
  195. }
  196. else
  197. {
  198. fLSqr += rkDir[i2]*rkDir[i2];
  199. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*rkPmE[i2];
  200. fParam = -fDelta/fLSqr;
  201. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + rkPmE[i2]*rkPmE[i2] + fDelta*fParam;
  202. if(pfLParam)
  203. {
  204. *pfLParam = fParam;
  205. rkPnt[i0] = extents[i0];
  206. rkPnt[i1] = -extents[i1];
  207. rkPnt[i2] = extents[i2];
  208. }
  209. }
  210. return;
  211. }
  212. // (v[i1],v[i2])-corner is closest
  213. fLSqr += rkDir[i2]*rkDir[i2];
  214. fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*kPpE[i2];
  215. fParam = -fDelta/fLSqr;
  216. rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam;
  217. if(pfLParam)
  218. {
  219. *pfLParam = fParam;
  220. rkPnt[i0] = extents[i0];
  221. rkPnt[i1] = -extents[i1];
  222. rkPnt[i2] = -extents[i2];
  223. }
  224. }
  225. }
  226. }
  227. static void CaseNoZeros(Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance)
  228. {
  229. Point kPmE(rkPnt.x - extents.x, rkPnt.y - extents.y, rkPnt.z - extents.z);
  230. float fProdDxPy, fProdDyPx, fProdDzPx, fProdDxPz, fProdDzPy, fProdDyPz;
  231. fProdDxPy = rkDir.x*kPmE.y;
  232. fProdDyPx = rkDir.y*kPmE.x;
  233. if(fProdDyPx >= fProdDxPy)
  234. {
  235. fProdDzPx = rkDir.z*kPmE.x;
  236. fProdDxPz = rkDir.x*kPmE.z;
  237. if(fProdDzPx >= fProdDxPz)
  238. {
  239. // line intersects x = e0
  240. Face(0, 1, 2, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance);
  241. }
  242. else
  243. {
  244. // line intersects z = e2
  245. Face(2, 0, 1, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance);
  246. }
  247. }
  248. else
  249. {
  250. fProdDzPy = rkDir.z*kPmE.y;
  251. fProdDyPz = rkDir.y*kPmE.z;
  252. if(fProdDzPy >= fProdDyPz)
  253. {
  254. // line intersects y = e1
  255. Face(1, 2, 0, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance);
  256. }
  257. else
  258. {
  259. // line intersects z = e2
  260. Face(2, 0, 1, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance);
  261. }
  262. }
  263. }
  264. static void Case0(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance)
  265. {
  266. float fPmE0 = rkPnt[i0] - extents[i0];
  267. float fPmE1 = rkPnt[i1] - extents[i1];
  268. float fProd0 = rkDir[i1]*fPmE0;
  269. float fProd1 = rkDir[i0]*fPmE1;
  270. float fDelta, fInvLSqr, fInv;
  271. if(fProd0 >= fProd1)
  272. {
  273. // line intersects P[i0] = e[i0]
  274. rkPnt[i0] = extents[i0];
  275. float fPpE1 = rkPnt[i1] + extents[i1];
  276. fDelta = fProd0 - rkDir[i0]*fPpE1;
  277. if(fDelta >= 0.0f)
  278. {
  279. fInvLSqr = 1.0f/(rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]);
  280. rfSqrDistance += fDelta*fDelta*fInvLSqr;
  281. if(pfLParam)
  282. {
  283. rkPnt[i1] = -extents[i1];
  284. *pfLParam = -(rkDir[i0]*fPmE0+rkDir[i1]*fPpE1)*fInvLSqr;
  285. }
  286. }
  287. else
  288. {
  289. if(pfLParam)
  290. {
  291. fInv = 1.0f/rkDir[i0];
  292. rkPnt[i1] -= fProd0*fInv;
  293. *pfLParam = -fPmE0*fInv;
  294. }
  295. }
  296. }
  297. else
  298. {
  299. // line intersects P[i1] = e[i1]
  300. rkPnt[i1] = extents[i1];
  301. float fPpE0 = rkPnt[i0] + extents[i0];
  302. fDelta = fProd1 - rkDir[i1]*fPpE0;
  303. if(fDelta >= 0.0f)
  304. {
  305. fInvLSqr = 1.0f/(rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]);
  306. rfSqrDistance += fDelta*fDelta*fInvLSqr;
  307. if(pfLParam)
  308. {
  309. rkPnt[i0] = -extents[i0];
  310. *pfLParam = -(rkDir[i0]*fPpE0+rkDir[i1]*fPmE1)*fInvLSqr;
  311. }
  312. }
  313. else
  314. {
  315. if(pfLParam)
  316. {
  317. fInv = 1.0f/rkDir[i1];
  318. rkPnt[i0] -= fProd1*fInv;
  319. *pfLParam = -fPmE1*fInv;
  320. }
  321. }
  322. }
  323. if(rkPnt[i2] < -extents[i2])
  324. {
  325. fDelta = rkPnt[i2] + extents[i2];
  326. rfSqrDistance += fDelta*fDelta;
  327. rkPnt[i2] = -extents[i2];
  328. }
  329. else if ( rkPnt[i2] > extents[i2] )
  330. {
  331. fDelta = rkPnt[i2] - extents[i2];
  332. rfSqrDistance += fDelta*fDelta;
  333. rkPnt[i2] = extents[i2];
  334. }
  335. }
  336. static void Case00(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance)
  337. {
  338. float fDelta;
  339. if(pfLParam)
  340. *pfLParam = (extents[i0] - rkPnt[i0])/rkDir[i0];
  341. rkPnt[i0] = extents[i0];
  342. if(rkPnt[i1] < -extents[i1])
  343. {
  344. fDelta = rkPnt[i1] + extents[i1];
  345. rfSqrDistance += fDelta*fDelta;
  346. rkPnt[i1] = -extents[i1];
  347. }
  348. else if(rkPnt[i1] > extents[i1])
  349. {
  350. fDelta = rkPnt[i1] - extents[i1];
  351. rfSqrDistance += fDelta*fDelta;
  352. rkPnt[i1] = extents[i1];
  353. }
  354. if(rkPnt[i2] < -extents[i2])
  355. {
  356. fDelta = rkPnt[i2] + extents[i2];
  357. rfSqrDistance += fDelta*fDelta;
  358. rkPnt[i1] = -extents[i2];
  359. }
  360. else if(rkPnt[i2] > extents[i2])
  361. {
  362. fDelta = rkPnt[i2] - extents[i2];
  363. rfSqrDistance += fDelta*fDelta;
  364. rkPnt[i2] = extents[i2];
  365. }
  366. }
  367. static void Case000(Point& rkPnt, const Point& extents, float& rfSqrDistance)
  368. {
  369. float fDelta;
  370. if(rkPnt.x < -extents.x)
  371. {
  372. fDelta = rkPnt.x + extents.x;
  373. rfSqrDistance += fDelta*fDelta;
  374. rkPnt.x = -extents.x;
  375. }
  376. else if(rkPnt.x > extents.x)
  377. {
  378. fDelta = rkPnt.x - extents.x;
  379. rfSqrDistance += fDelta*fDelta;
  380. rkPnt.x = extents.x;
  381. }
  382. if(rkPnt.y < -extents.y)
  383. {
  384. fDelta = rkPnt.y + extents.y;
  385. rfSqrDistance += fDelta*fDelta;
  386. rkPnt.y = -extents.y;
  387. }
  388. else if(rkPnt.y > extents.y)
  389. {
  390. fDelta = rkPnt.y - extents.y;
  391. rfSqrDistance += fDelta*fDelta;
  392. rkPnt.y = extents.y;
  393. }
  394. if(rkPnt.z < -extents.z)
  395. {
  396. fDelta = rkPnt.z + extents.z;
  397. rfSqrDistance += fDelta*fDelta;
  398. rkPnt.z = -extents.z;
  399. }
  400. else if(rkPnt.z > extents.z)
  401. {
  402. fDelta = rkPnt.z - extents.z;
  403. rfSqrDistance += fDelta*fDelta;
  404. rkPnt.z = extents.z;
  405. }
  406. }
  407. static float SqrDistance(const Ray& rkLine, const Point& center, const Point& extents, float* pfLParam)
  408. {
  409. // compute coordinates of line in box coordinate system
  410. Point kDiff = rkLine.mOrig - center;
  411. Point kPnt = kDiff;
  412. Point kDir = rkLine.mDir;
  413. // Apply reflections so that direction vector has nonnegative components.
  414. bool bReflect[3];
  415. for(int i=0;i<3;i++)
  416. {
  417. if(kDir[i]<0.0f)
  418. {
  419. kPnt[i] = -kPnt[i];
  420. kDir[i] = -kDir[i];
  421. bReflect[i] = true;
  422. }
  423. else
  424. {
  425. bReflect[i] = false;
  426. }
  427. }
  428. float fSqrDistance = 0.0f;
  429. if(kDir.x>0.0f)
  430. {
  431. if(kDir.y>0.0f)
  432. {
  433. if(kDir.z>0.0f) CaseNoZeros(kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,+,+)
  434. else Case0(0, 1, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,+,0)
  435. }
  436. else
  437. {
  438. if(kDir.z>0.0f) Case0(0, 2, 1, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,0,+)
  439. else Case00(0, 1, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,0,0)
  440. }
  441. }
  442. else
  443. {
  444. if(kDir.y>0.0f)
  445. {
  446. if(kDir.z>0.0f) Case0(1, 2, 0, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,+,+)
  447. else Case00(1, 0, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,+,0)
  448. }
  449. else
  450. {
  451. if(kDir.z>0.0f) Case00(2, 0, 1, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,0,+)
  452. else
  453. {
  454. Case000(kPnt, extents, fSqrDistance); // (0,0,0)
  455. if(pfLParam) *pfLParam = 0.0f;
  456. }
  457. }
  458. }
  459. return fSqrDistance;
  460. }
  461. inline_ float OPC_SegmentOBBSqrDist(const Segment& segment, const Point& c0, const Point& e0)
  462. {
  463. float fLP;
  464. float fSqrDistance = SqrDistance(Ray(segment.GetOrigin(), segment.ComputeDirection()), c0, e0, &fLP);
  465. if(fLP>=0.0f)
  466. {
  467. if(fLP<=1.0f) return fSqrDistance;
  468. else return OPC_PointAABBSqrDist(segment.mP1, c0, e0);
  469. }
  470. else return OPC_PointAABBSqrDist(segment.mP0, c0, e0);
  471. }
  472. inline_ BOOL LSSCollider::LSSAABBOverlap(const Point& center, const Point& extents)
  473. {
  474. // Stats
  475. mNbVolumeBVTests++;
  476. float s2 = OPC_SegmentOBBSqrDist(mSeg, center, extents);
  477. if(s2<mRadius2) return TRUE;
  478. return FALSE;
  479. }