colmathobbobb.cpp 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWMath *
  23. * *
  24. * $Archive:: /Commando/Code/wwmath/colmathobbobb.cpp $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 5/04/01 8:37p $*
  29. * *
  30. * $Revision:: 14 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * obb_intersect_box0_basis -- intersection test for a basis vector from box0 *
  35. * obb_intersect_box1_basis -- intersection test for a basis vector from box1 *
  36. * obb_intersect_axis -- intersection test for a axis *
  37. * intersect_obb_obb -- test two OBBoxes for intersection *
  38. * CollisionMath::Intersection_Test -- test two obb's for intersection *
  39. * CollisionMath::Intersection_Test -- test an OBB for intersection with an AAB *
  40. * CollisionMath::Intersection_Test -- Test an AAB for intersection with an OBB *
  41. * obb_separation_test -- test the projections of two obb's for separation *
  42. * obb_check_box0_basis -- projects the boxes onto a basis vector from box0 *
  43. * obb_check_box1_basis -- projects the two obbs onto a basis vector from box1 *
  44. * obb_check_axis -- projects the obbs onto an arbitrary axis *
  45. * obb_compute_projections -- computes projections of two boxes onto an arbitrary axis *
  46. * compute_contact_normal -- computes the contact normal (after contact is detected) *
  47. * eval_side -- returns -1,0,1 depending on ab and side *
  48. * compute_contact_point -- computes the contact point (after contact is detected) *
  49. * collide_obb_obb -- test two obb's for collision *
  50. * CollisionMath::Collide -- collide two OBB's *
  51. * CollisionMath::Collide -- collide an OBB with an AAB *
  52. * CollisionMath::Collide -- collide an AAB with an OBB *
  53. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  54. #include "colmath.h"
  55. #include "obbox.h"
  56. #include "aabox.h"
  57. #include "wwdebug.h"
  58. /*
  59. ** Separating Axes have to be rejected if their length is smaller than some epsilon.
  60. ** Otherwise, erroneous results can be reported.
  61. */
  62. #define AXISLEN_EPSILON2 WWMATH_EPSILON * WWMATH_EPSILON // squared length of a separating axis must be larger than this
  63. enum
  64. {
  65. /* Axes used in Box-Box intersection tests */
  66. INTERSECTION = 0,
  67. AXIS_A0,
  68. AXIS_A1,
  69. AXIS_A2,
  70. AXIS_B0,
  71. AXIS_B1,
  72. AXIS_B2,
  73. AXIS_A0B0,
  74. AXIS_A0B1,
  75. AXIS_A0B2,
  76. AXIS_A1B0,
  77. AXIS_A1B1,
  78. AXIS_A1B2,
  79. AXIS_A2B0,
  80. AXIS_A2B1,
  81. AXIS_A2B2
  82. };
  83. /********************************************************************************
  84. OBBox-OBBox intersection detection
  85. As with most of the collision detection functions, this code is based on the theorem
  86. that given any two non-intersecting convex polyhedra, a separating plane/axis
  87. can be found that will be defined by one of the face normals of one of the polyhedra
  88. or the cross product of an edge from each polyhedra.
  89. In the case of two oriented 3D boxes, 15 separating axes must be tested.
  90. Each of the basis vectors from box A, each of the basis vectors from box B, and
  91. the cross products of any combination of a basis vector from A and a basis vector
  92. from B. Some of these separating axis tests can be optimized. For example, if
  93. the axis being tested is a basis vector from the first box, then that box's
  94. extent does not need to be projected onto the axis...
  95. The first batch of functions in this module implement a intersection test.
  96. A boolean is returned indicating whether the two boxes intersect each other
  97. in any way.
  98. The OBB-ABB and ABB-OBB functions are also implemented in a way that re-uses
  99. the OBB-OBB code.
  100. ********************************************************************************/
  101. /**
  102. ** ObbIntersectionStruct
  103. ** Contains all of the intermediate and temporary values used by
  104. ** the set of functions used in detecting intersection for obb's
  105. */
  106. struct ObbIntersectionStruct
  107. {
  108. ObbIntersectionStruct(const OBBoxClass &box0,const OBBoxClass & box1) :
  109. Box0(box0),
  110. Box1(box1)
  111. {
  112. Vector3::Subtract(box1.Center,box0.Center,&C); // vector from center of box0 to center of box1
  113. A[0].Set(box0.Basis[0][0],box0.Basis[1][0],box0.Basis[2][0]);
  114. A[1].Set(box0.Basis[0][1],box0.Basis[1][1],box0.Basis[2][1]);
  115. A[2].Set(box0.Basis[0][2],box0.Basis[1][2],box0.Basis[2][2]);
  116. B[0].Set(box1.Basis[0][0],box1.Basis[1][0],box1.Basis[2][0]);
  117. B[1].Set(box1.Basis[0][1],box1.Basis[1][1],box1.Basis[2][1]);
  118. B[2].Set(box1.Basis[0][2],box1.Basis[1][2],box1.Basis[2][2]);
  119. }
  120. Vector3 C; // Vector from the center0 to center1
  121. Vector3 A[3]; // basis vectors for box0
  122. Vector3 B[3]; // basis vectors for box1
  123. float AB[3][3]; // dot products of the basis vectors
  124. const OBBoxClass & Box0;
  125. const OBBoxClass & Box1;
  126. private:
  127. //not implemented
  128. ObbIntersectionStruct(const ObbIntersectionStruct&);
  129. ObbIntersectionStruct & operator = (const ObbIntersectionStruct&);
  130. };
  131. /***********************************************************************************************
  132. * obb_intersect_box0_basis -- intersection test for a basis vector from box0 *
  133. * *
  134. * The optimization here is that the projection of the first box is known since the axis is *
  135. * one of its basis vectors. *
  136. * *
  137. * INPUT: *
  138. * *
  139. * OUTPUT: *
  140. * *
  141. * WARNINGS: *
  142. * *
  143. * HISTORY: *
  144. * 5/4/99 GTH : Created. *
  145. *=============================================================================================*/
  146. static bool obb_intersect_box0_basis
  147. (
  148. ObbIntersectionStruct & context,
  149. int axis_index
  150. )
  151. {
  152. // ra = box0 projection onto the axis
  153. // rb = box1 projection onto the axis
  154. float ra = context.Box0.Extent[axis_index];
  155. float rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[axis_index][0]) +
  156. WWMath::Fabs(context.Box1.Extent[1]*context.AB[axis_index][1]) +
  157. WWMath::Fabs(context.Box1.Extent[2]*context.AB[axis_index][2]);
  158. float rsum = ra+rb;
  159. // u = projected distance between the box centers
  160. float u = Vector3::Dot_Product(context.C,context.A[axis_index]);
  161. // (gth) the epsilon here was not scaled to the length of the axis so it
  162. // caused problems when the axis being tested became very small
  163. return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
  164. }
  165. /***********************************************************************************************
  166. * obb_intersect_box1_basis -- intersection test for a basis vector from box1 *
  167. * *
  168. * The "optimization" here is that the extent for the second box is known since the axis is *
  169. * one of its basis vectors. *
  170. * *
  171. * INPUT: *
  172. * *
  173. * OUTPUT: *
  174. * *
  175. * WARNINGS: *
  176. * *
  177. * HISTORY: *
  178. * 5/4/99 GTH : Created. *
  179. *=============================================================================================*/
  180. static bool obb_intersect_box1_basis
  181. (
  182. ObbIntersectionStruct & context,
  183. int axis_index
  184. )
  185. {
  186. // ra = box0 projection onto the axis
  187. // rb = box1 projection onto the axis
  188. float ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[0][axis_index]) +
  189. WWMath::Fabs(context.Box0.Extent[1]*context.AB[1][axis_index]) +
  190. WWMath::Fabs(context.Box0.Extent[2]*context.AB[2][axis_index]);
  191. float rb = context.Box1.Extent[axis_index];
  192. float rsum = ra+rb;
  193. // u = projected distance between the box centers
  194. float u = Vector3::Dot_Product(context.C,context.B[axis_index]);
  195. // (gth) the epsilon here was not scaled to the length of the axis so it
  196. // caused problems when the axis being tested became very small
  197. return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
  198. }
  199. /***********************************************************************************************
  200. * obb_intersect_axis -- intersection test for a axis *
  201. * *
  202. * Checks intersection on an arbitrary axis where you've already computed the projectsions. *
  203. * Many of the later tests in the OBB-OBB algorigthm fall into here since there are *
  204. * optimizations in computing the projections but they are all specific to the axis being used *
  205. * *
  206. * INPUT: *
  207. * *
  208. * OUTPUT: *
  209. * *
  210. * WARNINGS: *
  211. * *
  212. * HISTORY: *
  213. * 5/4/99 GTH : Created. *
  214. *=============================================================================================*/
  215. static inline bool obb_intersect_axis
  216. (
  217. ObbIntersectionStruct & context,
  218. const Vector3 & axis,
  219. float ra,
  220. float rb
  221. )
  222. {
  223. float rsum = ra+rb;
  224. float u = Vector3::Dot_Product(context.C,axis);
  225. // (gth) the epsilon here was not scaled to the length of the axis so it
  226. // caused problems when the axis being tested became very small
  227. return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
  228. }
  229. /***********************************************************************************************
  230. * intersect_obb_obb -- test two OBBoxes for intersection *
  231. * *
  232. * This function works in a very similar (but simplified) way as the Collide function. See *
  233. * the comments in that function for more clues regarding the math involved... *
  234. * *
  235. * Due to the re-usage of intermediate calculations, this function is ~2x faster than the *
  236. * equivalent Oriented_Boxes_Intersect. *
  237. * *
  238. * INPUT: *
  239. * *
  240. * OUTPUT: *
  241. * *
  242. * WARNINGS: *
  243. * *
  244. * HISTORY: *
  245. * 5/4/99 GTH : Created. *
  246. *=============================================================================================*/
  247. bool intersect_obb_obb
  248. (
  249. ObbIntersectionStruct & context
  250. )
  251. {
  252. Vector3 axis;
  253. float ra,rb;
  254. /////////////////////////////////////////////////////////////////////////
  255. // Axis = A0
  256. /////////////////////////////////////////////////////////////////////////
  257. context.AB[0][0] = Vector3::Dot_Product(context.A[0],context.B[0]);
  258. context.AB[0][1] = Vector3::Dot_Product(context.A[0],context.B[1]);
  259. context.AB[0][2] = Vector3::Dot_Product(context.A[0],context.B[2]);
  260. if (context.Box0.Extent[0] > 0.0f) {
  261. if (obb_intersect_box0_basis(context,0)) return false;
  262. }
  263. /////////////////////////////////////////////////////////////////////////
  264. // Axsis A1
  265. /////////////////////////////////////////////////////////////////////////
  266. context.AB[1][0] = Vector3::Dot_Product(context.A[1],context.B[0]);
  267. context.AB[1][1] = Vector3::Dot_Product(context.A[1],context.B[1]);
  268. context.AB[1][2] = Vector3::Dot_Product(context.A[1],context.B[2]);
  269. if (context.Box0.Extent[1] > 0.0f) {
  270. if (obb_intersect_box0_basis(context,1)) return false;
  271. }
  272. /////////////////////////////////////////////////////////////////////////
  273. // Axis = A2
  274. /////////////////////////////////////////////////////////////////////////
  275. context.AB[2][0] = Vector3::Dot_Product(context.A[2],context.B[0]);
  276. context.AB[2][1] = Vector3::Dot_Product(context.A[2],context.B[1]);
  277. context.AB[2][2] = Vector3::Dot_Product(context.A[2],context.B[2]);
  278. if (context.Box0.Extent[2] > 0.0f) {
  279. if (obb_intersect_box0_basis(context,2)) return false;
  280. }
  281. /////////////////////////////////////////////////////////////////////////
  282. // Axis B0,B1,B2
  283. /////////////////////////////////////////////////////////////////////////
  284. if (context.Box1.Extent[0] > 0.0f) {
  285. if (obb_intersect_box1_basis(context,0)) return false;
  286. }
  287. if (context.Box1.Extent[1] > 0.0f) {
  288. if (obb_intersect_box1_basis(context,1)) return false;
  289. }
  290. if (context.Box1.Extent[2] > 0.0f) {
  291. if (obb_intersect_box1_basis(context,2)) return false;
  292. }
  293. /////////////////////////////////////////////////////////////////////////
  294. // Axis = A0xB0
  295. /////////////////////////////////////////////////////////////////////////
  296. Vector3::Cross_Product(context.A[0],context.B[0],&axis);
  297. if (axis.Length2() > AXISLEN_EPSILON2) {
  298. ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][0]);
  299. rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][1]);
  300. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  301. }
  302. /////////////////////////////////////////////////////////////////////////
  303. // Axis = A0xB1
  304. /////////////////////////////////////////////////////////////////////////
  305. Vector3::Cross_Product(context.A[0],context.B[1],&axis);
  306. if (axis.Length2() > AXISLEN_EPSILON2) {
  307. ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][1]);
  308. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][0]);
  309. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  310. }
  311. /////////////////////////////////////////////////////////////////////////
  312. // Axis = A0xB2
  313. /////////////////////////////////////////////////////////////////////////
  314. Vector3::Cross_Product(context.A[0],context.B[2],&axis);
  315. if (axis.Length2() > AXISLEN_EPSILON2) {
  316. ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][2]);
  317. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][0]);
  318. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  319. }
  320. /////////////////////////////////////////////////////////////////////////
  321. // Axis = A1xB0
  322. /////////////////////////////////////////////////////////////////////////
  323. Vector3::Cross_Product(context.A[1],context.B[0],&axis);
  324. if (axis.Length2() > AXISLEN_EPSILON2) {
  325. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][0]);
  326. rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][1]);
  327. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  328. }
  329. /////////////////////////////////////////////////////////////////////////
  330. // Axis = A1xB1
  331. /////////////////////////////////////////////////////////////////////////
  332. Vector3::Cross_Product(context.A[1],context.B[1],&axis);
  333. if (axis.Length2() > AXISLEN_EPSILON2) {
  334. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][1]);
  335. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][0]);
  336. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  337. }
  338. /////////////////////////////////////////////////////////////////////////
  339. // Axis = A1xB2
  340. /////////////////////////////////////////////////////////////////////////
  341. Vector3::Cross_Product(context.A[1],context.B[2],&axis);
  342. if (axis.Length2() > AXISLEN_EPSILON2) {
  343. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][2]);
  344. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][0]);
  345. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  346. }
  347. /////////////////////////////////////////////////////////////////////////
  348. // Axis = A2xB0
  349. /////////////////////////////////////////////////////////////////////////
  350. Vector3::Cross_Product(context.A[2],context.B[0],&axis);
  351. if (axis.Length2() > AXISLEN_EPSILON2) {
  352. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][0])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][0]);
  353. rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][1]);
  354. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  355. }
  356. /////////////////////////////////////////////////////////////////////////
  357. // Axis = A2xB1
  358. /////////////////////////////////////////////////////////////////////////
  359. Vector3::Cross_Product(context.A[2],context.B[1],&axis);
  360. if (axis.Length2() > AXISLEN_EPSILON2) {
  361. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][1]);
  362. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][0]);
  363. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  364. }
  365. /////////////////////////////////////////////////////////////////////////
  366. // Axis = A2xB2
  367. /////////////////////////////////////////////////////////////////////////
  368. Vector3::Cross_Product(context.A[2],context.B[2],&axis);
  369. if (axis.Length2() > AXISLEN_EPSILON2) {
  370. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][2]);
  371. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][0]);
  372. if (obb_intersect_axis(context,axis,ra,rb)) return false;
  373. }
  374. return true;
  375. }
  376. /***********************************************************************************************
  377. * CollisionMath::Intersection_Test -- test two obb's for intersection *
  378. * *
  379. * Simply sets up the context and calls intersect_obb_obb *
  380. * *
  381. * INPUT: *
  382. * *
  383. * OUTPUT: *
  384. * *
  385. * WARNINGS: *
  386. * *
  387. * HISTORY: *
  388. * 5/25/99 GTH : Created. *
  389. *=============================================================================================*/
  390. bool CollisionMath::Intersection_Test(const OBBoxClass & box0,const OBBoxClass & box1)
  391. {
  392. ObbIntersectionStruct context(box0,box1);
  393. return intersect_obb_obb(context);
  394. }
  395. /***********************************************************************************************
  396. * CollisionMath::Intersection_Test -- test an OBB for intersection with an AAB *
  397. * *
  398. * INPUT: *
  399. * *
  400. * OUTPUT: *
  401. * *
  402. * WARNINGS: *
  403. * *
  404. * HISTORY: *
  405. * 5/25/99 GTH : Created. *
  406. *=============================================================================================*/
  407. bool CollisionMath::Intersection_Test(const OBBoxClass & box0,const AABoxClass & box1)
  408. {
  409. OBBoxClass obbox1(box1.Center,box1.Extent);
  410. ObbIntersectionStruct context(box0,obbox1);
  411. return intersect_obb_obb(context);
  412. }
  413. /***********************************************************************************************
  414. * CollisionMath::Intersection_Test -- Test an AAB for intersection with an OBB *
  415. * *
  416. * INPUT: *
  417. * *
  418. * OUTPUT: *
  419. * *
  420. * WARNINGS: *
  421. * *
  422. * HISTORY: *
  423. * 5/25/99 GTH : Created. *
  424. *=============================================================================================*/
  425. bool CollisionMath::Intersection_Test(const AABoxClass & box0,const OBBoxClass & box1)
  426. {
  427. OBBoxClass obbox0(box0.Center,box0.Extent);
  428. ObbIntersectionStruct context(obbox0,box1);
  429. return intersect_obb_obb(context);
  430. }
  431. /********************************************************************************
  432. OBBox-OBBox collision detection
  433. This batch of functions implement collision detection for moving oriented
  434. boxes. Assuming that the two arbitrarily oriented boxes are moving at a constant
  435. velocity along a path and not rotating, the time of collision can be found.
  436. The OBB-ABB and ABB-OBB functions are also implemented in a way that re-uses
  437. the OBB-OBB code.
  438. For the code which computes the point of collision and collision normal, you'll
  439. have to refer to the paper by Dave Eberly on oriented bounding boxes. The
  440. formulas for the collision point are the only part of this I was unable to
  441. derive myself (they are pretty nasty...)
  442. ********************************************************************************/
  443. /**
  444. ** ObbCollisionStruct
  445. ** Contains all of the intermediate and temporary values used by
  446. ** the set of functions used in detecting collisions for obb's
  447. */
  448. struct ObbCollisionStruct
  449. {
  450. ObbCollisionStruct(const OBBoxClass &box0,const Vector3 &move0,const OBBoxClass & box1,const Vector3 &move1) :
  451. StartBad(true), // Startbad is true until one of the axes clears it
  452. AxisId(INTERSECTION), // AxisId will be the axis that allowed the longest move
  453. MaxFrac(0.0f), // MaxFrac is the longest allowed move so far
  454. Box0(box0),
  455. Move0(move0),
  456. Box1(box1),
  457. Move1(move1)
  458. {
  459. Vector3::Subtract(box1.Center,box0.Center,&C); // vector from center of box0 to center of box1
  460. Vector3::Subtract(move1,move0,&M); // move vector relative to stationary box0
  461. A[0].Set(box0.Basis[0][0],box0.Basis[1][0],box0.Basis[2][0]);
  462. A[1].Set(box0.Basis[0][1],box0.Basis[1][1],box0.Basis[2][1]);
  463. A[2].Set(box0.Basis[0][2],box0.Basis[1][2],box0.Basis[2][2]);
  464. B[0].Set(box1.Basis[0][0],box1.Basis[1][0],box1.Basis[2][0]);
  465. B[1].Set(box1.Basis[0][1],box1.Basis[1][1],box1.Basis[2][1]);
  466. B[2].Set(box1.Basis[0][2],box1.Basis[1][2],box1.Basis[2][2]);
  467. }
  468. bool StartBad; // Inital configuration is intersecting?
  469. float MaxFrac; // Longest move allowed so far
  470. int AxisId; // Last separating axis
  471. int Side; // which side of the interval
  472. int TestAxisId; // Axis 'id' we're working on
  473. Vector3 TestAxis; // Axis that we're working on
  474. Vector3 C; // Vector from the center0 to center1
  475. Vector3 M; // Move vector relative to stationary box0
  476. Vector3 A[3]; // basis vectors for box0
  477. Vector3 B[3]; // basis vectors for box1
  478. float AB[3][3]; // dot products of the basis vectors
  479. const OBBoxClass & Box0;
  480. const Vector3 & Move0;
  481. const OBBoxClass & Box1;
  482. const Vector3 & Move1;
  483. private:
  484. //not implemented
  485. ObbCollisionStruct(const ObbCollisionStruct&);
  486. ObbCollisionStruct & operator = (const ObbCollisionStruct&);
  487. };
  488. /***********************************************************************************************
  489. * obb_separation_test -- test the projections of two obb's for separation *
  490. * *
  491. * INPUT: *
  492. * *
  493. * OUTPUT: *
  494. * *
  495. * WARNINGS: *
  496. * *
  497. * HISTORY: *
  498. * 4/8/99 GTH : Created. *
  499. *=============================================================================================*/
  500. static inline bool obb_separation_test
  501. (
  502. ObbCollisionStruct & context,
  503. float ra,
  504. float rb,
  505. float u0,
  506. float u1
  507. )
  508. {
  509. float tmp;
  510. float rsum = ra+rb;
  511. if ( u0 + WWMATH_EPSILON > rsum ) {
  512. context.StartBad = false;
  513. if ( u1 > rsum ) {
  514. context.MaxFrac = 1.0f;
  515. return true;
  516. } else {
  517. tmp = (rsum-u0)/(u1-u0);
  518. if ( tmp > context.MaxFrac ) {
  519. context.MaxFrac = tmp;
  520. context.AxisId = context.TestAxisId;
  521. context.Side = +1;
  522. }
  523. }
  524. } else if ( u0 - WWMATH_EPSILON < -rsum ) {
  525. context.StartBad = false;
  526. if ( u1 < -rsum ) {
  527. context.MaxFrac = 1.0f;
  528. return true;
  529. } else {
  530. tmp = (-rsum-u0)/(u1-u0);
  531. if ( tmp > context.MaxFrac ) {
  532. context.MaxFrac = tmp;
  533. context.AxisId = context.TestAxisId;
  534. context.Side = -1;
  535. }
  536. }
  537. }
  538. return false;
  539. }
  540. /***********************************************************************************************
  541. * obb_check_box0_basis -- projects the boxes onto a basis vector from box0 *
  542. * *
  543. * INPUT: *
  544. * *
  545. * OUTPUT: *
  546. * *
  547. * WARNINGS: *
  548. * *
  549. * HISTORY: *
  550. * 4/8/99 GTH : Created. *
  551. *=============================================================================================*/
  552. static bool obb_check_box0_basis
  553. (
  554. ObbCollisionStruct & context,
  555. int axis_index
  556. )
  557. {
  558. // ra = box0 projection onto the axis
  559. // rb = box1 projection onto the axis
  560. float ra = context.Box0.Extent[axis_index];
  561. float rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[axis_index][0]) +
  562. WWMath::Fabs(context.Box1.Extent[1]*context.AB[axis_index][1]) +
  563. WWMath::Fabs(context.Box1.Extent[2]*context.AB[axis_index][2]);
  564. // u0 = projected distance between the box centers at t0
  565. // u1 = projected distance between the box centers at t1
  566. float u0 = Vector3::Dot_Product(context.C,context.A[axis_index]);
  567. float u1 = u0 + Vector3::Dot_Product(context.M,context.A[axis_index]);
  568. return obb_separation_test(context,ra,rb,u0,u1);
  569. }
  570. /***********************************************************************************************
  571. * obb_check_box1_basis -- projects the two obbs onto a basis vector from box1 *
  572. * *
  573. * INPUT: *
  574. * *
  575. * OUTPUT: *
  576. * *
  577. * WARNINGS: *
  578. * *
  579. * HISTORY: *
  580. * 4/8/99 GTH : Created. *
  581. *=============================================================================================*/
  582. static bool obb_check_box1_basis
  583. (
  584. ObbCollisionStruct & context,
  585. int axis_index
  586. )
  587. {
  588. // ra = box0 projection onto the axis
  589. // rb = box1 projection onto the axis
  590. float ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[0][axis_index]) +
  591. WWMath::Fabs(context.Box0.Extent[1]*context.AB[1][axis_index]) +
  592. WWMath::Fabs(context.Box0.Extent[2]*context.AB[2][axis_index]);
  593. float rb = context.Box1.Extent[axis_index];
  594. // u0 = projected distance between the box centers at t0
  595. // u1 = projected distance between the box centers at t1
  596. float u0 = Vector3::Dot_Product(context.C,context.B[axis_index]);
  597. float u1 = u0 + Vector3::Dot_Product(context.M,context.B[axis_index]);
  598. return obb_separation_test(context,ra,rb,u0,u1);
  599. }
  600. /***********************************************************************************************
  601. * obb_check_axis -- projects the obbs onto an arbitrary axis *
  602. * *
  603. * INPUT: *
  604. * *
  605. * OUTPUT: *
  606. * *
  607. * WARNINGS: *
  608. * *
  609. * HISTORY: *
  610. * 4/8/99 GTH : Created. *
  611. *=============================================================================================*/
  612. static inline bool obb_check_axis
  613. (
  614. ObbCollisionStruct & context,
  615. float ra,
  616. float rb
  617. )
  618. {
  619. float u0 = Vector3::Dot_Product(context.C,context.TestAxis);
  620. float u1 = u0 + Vector3::Dot_Product(context.M,context.TestAxis);
  621. return obb_separation_test(context,ra,rb,u0,u1);
  622. }
  623. /***********************************************************************************************
  624. * obb_compute_projections -- computes projections of two boxes onto an arbitrary axis *
  625. * *
  626. * INPUT: *
  627. * *
  628. * OUTPUT: *
  629. * *
  630. * WARNINGS: *
  631. * *
  632. * HISTORY: *
  633. * 4/8/99 GTH : Created. *
  634. *=============================================================================================*/
  635. static inline void obb_compute_projections
  636. (
  637. const ObbCollisionStruct & context,
  638. float * ra,
  639. float * rb
  640. )
  641. {
  642. *ra = context.Box0.Extent.X * WWMath::Fabs(Vector3::Dot_Product(context.A[0],context.TestAxis)) +
  643. context.Box0.Extent.Y * WWMath::Fabs(Vector3::Dot_Product(context.A[1],context.TestAxis)) +
  644. context.Box0.Extent.Z * WWMath::Fabs(Vector3::Dot_Product(context.A[2],context.TestAxis));
  645. *rb = context.Box1.Extent.X * WWMath::Fabs(Vector3::Dot_Product(context.B[0],context.TestAxis)) +
  646. context.Box1.Extent.Y * WWMath::Fabs(Vector3::Dot_Product(context.B[1],context.TestAxis)) +
  647. context.Box1.Extent.Z * WWMath::Fabs(Vector3::Dot_Product(context.B[2],context.TestAxis));
  648. }
  649. /***********************************************************************************************
  650. * compute_contact_normal -- computes the contact normal (after contact is detected) *
  651. * *
  652. * INPUT: *
  653. * *
  654. * OUTPUT: *
  655. * *
  656. * WARNINGS: *
  657. * *
  658. * HISTORY: *
  659. * 4/8/99 GTH : Created. *
  660. *=============================================================================================*/
  661. static inline void compute_contact_normal(ObbCollisionStruct & context,CastResultStruct * result)
  662. {
  663. switch(context.AxisId)
  664. {
  665. case INTERSECTION:
  666. #pragma message("Fatal assert disabled for demo, obb-obb collision")
  667. // WWASSERT(0);
  668. // break;
  669. case AXIS_A0:
  670. result->Normal = context.A[0];
  671. break;
  672. case AXIS_A1:
  673. result->Normal = context.A[1];
  674. break;
  675. case AXIS_A2:
  676. result->Normal = context.A[2];
  677. break;
  678. case AXIS_B0:
  679. result->Normal = context.B[0];
  680. break;
  681. case AXIS_B1:
  682. result->Normal = context.B[1];
  683. break;
  684. case AXIS_B2:
  685. result->Normal = context.B[2];
  686. break;
  687. case AXIS_A0B0:
  688. Vector3::Cross_Product(context.A[0],context.B[0],&result->Normal);
  689. result->Normal.Normalize();
  690. break;
  691. case AXIS_A0B1:
  692. Vector3::Cross_Product(context.A[0],context.B[1],&result->Normal);
  693. result->Normal.Normalize();
  694. break;
  695. case AXIS_A0B2:
  696. Vector3::Cross_Product(context.A[0],context.B[2],&result->Normal);
  697. result->Normal.Normalize();
  698. break;
  699. case AXIS_A1B0:
  700. Vector3::Cross_Product(context.A[1],context.B[0],&result->Normal);
  701. result->Normal.Normalize();
  702. break;
  703. case AXIS_A1B1:
  704. Vector3::Cross_Product(context.A[1],context.B[1],&result->Normal);
  705. result->Normal.Normalize();
  706. break;
  707. case AXIS_A1B2:
  708. Vector3::Cross_Product(context.A[1],context.B[2],&result->Normal);
  709. result->Normal.Normalize();
  710. break;
  711. case AXIS_A2B0:
  712. Vector3::Cross_Product(context.A[2],context.B[0],&result->Normal);
  713. result->Normal.Normalize();
  714. break;
  715. case AXIS_A2B1:
  716. Vector3::Cross_Product(context.A[2],context.B[1],&result->Normal);
  717. result->Normal.Normalize();
  718. break;
  719. case AXIS_A2B2:
  720. Vector3::Cross_Product(context.A[2],context.B[2],&result->Normal);
  721. result->Normal.Normalize();
  722. break;
  723. }
  724. result->Normal *= -context.Side;
  725. }
  726. /***********************************************************************************************
  727. * eval_side -- returns -1,0,1 depending on ab and side *
  728. * *
  729. * INPUT: *
  730. * *
  731. * OUTPUT: *
  732. * *
  733. * WARNINGS: *
  734. * *
  735. * HISTORY: *
  736. * 4/8/99 GTH : Created. *
  737. *=============================================================================================*/
  738. static inline float eval_side(float ab,float side)
  739. {
  740. if (ab > 0.0f) {
  741. return side;
  742. } else if (ab < 0.0f) {
  743. return -side;
  744. } else {
  745. return 0.0f;
  746. }
  747. }
  748. /***********************************************************************************************
  749. * compute_contact_point -- computes the contact point (after contact is detected) *
  750. * *
  751. * INPUT: *
  752. * *
  753. * OUTPUT: *
  754. * *
  755. * WARNINGS: *
  756. * *
  757. * HISTORY: *
  758. * 4/8/99 GTH : Created. *
  759. *=============================================================================================*/
  760. static inline void compute_contact_point(ObbCollisionStruct & context,CastResultStruct * result)
  761. {
  762. int i,j;
  763. float x[3]; // box0 parameters
  764. float y[3]; // box1 parameters
  765. float den;
  766. Vector3 dcnew(0,0,0);
  767. //again:
  768. if (context.AxisId >= AXIS_A0B0) {
  769. Vector3 cnew0;
  770. Vector3 cnew1;
  771. Vector3::Add(context.Box0.Center,context.MaxFrac * context.Move0,&cnew0);
  772. Vector3::Add(context.Box1.Center,context.MaxFrac * context.Move1,&cnew1);
  773. Vector3::Subtract(cnew1,cnew0,&dcnew);
  774. }
  775. //PROBLEMS:
  776. //in case of edge-face or face-face or perfectly aligned edge-edge this
  777. //routine is only computing a single point.
  778. switch(context.AxisId)
  779. {
  780. case AXIS_A0:
  781. case AXIS_A1:
  782. case AXIS_A2:
  783. i = context.AxisId - AXIS_A0;
  784. for (j=0; j<3; j++) {
  785. y[j] = -eval_side(context.AB[i][j],context.Side);
  786. }
  787. context.Box1.Compute_Point(y,&(result->ContactPoint));
  788. result->ContactPoint += result->Fraction * context.Move1;
  789. return;
  790. case AXIS_B0:
  791. case AXIS_B1:
  792. case AXIS_B2:
  793. j = context.AxisId - AXIS_B0;
  794. for (i=0; i<3; i++) {
  795. x[i] = eval_side(context.AB[i][j],context.Side);
  796. }
  797. context.Box0.Compute_Point(x,&(result->ContactPoint));
  798. result->ContactPoint += result->Fraction * context.Move0;
  799. return;
  800. case AXIS_A0B0:
  801. x[1] = -eval_side(context.AB[2][0],context.Side) * context.Box0.Extent[1];
  802. x[2] = eval_side(context.AB[1][0],context.Side) * context.Box0.Extent[2];
  803. y[1] = -eval_side(context.AB[0][2],context.Side) * context.Box1.Extent[1];
  804. y[2] = eval_side(context.AB[0][1],context.Side) * context.Box1.Extent[2];
  805. den = (1.0f - context.AB[0][0] * context.AB[0][0]);
  806. if (WWMath::Fabs(den) > 0.0f) {
  807. x[0] = Vector3::Dot_Product(context.A[0],dcnew);
  808. x[0] += context.AB[0][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[1][0]*x[1] + context.AB[2][0]*x[2]);
  809. x[0] += context.AB[0][1] * y[1] + context.AB[0][2] * y[2];
  810. x[0] /= den;
  811. } else {
  812. x[0] = 0.0f;
  813. }
  814. break;
  815. case AXIS_A0B1:
  816. x[1] = -eval_side(context.AB[2][1],context.Side) * context.Box0.Extent[1];
  817. x[2] = eval_side(context.AB[1][1],context.Side) * context.Box0.Extent[2];
  818. y[0] = eval_side(context.AB[0][2],context.Side) * context.Box1.Extent[0];
  819. y[2] = -eval_side(context.AB[0][0],context.Side) * context.Box1.Extent[2];
  820. den = (1.0f - context.AB[0][1] * context.AB[0][1]);
  821. if (WWMath::Fabs(den) > 0.0f) {
  822. x[0] = Vector3::Dot_Product(context.A[0],dcnew);
  823. x[0] += context.AB[0][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[1][1]*x[1] + context.AB[2][1]*x[2]);
  824. x[0] += context.AB[0][0] * y[0] + context.AB[0][2] * y[2];
  825. x[0] /= den;
  826. } else {
  827. x[0] = 0.0f;
  828. }
  829. break;
  830. case AXIS_A0B2:
  831. x[1] = -eval_side(context.AB[2][2],context.Side) * context.Box0.Extent[1];
  832. x[2] = eval_side(context.AB[1][2],context.Side) * context.Box0.Extent[2];
  833. y[0] = -eval_side(context.AB[0][1],context.Side) * context.Box1.Extent[0];
  834. y[1] = eval_side(context.AB[0][0],context.Side) * context.Box1.Extent[1];
  835. den = (1.0f - context.AB[0][2] * context.AB[0][2]);
  836. if (WWMath::Fabs(den) > 0.0f) {
  837. x[0] = Vector3::Dot_Product(context.A[0],dcnew);
  838. x[0] += context.AB[0][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[1][2]*x[1] + context.AB[2][2]*x[2]);
  839. x[0] += context.AB[0][0] * y[0] + context.AB[0][1] * y[1];
  840. x[0] /= den;
  841. } else {
  842. x[0] = 0.0f;
  843. }
  844. break;
  845. case AXIS_A1B0:
  846. x[0] = eval_side(context.AB[2][0],context.Side) * context.Box0.Extent[0];
  847. x[2] = -eval_side(context.AB[0][0],context.Side) * context.Box0.Extent[2];
  848. y[1] = -eval_side(context.AB[1][2],context.Side) * context.Box1.Extent[1];
  849. y[2] = eval_side(context.AB[1][1],context.Side) * context.Box1.Extent[2];
  850. den = (1.0f - context.AB[1][0] * context.AB[1][0]);
  851. if (WWMath::Fabs(den) > 0.0f) {
  852. x[1] = Vector3::Dot_Product(context.A[1],dcnew);
  853. x[1] += context.AB[1][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[0][0]*x[0] + context.AB[2][0]*x[2]);
  854. x[1] += context.AB[1][1] * y[1] + context.AB[1][2] * y[2];
  855. x[1] /= den;
  856. } else {
  857. x[1] = 0.0f;
  858. }
  859. break;
  860. case AXIS_A1B1:
  861. x[0] = eval_side(context.AB[2][1],context.Side) * context.Box0.Extent[0];
  862. x[2] = -eval_side(context.AB[0][1],context.Side) * context.Box0.Extent[2];
  863. y[0] = eval_side(context.AB[1][2],context.Side) * context.Box1.Extent[0];
  864. y[2] = -eval_side(context.AB[1][0],context.Side) * context.Box1.Extent[2];
  865. den = 1.0f / (1.0f - context.AB[1][1] * context.AB[1][1]);
  866. if (WWMath::Fabs(den) > 0.0f) {
  867. x[1] = Vector3::Dot_Product(context.A[1],dcnew);
  868. x[1] += context.AB[1][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[0][1]*x[0] + context.AB[2][1]*x[2]);
  869. x[1] += context.AB[1][0] * y[0] + context.AB[1][2] * y[2];
  870. x[1] /= den;
  871. } else {
  872. x[1] = 0.0f;
  873. }
  874. break;
  875. case AXIS_A1B2:
  876. x[0] = eval_side(context.AB[2][2],context.Side) * context.Box0.Extent[0];
  877. x[2] = -eval_side(context.AB[0][2],context.Side) * context.Box0.Extent[2];
  878. y[0] = -eval_side(context.AB[1][1],context.Side) * context.Box1.Extent[0];
  879. y[1] = eval_side(context.AB[1][0],context.Side) * context.Box1.Extent[1];
  880. den = (1.0f - context.AB[1][2] * context.AB[1][2]);
  881. if (WWMath::Fabs(den) > 0.0f) {
  882. x[1] = Vector3::Dot_Product(context.A[1],dcnew);
  883. x[1] += context.AB[1][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[0][2]*x[0] + context.AB[2][2]*x[2]);
  884. x[1] += context.AB[1][0] * y[0] + context.AB[1][1] * y[1];
  885. x[1] /= den;
  886. } else {
  887. x[1] = 0.0f;
  888. }
  889. break;
  890. case AXIS_A2B0:
  891. x[0] = -eval_side(context.AB[1][0],context.Side) * context.Box0.Extent[0];
  892. x[1] = eval_side(context.AB[0][0],context.Side) * context.Box0.Extent[1];
  893. y[1] = -eval_side(context.AB[2][2],context.Side) * context.Box1.Extent[1];
  894. y[2] = eval_side(context.AB[2][1],context.Side) * context.Box1.Extent[2];
  895. den = (1.0f - context.AB[2][0] * context.AB[2][0]);
  896. if (WWMath::Fabs(den) > 0.0f) {
  897. x[2] = Vector3::Dot_Product(context.A[2],dcnew);
  898. x[2] += context.AB[2][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[0][0]*x[0] + context.AB[1][0]*x[1]);
  899. x[2] += context.AB[2][1] * y[1] + context.AB[2][2] * y[2];
  900. x[2] /= den;
  901. } else {
  902. x[2] = 0.0f;
  903. }
  904. break;
  905. case AXIS_A2B1:
  906. x[0] = -eval_side(context.AB[1][1],context.Side) * context.Box0.Extent[0];
  907. x[1] = eval_side(context.AB[0][1],context.Side) * context.Box0.Extent[1];
  908. y[0] = eval_side(context.AB[2][2],context.Side) * context.Box1.Extent[0];
  909. y[2] = -eval_side(context.AB[2][0],context.Side) * context.Box1.Extent[2];
  910. den = (1.0f - context.AB[2][1] * context.AB[2][1]);
  911. if (WWMath::Fabs(den) > 0.0f) {
  912. x[2] = Vector3::Dot_Product(context.A[2],dcnew);
  913. x[2] += context.AB[2][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[0][1]*x[0] + context.AB[1][1]*x[1]);
  914. x[2] += context.AB[2][0] * y[0] + context.AB[2][2] * y[2];
  915. x[2] /= den;
  916. } else {
  917. x[2] = 0.0f;
  918. }
  919. break;
  920. case AXIS_A2B2:
  921. x[0] = -eval_side(context.AB[1][2],context.Side) * context.Box0.Extent[0];
  922. x[1] = eval_side(context.AB[0][2],context.Side) * context.Box0.Extent[1];
  923. y[0] = -eval_side(context.AB[2][1],context.Side) * context.Box1.Extent[0];
  924. y[1] = eval_side(context.AB[2][0],context.Side) * context.Box1.Extent[1];
  925. den = (1.0f - context.AB[2][2] * context.AB[2][2]);
  926. if (WWMath::Fabs(den) > 0.0f) {
  927. x[2] = Vector3::Dot_Product(context.A[2],dcnew);
  928. x[2] += context.AB[2][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[0][2]*x[0] + context.AB[1][2]*x[1]);
  929. x[2] += context.AB[2][0] * y[0] + context.AB[2][1] * y[1];
  930. x[2] /= den;
  931. } else {
  932. x[2] = 0.0f;
  933. }
  934. break;
  935. }
  936. // all but the first two cases fall through to here
  937. result->ContactPoint.X = context.Box0.Center.X +
  938. x[0]*context.A[0].X +
  939. x[1]*context.A[1].X +
  940. x[2]*context.A[2].X;
  941. result->ContactPoint.Y = context.Box0.Center.Y +
  942. x[0]*context.A[0].Y +
  943. x[1]*context.A[1].Y +
  944. x[2]*context.A[2].Y;
  945. result->ContactPoint.Z = context.Box0.Center.Z +
  946. x[0]*context.A[0].Z +
  947. x[1]*context.A[1].Z +
  948. x[2]*context.A[2].Z;
  949. Vector3::Add(result->ContactPoint,result->Fraction * context.Move0,&(result->ContactPoint));
  950. }
  951. /***********************************************************************************************
  952. * collide_obb_obb -- test two obb's for collision *
  953. * *
  954. * INPUT: *
  955. * *
  956. * OUTPUT: *
  957. * *
  958. * WARNINGS: *
  959. * *
  960. * HISTORY: *
  961. * 5/25/99 GTH : Created. *
  962. *=============================================================================================*/
  963. bool collide_obb_obb
  964. (
  965. ObbCollisionStruct & context,
  966. CastResultStruct * result
  967. )
  968. {
  969. Vector3 axis;
  970. float ra,rb;
  971. /////////////////////////////////////////////////////////////////////////
  972. // Axis = A0
  973. // Projecting the two boxes onto Box0's X axis. If their intervals
  974. // on this line do not intersect, the boxes are not intersecting!
  975. // Each of the tests in this function work in a similar way.
  976. // For this function I compute the AB's that are needed. The first
  977. // three tests compute all of these constants.
  978. /////////////////////////////////////////////////////////////////////////
  979. context.TestAxisId = AXIS_A0;
  980. context.AB[0][0] = Vector3::Dot_Product(context.A[0],context.B[0]);
  981. context.AB[0][1] = Vector3::Dot_Product(context.A[0],context.B[1]);
  982. context.AB[0][2] = Vector3::Dot_Product(context.A[0],context.B[2]);
  983. if (obb_check_box0_basis(context,0)) goto exit;
  984. /////////////////////////////////////////////////////////////////////////
  985. // Axsis A1
  986. /////////////////////////////////////////////////////////////////////////
  987. context.TestAxisId = AXIS_A1;
  988. context.AB[1][0] = Vector3::Dot_Product(context.A[1],context.B[0]);
  989. context.AB[1][1] = Vector3::Dot_Product(context.A[1],context.B[1]);
  990. context.AB[1][2] = Vector3::Dot_Product(context.A[1],context.B[2]);
  991. if (obb_check_box0_basis(context,1)) goto exit;
  992. /////////////////////////////////////////////////////////////////////////
  993. // Axis = A2
  994. /////////////////////////////////////////////////////////////////////////
  995. context.TestAxisId = AXIS_A2;
  996. context.AB[2][0] = Vector3::Dot_Product(context.A[2],context.B[0]);
  997. context.AB[2][1] = Vector3::Dot_Product(context.A[2],context.B[1]);
  998. context.AB[2][2] = Vector3::Dot_Product(context.A[2],context.B[2]);
  999. if (obb_check_box0_basis(context,2)) goto exit;
  1000. /////////////////////////////////////////////////////////////////////////
  1001. // Axis = B0
  1002. /////////////////////////////////////////////////////////////////////////
  1003. context.TestAxisId = AXIS_B0;
  1004. if (obb_check_box1_basis(context,0)) goto exit;
  1005. /////////////////////////////////////////////////////////////////////////
  1006. // Axis = B1
  1007. /////////////////////////////////////////////////////////////////////////
  1008. context.TestAxisId = AXIS_B1;
  1009. if (obb_check_box1_basis(context,1)) goto exit;
  1010. /////////////////////////////////////////////////////////////////////////
  1011. // Axis = B2
  1012. /////////////////////////////////////////////////////////////////////////
  1013. context.TestAxisId = AXIS_B2;
  1014. if (obb_check_box1_basis(context,2)) goto exit;
  1015. /////////////////////////////////////////////////////////////////////////
  1016. // Axis = A0xB0
  1017. // The axes defined by the cross product between the boxes' basis
  1018. // vectors are optimized in a similar way to this one:
  1019. //
  1020. // ra = |ex*A0*(A0xB0)| + |ey*A1*(A0xB0)| + |ez*A2*(A0xB0)|
  1021. // = |ey*A1*(A0xB0)| + |ez*A2*(A0xB0)| A0*(A0xB0)=0
  1022. // = |ey*B0*(A1xA0)| + |ez*B0*(A2xA0)| A*(BxC)=B*(CxA)=C*(AxB)
  1023. // = |-ey*A2*B0| + |ez*A1*B0| A0xA1=A2
  1024. // = |ey*AB[2][0]| + |ez*AB[1][0]| already computed these dot products!
  1025. //
  1026. /////////////////////////////////////////////////////////////////////////
  1027. Vector3::Cross_Product(context.A[0],context.B[0],&context.TestAxis);
  1028. context.TestAxisId = AXIS_A0B0;
  1029. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1030. ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][0]);
  1031. rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][1]);
  1032. if (obb_check_axis(context,ra,rb)) goto exit;
  1033. }
  1034. /////////////////////////////////////////////////////////////////////////
  1035. // Axis = A0xB1
  1036. /////////////////////////////////////////////////////////////////////////
  1037. Vector3::Cross_Product(context.A[0],context.B[1],&context.TestAxis);
  1038. context.TestAxisId = AXIS_A0B1;
  1039. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1040. ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][1]);
  1041. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][0]);
  1042. if (obb_check_axis(context,ra,rb)) goto exit;
  1043. }
  1044. /////////////////////////////////////////////////////////////////////////
  1045. // Axis = A0xB2
  1046. /////////////////////////////////////////////////////////////////////////
  1047. Vector3::Cross_Product(context.A[0],context.B[2],&context.TestAxis);
  1048. context.TestAxisId = AXIS_A0B2;
  1049. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1050. ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][2]);
  1051. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][0]);
  1052. if (obb_check_axis(context,ra,rb)) goto exit;
  1053. }
  1054. /////////////////////////////////////////////////////////////////////////
  1055. // Axis = A1xB0
  1056. /////////////////////////////////////////////////////////////////////////
  1057. Vector3::Cross_Product(context.A[1],context.B[0],&context.TestAxis);
  1058. context.TestAxisId = AXIS_A1B0;
  1059. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1060. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][0]);
  1061. rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][1]);
  1062. if (obb_check_axis(context,ra,rb)) goto exit;
  1063. }
  1064. /////////////////////////////////////////////////////////////////////////
  1065. // Axis = A1xB1
  1066. /////////////////////////////////////////////////////////////////////////
  1067. Vector3::Cross_Product(context.A[1],context.B[1],&context.TestAxis);
  1068. context.TestAxisId = AXIS_A1B1;
  1069. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1070. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][1]);
  1071. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][0]);
  1072. if (obb_check_axis(context,ra,rb)) goto exit;
  1073. }
  1074. /////////////////////////////////////////////////////////////////////////
  1075. // Axis = A1xB2
  1076. /////////////////////////////////////////////////////////////////////////
  1077. Vector3::Cross_Product(context.A[1],context.B[2],&context.TestAxis);
  1078. context.TestAxisId = AXIS_A1B2;
  1079. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1080. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][2]);
  1081. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][0]);
  1082. if (obb_check_axis(context,ra,rb)) goto exit;
  1083. }
  1084. /////////////////////////////////////////////////////////////////////////
  1085. // Axis = A2xB0
  1086. /////////////////////////////////////////////////////////////////////////
  1087. Vector3::Cross_Product(context.A[2],context.B[0],&context.TestAxis);
  1088. context.TestAxisId = AXIS_A2B0;
  1089. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1090. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][0])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][0]);
  1091. rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][1]);
  1092. if (obb_check_axis(context,ra,rb)) goto exit;
  1093. }
  1094. /////////////////////////////////////////////////////////////////////////
  1095. // Axis = A2xB1
  1096. /////////////////////////////////////////////////////////////////////////
  1097. Vector3::Cross_Product(context.A[2],context.B[1],&context.TestAxis);
  1098. context.TestAxisId = AXIS_A2B1;
  1099. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1100. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][1]);
  1101. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][0]);
  1102. if (obb_check_axis(context,ra,rb)) goto exit;
  1103. }
  1104. /////////////////////////////////////////////////////////////////////////
  1105. // Axis = A2xB2
  1106. /////////////////////////////////////////////////////////////////////////
  1107. Vector3::Cross_Product(context.A[2],context.B[2],&context.TestAxis);
  1108. context.TestAxisId = AXIS_A2B2;
  1109. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1110. ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][2]);
  1111. rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][0]);
  1112. if (obb_check_axis(context,ra,rb)) goto exit;
  1113. }
  1114. if (!result->StartBad) {
  1115. context.TestAxisId = context.AxisId;
  1116. /////////////////////////////////////////////////////////////////////////
  1117. // Final three checks are for eliminating false collisions
  1118. // Axis = A0xMove
  1119. /////////////////////////////////////////////////////////////////////////
  1120. Vector3::Cross_Product(context.A[0],context.Move0,&context.TestAxis);
  1121. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1122. obb_compute_projections(context,&ra,&rb);
  1123. if (obb_check_axis(context,ra,rb)) goto exit;
  1124. }
  1125. /////////////////////////////////////////////////////////////////////////
  1126. // Axis = A1xMove
  1127. /////////////////////////////////////////////////////////////////////////
  1128. Vector3::Cross_Product(context.A[1],context.Move0,&context.TestAxis);
  1129. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1130. obb_compute_projections(context,&ra,&rb);
  1131. if (obb_check_axis(context,ra,rb)) goto exit;
  1132. }
  1133. /////////////////////////////////////////////////////////////////////////
  1134. // Axis = A2xMove
  1135. /////////////////////////////////////////////////////////////////////////
  1136. Vector3::Cross_Product(context.A[2],context.Move0,&context.TestAxis);
  1137. if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
  1138. obb_compute_projections(context,&ra,&rb);
  1139. if (obb_check_axis(context,ra,rb)) goto exit;
  1140. }
  1141. }
  1142. exit:
  1143. if (context.StartBad) {
  1144. result->StartBad = true;
  1145. result->Fraction = 0.0f;
  1146. return true;
  1147. }
  1148. /*
  1149. ** If our fraction is smaller, override the previous
  1150. ** values because our collision occured first.
  1151. */
  1152. if (context.MaxFrac < result->Fraction) {
  1153. result->Fraction = context.MaxFrac;
  1154. compute_contact_normal(context,result);
  1155. if (result->ComputeContactPoint) {
  1156. compute_contact_point(context,result);
  1157. }
  1158. return true;
  1159. }
  1160. return false;
  1161. }
  1162. /***********************************************************************************************
  1163. * CollisionMath::Collide -- collide two obb's *
  1164. * *
  1165. * INPUT: *
  1166. * *
  1167. * OUTPUT: *
  1168. * *
  1169. * WARNINGS: *
  1170. * *
  1171. * HISTORY: *
  1172. * 4/8/99 GTH : Created. *
  1173. *=============================================================================================*/
  1174. bool CollisionMath::Collide
  1175. (
  1176. const OBBoxClass & box0,
  1177. const Vector3 & move0,
  1178. const OBBoxClass & box1,
  1179. const Vector3 & move1,
  1180. CastResultStruct * result
  1181. )
  1182. {
  1183. ObbCollisionStruct context(box0,move0,box1,move1);
  1184. return collide_obb_obb(context,result);
  1185. }
  1186. /***********************************************************************************************
  1187. * CollisionMath::Collide -- collide an OBB with an AAB *
  1188. * *
  1189. * INPUT: *
  1190. * *
  1191. * OUTPUT: *
  1192. * *
  1193. * WARNINGS: *
  1194. * *
  1195. * HISTORY: *
  1196. * 5/25/99 GTH : Created. *
  1197. *=============================================================================================*/
  1198. bool CollisionMath::Collide
  1199. (
  1200. const OBBoxClass & box0,
  1201. const Vector3 & move0,
  1202. const AABoxClass & box1,
  1203. const Vector3 & move1,
  1204. CastResultStruct * result
  1205. )
  1206. {
  1207. OBBoxClass obbox1(box1.Center,box1.Extent);
  1208. ObbCollisionStruct context(box0,move0,obbox1,move1);
  1209. return collide_obb_obb(context,result);
  1210. }
  1211. /***********************************************************************************************
  1212. * CollisionMath::Collide -- collide an AAB with an OBB *
  1213. * *
  1214. * INPUT: *
  1215. * *
  1216. * OUTPUT: *
  1217. * *
  1218. * WARNINGS: *
  1219. * *
  1220. * HISTORY: *
  1221. * 5/25/99 GTH : Created. *
  1222. *=============================================================================================*/
  1223. bool CollisionMath::Collide
  1224. (
  1225. const AABoxClass & box0,
  1226. const Vector3 & move0,
  1227. const OBBoxClass & box1,
  1228. const Vector3 & move1,
  1229. CastResultStruct * result
  1230. )
  1231. {
  1232. OBBoxClass obbox0(box0.Center,box0.Extent);
  1233. ObbCollisionStruct context(obbox0,move0,box1,move1);
  1234. return collide_obb_obb(context,result);
  1235. }