2
0

collision_trimesh_box.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  1. /*************************************************************************
  2. * *
  3. * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
  4. * All rights reserved. Email: [email protected] Web: www.q12.org *
  5. * *
  6. * This library is free software; you can redistribute it and/or *
  7. * modify it under the terms of EITHER: *
  8. * (1) The GNU Lesser General Public License as published by the Free *
  9. * Software Foundation; either version 2.1 of the License, or (at *
  10. * your option) any later version. The text of the GNU Lesser *
  11. * General Public License is included with this library in the *
  12. * file LICENSE.TXT. *
  13. * (2) The BSD-style license that is included with this library in *
  14. * the file LICENSE-BSD.TXT. *
  15. * *
  16. * This library is distributed in the hope that it will be useful, *
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
  19. * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
  20. * *
  21. *************************************************************************/
  22. /*************************************************************************
  23. * *
  24. * Triangle-box collider by Alen Ladavac and Vedran Klanac. *
  25. * Ported to ODE by Oskari Nyman. *
  26. * *
  27. *************************************************************************/
  28. #include <ode/collision.h>
  29. #include <ode/matrix.h>
  30. #include <ode/rotation.h>
  31. #include <ode/odemath.h>
  32. #include "collision_util.h"
  33. #include "collision_trimesh_internal.h"
  34. #if dTRIMESH_ENABLED
  35. static void
  36. GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride,
  37. dxGeom* in_g1, dxGeom* in_g2,
  38. const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth,
  39. int& OutTriCount);
  40. // largest number, double or float
  41. #if defined(dSINGLE)
  42. #define MAXVALUE FLT_MAX
  43. #else
  44. #define MAXVALUE DBL_MAX
  45. #endif
  46. // dVector3
  47. // r=a-b
  48. #define SUBTRACT(a,b,r) do{ \
  49. (r)[0]=(a)[0] - (b)[0]; \
  50. (r)[1]=(a)[1] - (b)[1]; \
  51. (r)[2]=(a)[2] - (b)[2]; }while(0)
  52. // dVector3
  53. // a=b
  54. #define SET(a,b) do{ \
  55. (a)[0]=(b)[0]; \
  56. (a)[1]=(b)[1]; \
  57. (a)[2]=(b)[2]; }while(0)
  58. // dMatrix3
  59. // a=b
  60. #define SETM(a,b) do{ \
  61. (a)[0]=(b)[0]; \
  62. (a)[1]=(b)[1]; \
  63. (a)[2]=(b)[2]; \
  64. (a)[3]=(b)[3]; \
  65. (a)[4]=(b)[4]; \
  66. (a)[5]=(b)[5]; \
  67. (a)[6]=(b)[6]; \
  68. (a)[7]=(b)[7]; \
  69. (a)[8]=(b)[8]; \
  70. (a)[9]=(b)[9]; \
  71. (a)[10]=(b)[10]; \
  72. (a)[11]=(b)[11]; }while(0)
  73. // dVector3
  74. // r=a+b
  75. #define ADD(a,b,r) do{ \
  76. (r)[0]=(a)[0] + (b)[0]; \
  77. (r)[1]=(a)[1] + (b)[1]; \
  78. (r)[2]=(a)[2] + (b)[2]; }while(0)
  79. // dMatrix3, int, dVector3
  80. // v=column a from m
  81. #define GETCOL(m,a,v) do{ \
  82. (v)[0]=(m)[(a)+0]; \
  83. (v)[1]=(m)[(a)+4]; \
  84. (v)[2]=(m)[(a)+8]; }while(0)
  85. // dVector4, dVector3
  86. // distance between plane p and point v
  87. #define POINTDISTANCE(p,v) \
  88. ( p[0]*v[0] + p[1]*v[1] + p[2]*v[2] + p[3] )
  89. // dVector4, dVector3, dReal
  90. // construct plane from normal and d
  91. #define CONSTRUCTPLANE(plane,normal,d) do{ \
  92. plane[0]=normal[0];\
  93. plane[1]=normal[1];\
  94. plane[2]=normal[2];\
  95. plane[3]=d; }while(0)
  96. // dVector3
  97. // length of vector a
  98. #define LENGTHOF(a) \
  99. dSqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2])
  100. struct sTrimeshBoxColliderData
  101. {
  102. sTrimeshBoxColliderData(): m_iBestAxis(0), m_iExitAxis(0), m_ctContacts(0) {}
  103. void SetupInitialContext(dxTriMesh *TriMesh, dxGeom *BoxGeom,
  104. int Flags, dContactGeom* Contacts, int Stride);
  105. int TestCollisionForSingleTriangle(int ctContacts0, int Triint,
  106. dVector3 dv[3], bool &bOutFinishSearching);
  107. bool _cldTestNormal(dReal fp0, dReal fR, dVector3 vNormal, int iAxis);
  108. bool _cldTestFace(dReal fp0, dReal fp1, dReal fp2, dReal fR, dReal fD,
  109. dVector3 vNormal, int iAxis);
  110. bool _cldTestEdge(dReal fp0, dReal fp1, dReal fR, dReal fD,
  111. dVector3 vNormal, int iAxis);
  112. bool _cldTestSeparatingAxes(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2);
  113. void _cldClipping(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2);
  114. void _cldTestOneTriangle(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2);
  115. // box data
  116. dMatrix3 m_mHullBoxRot;
  117. dVector3 m_vHullBoxPos;
  118. dVector3 m_vBoxHalfSize;
  119. // mesh data
  120. dVector3 m_vHullDstPos;
  121. // global collider data
  122. dVector3 m_vBestNormal;
  123. dReal m_fBestDepth;
  124. int m_iBestAxis;
  125. int m_iExitAxis;
  126. dVector3 m_vE0, m_vE1, m_vE2, m_vN;
  127. // global info for contact creation
  128. int m_iFlags;
  129. dContactGeom *m_ContactGeoms;
  130. int m_iStride;
  131. dxGeom *m_Geom1;
  132. dxGeom *m_Geom2;
  133. int m_ctContacts;
  134. };
  135. // Test normal of mesh face as separating axis for intersection
  136. bool sTrimeshBoxColliderData::_cldTestNormal(dReal fp0, dReal fR, dVector3 vNormal, int iAxis)
  137. {
  138. // calculate overlapping interval of box and triangle
  139. dReal fDepth = fR+fp0;
  140. // if we do not overlap
  141. if ( fDepth<0 ) {
  142. // do nothing
  143. return false;
  144. }
  145. // calculate normal's length
  146. dReal fLength = LENGTHOF(vNormal);
  147. // if long enough
  148. if ( fLength > 0.0f ) {
  149. dReal fOneOverLength = 1.0f/fLength;
  150. // normalize depth
  151. fDepth = fDepth*fOneOverLength;
  152. // get minimum depth
  153. if (fDepth < m_fBestDepth) {
  154. m_vBestNormal[0] = -vNormal[0]*fOneOverLength;
  155. m_vBestNormal[1] = -vNormal[1]*fOneOverLength;
  156. m_vBestNormal[2] = -vNormal[2]*fOneOverLength;
  157. m_iBestAxis = iAxis;
  158. //dAASSERT(fDepth>=0);
  159. m_fBestDepth = fDepth;
  160. }
  161. }
  162. return true;
  163. }
  164. // Test box axis as separating axis
  165. bool sTrimeshBoxColliderData::_cldTestFace(dReal fp0, dReal fp1, dReal fp2, dReal fR, dReal fD,
  166. dVector3 vNormal, int iAxis)
  167. {
  168. dReal fMin, fMax;
  169. // find min of triangle interval
  170. if ( fp0 < fp1 ) {
  171. if ( fp0 < fp2 ) {
  172. fMin = fp0;
  173. } else {
  174. fMin = fp2;
  175. }
  176. } else {
  177. if( fp1 < fp2 ) {
  178. fMin = fp1;
  179. } else {
  180. fMin = fp2;
  181. }
  182. }
  183. // find max of triangle interval
  184. if ( fp0 > fp1 ) {
  185. if ( fp0 > fp2 ) {
  186. fMax = fp0;
  187. } else {
  188. fMax = fp2;
  189. }
  190. } else {
  191. if( fp1 > fp2 ) {
  192. fMax = fp1;
  193. } else {
  194. fMax = fp2;
  195. }
  196. }
  197. // calculate minimum and maximum depth
  198. dReal fDepthMin = fR - fMin;
  199. dReal fDepthMax = fMax + fR;
  200. // if we dont't have overlapping interval
  201. if ( fDepthMin < 0 || fDepthMax < 0 ) {
  202. // do nothing
  203. return false;
  204. }
  205. dReal fDepth = 0;
  206. // if greater depth is on negative side
  207. if ( fDepthMin > fDepthMax ) {
  208. // use smaller depth (one from positive side)
  209. fDepth = fDepthMax;
  210. // flip normal direction
  211. vNormal[0] = -vNormal[0];
  212. vNormal[1] = -vNormal[1];
  213. vNormal[2] = -vNormal[2];
  214. fD = -fD;
  215. // if greater depth is on positive side
  216. } else {
  217. // use smaller depth (one from negative side)
  218. fDepth = fDepthMin;
  219. }
  220. // if lower depth than best found so far
  221. if (fDepth < m_fBestDepth) {
  222. // remember current axis as best axis
  223. m_vBestNormal[0] = vNormal[0];
  224. m_vBestNormal[1] = vNormal[1];
  225. m_vBestNormal[2] = vNormal[2];
  226. m_iBestAxis = iAxis;
  227. //dAASSERT(fDepth>=0);
  228. m_fBestDepth = fDepth;
  229. }
  230. return true;
  231. }
  232. // Test cross products of box axis and triangle edges as separating axis
  233. bool sTrimeshBoxColliderData::_cldTestEdge(dReal fp0, dReal fp1, dReal fR, dReal fD,
  234. dVector3 vNormal, int iAxis)
  235. {
  236. dReal fMin, fMax;
  237. // ===== Begin Patch by Francisco Leon, 2006/10/28 =====
  238. // Fixed Null Normal. This prevents boxes passing
  239. // through trimeshes at certain contact angles
  240. fMin = vNormal[0] * vNormal[0] +
  241. vNormal[1] * vNormal[1] +
  242. vNormal[2] * vNormal[2];
  243. if ( fMin <= dEpsilon ) /// THIS NORMAL WOULD BE DANGEROUS
  244. return true;
  245. // ===== Ending Patch by Francisco Leon =====
  246. // calculate min and max interval values
  247. if ( fp0 < fp1 ) {
  248. fMin = fp0;
  249. fMax = fp1;
  250. } else {
  251. fMin = fp1;
  252. fMax = fp0;
  253. }
  254. // check if we overlapp
  255. dReal fDepthMin = fR - fMin;
  256. dReal fDepthMax = fMax + fR;
  257. // if we don't overlapp
  258. if ( fDepthMin < 0 || fDepthMax < 0 ) {
  259. // do nothing
  260. return false;
  261. }
  262. dReal fDepth;
  263. // if greater depth is on negative side
  264. if ( fDepthMin > fDepthMax ) {
  265. // use smaller depth (one from positive side)
  266. fDepth = fDepthMax;
  267. // flip normal direction
  268. vNormal[0] = -vNormal[0];
  269. vNormal[1] = -vNormal[1];
  270. vNormal[2] = -vNormal[2];
  271. fD = -fD;
  272. // if greater depth is on positive side
  273. } else {
  274. // use smaller depth (one from negative side)
  275. fDepth = fDepthMin;
  276. }
  277. // calculate normal's length
  278. dReal fLength = LENGTHOF(vNormal);
  279. // if long enough
  280. if ( fLength > 0.0f ) {
  281. // normalize depth
  282. dReal fOneOverLength = 1.0f/fLength;
  283. fDepth = fDepth*fOneOverLength;
  284. fD*=fOneOverLength;
  285. // if lower depth than best found so far (favor face over edges)
  286. if (fDepth*1.5f < m_fBestDepth) {
  287. // remember current axis as best axis
  288. m_vBestNormal[0] = vNormal[0]*fOneOverLength;
  289. m_vBestNormal[1] = vNormal[1]*fOneOverLength;
  290. m_vBestNormal[2] = vNormal[2]*fOneOverLength;
  291. m_iBestAxis = iAxis;
  292. //dAASSERT(fDepth>=0);
  293. m_fBestDepth = fDepth;
  294. }
  295. }
  296. return true;
  297. }
  298. // clip polygon with plane and generate new polygon points
  299. static void _cldClipPolyToPlane( dVector3 avArrayIn[], int ctIn,
  300. dVector3 avArrayOut[], int &ctOut,
  301. const dVector4 &plPlane )
  302. {
  303. // start with no output points
  304. ctOut = 0;
  305. int i0 = ctIn-1;
  306. // for each edge in input polygon
  307. for (int i1=0; i1<ctIn; i0=i1, i1++) {
  308. // calculate distance of edge points to plane
  309. dReal fDistance0 = POINTDISTANCE( plPlane ,avArrayIn[i0] );
  310. dReal fDistance1 = POINTDISTANCE( plPlane ,avArrayIn[i1] );
  311. // if first point is in front of plane
  312. if( fDistance0 >= 0 ) {
  313. // emit point
  314. avArrayOut[ctOut][0] = avArrayIn[i0][0];
  315. avArrayOut[ctOut][1] = avArrayIn[i0][1];
  316. avArrayOut[ctOut][2] = avArrayIn[i0][2];
  317. ctOut++;
  318. }
  319. // if points are on different sides
  320. if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) {
  321. // find intersection point of edge and plane
  322. dVector3 vIntersectionPoint;
  323. vIntersectionPoint[0]= avArrayIn[i0][0] - (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1);
  324. vIntersectionPoint[1]= avArrayIn[i0][1] - (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1);
  325. vIntersectionPoint[2]= avArrayIn[i0][2] - (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1);
  326. // emit intersection point
  327. avArrayOut[ctOut][0] = vIntersectionPoint[0];
  328. avArrayOut[ctOut][1] = vIntersectionPoint[1];
  329. avArrayOut[ctOut][2] = vIntersectionPoint[2];
  330. ctOut++;
  331. }
  332. }
  333. }
  334. bool sTrimeshBoxColliderData::_cldTestSeparatingAxes(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) {
  335. // reset best axis
  336. m_iBestAxis = 0;
  337. m_iExitAxis = -1;
  338. m_fBestDepth = MAXVALUE;
  339. // calculate edges
  340. SUBTRACT(v1,v0,m_vE0);
  341. SUBTRACT(v2,v0,m_vE1);
  342. SUBTRACT(m_vE1,m_vE0,m_vE2);
  343. // calculate poly normal
  344. dCROSS(m_vN,=,m_vE0,m_vE1);
  345. // calculate length of face normal
  346. dReal fNLen = LENGTHOF(m_vN);
  347. // Even though all triangles might be initially valid,
  348. // a triangle may degenerate into a segment after applying
  349. // space transformation.
  350. if (!fNLen) {
  351. return false;
  352. }
  353. // extract box axes as vectors
  354. dVector3 vA0,vA1,vA2;
  355. GETCOL(m_mHullBoxRot,0,vA0);
  356. GETCOL(m_mHullBoxRot,1,vA1);
  357. GETCOL(m_mHullBoxRot,2,vA2);
  358. // box halfsizes
  359. dReal fa0 = m_vBoxHalfSize[0];
  360. dReal fa1 = m_vBoxHalfSize[1];
  361. dReal fa2 = m_vBoxHalfSize[2];
  362. // calculate relative position between box and triangle
  363. dVector3 vD;
  364. SUBTRACT(v0,m_vHullBoxPos,vD);
  365. dVector3 vL;
  366. dReal fp0, fp1, fp2, fR, fD;
  367. // Test separating axes for intersection
  368. // ************************************************
  369. // Axis 1 - Triangle Normal
  370. SET(vL,m_vN);
  371. fp0 = dDOT(vL,vD);
  372. fp1 = fp0;
  373. fp2 = fp0;
  374. fR=fa0*dFabs( dDOT(m_vN,vA0) ) + fa1 * dFabs( dDOT(m_vN,vA1) ) + fa2 * dFabs( dDOT(m_vN,vA2) );
  375. if (!_cldTestNormal(fp0, fR, vL, 1)) {
  376. m_iExitAxis=1;
  377. return false;
  378. }
  379. // ************************************************
  380. // Test Faces
  381. // ************************************************
  382. // Axis 2 - Box X-Axis
  383. SET(vL,vA0);
  384. fD = dDOT(vL,m_vN)/fNLen;
  385. fp0 = dDOT(vL,vD);
  386. fp1 = fp0 + dDOT(vA0,m_vE0);
  387. fp2 = fp0 + dDOT(vA0,m_vE1);
  388. fR = fa0;
  389. if (!_cldTestFace(fp0, fp1, fp2, fR, fD, vL, 2)) {
  390. m_iExitAxis=2;
  391. return false;
  392. }
  393. // ************************************************
  394. // ************************************************
  395. // Axis 3 - Box Y-Axis
  396. SET(vL,vA1);
  397. fD = dDOT(vL,m_vN)/fNLen;
  398. fp0 = dDOT(vL,vD);
  399. fp1 = fp0 + dDOT(vA1,m_vE0);
  400. fp2 = fp0 + dDOT(vA1,m_vE1);
  401. fR = fa1;
  402. if (!_cldTestFace(fp0, fp1, fp2, fR, fD, vL, 3)) {
  403. m_iExitAxis=3;
  404. return false;
  405. }
  406. // ************************************************
  407. // ************************************************
  408. // Axis 4 - Box Z-Axis
  409. SET(vL,vA2);
  410. fD = dDOT(vL,m_vN)/fNLen;
  411. fp0 = dDOT(vL,vD);
  412. fp1 = fp0 + dDOT(vA2,m_vE0);
  413. fp2 = fp0 + dDOT(vA2,m_vE1);
  414. fR = fa2;
  415. if (!_cldTestFace(fp0, fp1, fp2, fR, fD, vL, 4)) {
  416. m_iExitAxis=4;
  417. return false;
  418. }
  419. // ************************************************
  420. // Test Edges
  421. // ************************************************
  422. // Axis 5 - Box X-Axis cross Edge0
  423. dCROSS(vL,=,vA0,m_vE0);
  424. fD = dDOT(vL,m_vN)/fNLen;
  425. fp0 = dDOT(vL,vD);
  426. fp1 = fp0;
  427. fp2 = fp0 + dDOT(vA0,m_vN);
  428. fR = fa1 * dFabs(dDOT(vA2,m_vE0)) + fa2 * dFabs(dDOT(vA1,m_vE0));
  429. if (!_cldTestEdge(fp1, fp2, fR, fD, vL, 5)) {
  430. m_iExitAxis=5;
  431. return false;
  432. }
  433. // ************************************************
  434. // ************************************************
  435. // Axis 6 - Box X-Axis cross Edge1
  436. dCROSS(vL,=,vA0,m_vE1);
  437. fD = dDOT(vL,m_vN)/fNLen;
  438. fp0 = dDOT(vL,vD);
  439. fp1 = fp0 - dDOT(vA0,m_vN);
  440. fp2 = fp0;
  441. fR = fa1 * dFabs(dDOT(vA2,m_vE1)) + fa2 * dFabs(dDOT(vA1,m_vE1));
  442. if (!_cldTestEdge(fp0, fp1, fR, fD, vL, 6)) {
  443. m_iExitAxis=6;
  444. return false;
  445. }
  446. // ************************************************
  447. // ************************************************
  448. // Axis 7 - Box X-Axis cross Edge2
  449. dCROSS(vL,=,vA0,m_vE2);
  450. fD = dDOT(vL,m_vN)/fNLen;
  451. fp0 = dDOT(vL,vD);
  452. fp1 = fp0 - dDOT(vA0,m_vN);
  453. fp2 = fp0 - dDOT(vA0,m_vN);
  454. fR = fa1 * dFabs(dDOT(vA2,m_vE2)) + fa2 * dFabs(dDOT(vA1,m_vE2));
  455. if (!_cldTestEdge(fp0, fp1, fR, fD, vL, 7)) {
  456. m_iExitAxis=7;
  457. return false;
  458. }
  459. // ************************************************
  460. // ************************************************
  461. // Axis 8 - Box Y-Axis cross Edge0
  462. dCROSS(vL,=,vA1,m_vE0);
  463. fD = dDOT(vL,m_vN)/fNLen;
  464. fp0 = dDOT(vL,vD);
  465. fp1 = fp0;
  466. fp2 = fp0 + dDOT(vA1,m_vN);
  467. fR = fa0 * dFabs(dDOT(vA2,m_vE0)) + fa2 * dFabs(dDOT(vA0,m_vE0));
  468. if (!_cldTestEdge(fp0, fp2, fR, fD, vL, 8)) {
  469. m_iExitAxis=8;
  470. return false;
  471. }
  472. // ************************************************
  473. // ************************************************
  474. // Axis 9 - Box Y-Axis cross Edge1
  475. dCROSS(vL,=,vA1,m_vE1);
  476. fD = dDOT(vL,m_vN)/fNLen;
  477. fp0 = dDOT(vL,vD);
  478. fp1 = fp0 - dDOT(vA1,m_vN);
  479. fp2 = fp0;
  480. fR = fa0 * dFabs(dDOT(vA2,m_vE1)) + fa2 * dFabs(dDOT(vA0,m_vE1));
  481. if (!_cldTestEdge(fp0, fp1, fR, fD, vL, 9)) {
  482. m_iExitAxis=9;
  483. return false;
  484. }
  485. // ************************************************
  486. // ************************************************
  487. // Axis 10 - Box Y-Axis cross Edge2
  488. dCROSS(vL,=,vA1,m_vE2);
  489. fD = dDOT(vL,m_vN)/fNLen;
  490. fp0 = dDOT(vL,vD);
  491. fp1 = fp0 - dDOT(vA1,m_vN);
  492. fp2 = fp0 - dDOT(vA1,m_vN);
  493. fR = fa0 * dFabs(dDOT(vA2,m_vE2)) + fa2 * dFabs(dDOT(vA0,m_vE2));
  494. if (!_cldTestEdge(fp0, fp1, fR, fD, vL, 10)) {
  495. m_iExitAxis=10;
  496. return false;
  497. }
  498. // ************************************************
  499. // ************************************************
  500. // Axis 11 - Box Z-Axis cross Edge0
  501. dCROSS(vL,=,vA2,m_vE0);
  502. fD = dDOT(vL,m_vN)/fNLen;
  503. fp0 = dDOT(vL,vD);
  504. fp1 = fp0;
  505. fp2 = fp0 + dDOT(vA2,m_vN);
  506. fR = fa0 * dFabs(dDOT(vA1,m_vE0)) + fa1 * dFabs(dDOT(vA0,m_vE0));
  507. if (!_cldTestEdge(fp0, fp2, fR, fD, vL, 11)) {
  508. m_iExitAxis=11;
  509. return false;
  510. }
  511. // ************************************************
  512. // ************************************************
  513. // Axis 12 - Box Z-Axis cross Edge1
  514. dCROSS(vL,=,vA2,m_vE1);
  515. fD = dDOT(vL,m_vN)/fNLen;
  516. fp0 = dDOT(vL,vD);
  517. fp1 = fp0 - dDOT(vA2,m_vN);
  518. fp2 = fp0;
  519. fR = fa0 * dFabs(dDOT(vA1,m_vE1)) + fa1 * dFabs(dDOT(vA0,m_vE1));
  520. if (!_cldTestEdge(fp0, fp1, fR, fD, vL, 12)) {
  521. m_iExitAxis=12;
  522. return false;
  523. }
  524. // ************************************************
  525. // ************************************************
  526. // Axis 13 - Box Z-Axis cross Edge2
  527. dCROSS(vL,=,vA2,m_vE2);
  528. fD = dDOT(vL,m_vN)/fNLen;
  529. fp0 = dDOT(vL,vD);
  530. fp1 = fp0 - dDOT(vA2,m_vN);
  531. fp2 = fp0 - dDOT(vA2,m_vN);
  532. fR = fa0 * dFabs(dDOT(vA1,m_vE2)) + fa1 * dFabs(dDOT(vA0,m_vE2));
  533. if (!_cldTestEdge(fp0, fp1, fR, fD, vL, 13)) {
  534. m_iExitAxis=13;
  535. return false;
  536. }
  537. // ************************************************
  538. return true;
  539. }
  540. // find two closest points on two lines
  541. static bool _cldClosestPointOnTwoLines( dVector3 vPoint1, dVector3 vLenVec1,
  542. dVector3 vPoint2, dVector3 vLenVec2,
  543. dReal &fvalue1, dReal &fvalue2)
  544. {
  545. // calculate denominator
  546. dVector3 vp;
  547. SUBTRACT(vPoint2,vPoint1,vp);
  548. dReal fuaub = dDOT(vLenVec1,vLenVec2);
  549. dReal fq1 = dDOT(vLenVec1,vp);
  550. dReal fq2 = -dDOT(vLenVec2,vp);
  551. dReal fd = 1.0f - fuaub * fuaub;
  552. // if denominator is positive
  553. if (fd > 0.0f) {
  554. // calculate points of closest approach
  555. fd = 1.0f/fd;
  556. fvalue1 = (fq1 + fuaub*fq2)*fd;
  557. fvalue2 = (fuaub*fq1 + fq2)*fd;
  558. return true;
  559. // otherwise
  560. } else {
  561. // lines are parallel
  562. fvalue1 = 0.0f;
  563. fvalue2 = 0.0f;
  564. return false;
  565. }
  566. }
  567. // clip and generate contacts
  568. void sTrimeshBoxColliderData::_cldClipping(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) {
  569. dIASSERT( !(m_iFlags & CONTACTS_UNIMPORTANT) || m_ctContacts < (m_iFlags & NUMC_MASK) ); // Do not call the function if there is no room to store results
  570. // if we have edge/edge intersection
  571. if (m_iBestAxis > 4 ) {
  572. dVector3 vub,vPb,vPa;
  573. SET(vPa,m_vHullBoxPos);
  574. // calculate point on box edge
  575. for( int i=0; i<3; i++) {
  576. dVector3 vRotCol;
  577. GETCOL(m_mHullBoxRot,i,vRotCol);
  578. dReal fSign = dDOT(m_vBestNormal,vRotCol) > 0 ? 1.0f : -1.0f;
  579. vPa[0] += fSign * m_vBoxHalfSize[i] * vRotCol[0];
  580. vPa[1] += fSign * m_vBoxHalfSize[i] * vRotCol[1];
  581. vPa[2] += fSign * m_vBoxHalfSize[i] * vRotCol[2];
  582. }
  583. int iEdge = (m_iBestAxis-5)%3;
  584. // decide which edge is on triangle
  585. if ( iEdge == 0 ) {
  586. SET(vPb,v0);
  587. SET(vub,m_vE0);
  588. } else if ( iEdge == 1) {
  589. SET(vPb,v2);
  590. SET(vub,m_vE1);
  591. } else {
  592. SET(vPb,v1);
  593. SET(vub,m_vE2);
  594. }
  595. // setup direction parameter for face edge
  596. dNormalize3(vub);
  597. dReal fParam1, fParam2;
  598. // setup direction parameter for box edge
  599. dVector3 vua;
  600. int col=(m_iBestAxis-5)/3;
  601. GETCOL(m_mHullBoxRot,col,vua);
  602. // find two closest points on both edges
  603. _cldClosestPointOnTwoLines( vPa, vua, vPb, vub, fParam1, fParam2 );
  604. vPa[0] += vua[0]*fParam1;
  605. vPa[1] += vua[1]*fParam1;
  606. vPa[2] += vua[2]*fParam1;
  607. vPb[0] += vub[0]*fParam2;
  608. vPb[1] += vub[1]*fParam2;
  609. vPb[2] += vub[2]*fParam2;
  610. // calculate collision point
  611. dVector3 vPntTmp;
  612. ADD(vPa,vPb,vPntTmp);
  613. vPntTmp[0]*=0.5f;
  614. vPntTmp[1]*=0.5f;
  615. vPntTmp[2]*=0.5f;
  616. // generate contact point between two closest points
  617. #if 0 //#ifdef ORIG -- if to use conditional define, GenerateContact must be moved into #else
  618. dContactGeom* Contact = SAFECONTACT(m_iFlags, m_ContactGeoms, m_ctContacts, m_iStride);
  619. Contact->depth = m_fBestDepth;
  620. SET(Contact->normal,m_vBestNormal);
  621. SET(Contact->pos,vPntTmp);
  622. Contact->g1 = Geom1;
  623. Contact->g2 = Geom2;
  624. m_ctContacts++;
  625. #endif
  626. GenerateContact(m_iFlags, m_ContactGeoms, m_iStride, m_Geom1, m_Geom2,
  627. vPntTmp, m_vBestNormal, m_fBestDepth, m_ctContacts);
  628. // if triangle is the referent face then clip box to triangle face
  629. } else if (m_iBestAxis == 1) {
  630. dVector3 vNormal2;
  631. vNormal2[0]=-m_vBestNormal[0];
  632. vNormal2[1]=-m_vBestNormal[1];
  633. vNormal2[2]=-m_vBestNormal[2];
  634. // vNr is normal in box frame, pointing from triangle to box
  635. dMatrix3 mTransposed;
  636. mTransposed[0*4+0]=m_mHullBoxRot[0*4+0];
  637. mTransposed[0*4+1]=m_mHullBoxRot[1*4+0];
  638. mTransposed[0*4+2]=m_mHullBoxRot[2*4+0];
  639. mTransposed[1*4+0]=m_mHullBoxRot[0*4+1];
  640. mTransposed[1*4+1]=m_mHullBoxRot[1*4+1];
  641. mTransposed[1*4+2]=m_mHullBoxRot[2*4+1];
  642. mTransposed[2*4+0]=m_mHullBoxRot[0*4+2];
  643. mTransposed[2*4+1]=m_mHullBoxRot[1*4+2];
  644. mTransposed[2*4+2]=m_mHullBoxRot[2*4+2];
  645. dVector3 vNr;
  646. vNr[0]=mTransposed[0*4+0]*vNormal2[0]+ mTransposed[0*4+1]*vNormal2[1]+ mTransposed[0*4+2]*vNormal2[2];
  647. vNr[1]=mTransposed[1*4+0]*vNormal2[0]+ mTransposed[1*4+1]*vNormal2[1]+ mTransposed[1*4+2]*vNormal2[2];
  648. vNr[2]=mTransposed[2*4+0]*vNormal2[0]+ mTransposed[2*4+1]*vNormal2[1]+ mTransposed[2*4+2]*vNormal2[2];
  649. dVector3 vAbsNormal;
  650. vAbsNormal[0] = dFabs( vNr[0] );
  651. vAbsNormal[1] = dFabs( vNr[1] );
  652. vAbsNormal[2] = dFabs( vNr[2] );
  653. // get closest face from box
  654. int iB0, iB1, iB2;
  655. if (vAbsNormal[1] > vAbsNormal[0]) {
  656. if (vAbsNormal[1] > vAbsNormal[2]) {
  657. iB1 = 0; iB0 = 1; iB2 = 2;
  658. } else {
  659. iB1 = 0; iB2 = 1; iB0 = 2;
  660. }
  661. } else {
  662. if (vAbsNormal[0] > vAbsNormal[2]) {
  663. iB0 = 0; iB1 = 1; iB2 = 2;
  664. } else {
  665. iB1 = 0; iB2 = 1; iB0 = 2;
  666. }
  667. }
  668. // Here find center of box face we are going to project
  669. dVector3 vCenter;
  670. dVector3 vRotCol;
  671. GETCOL(m_mHullBoxRot,iB0,vRotCol);
  672. if (vNr[iB0] > 0) {
  673. vCenter[0] = m_vHullBoxPos[0] - v0[0] - m_vBoxHalfSize[iB0] * vRotCol[0];
  674. vCenter[1] = m_vHullBoxPos[1] - v0[1] - m_vBoxHalfSize[iB0] * vRotCol[1];
  675. vCenter[2] = m_vHullBoxPos[2] - v0[2] - m_vBoxHalfSize[iB0] * vRotCol[2];
  676. } else {
  677. vCenter[0] = m_vHullBoxPos[0] - v0[0] + m_vBoxHalfSize[iB0] * vRotCol[0];
  678. vCenter[1] = m_vHullBoxPos[1] - v0[1] + m_vBoxHalfSize[iB0] * vRotCol[1];
  679. vCenter[2] = m_vHullBoxPos[2] - v0[2] + m_vBoxHalfSize[iB0] * vRotCol[2];
  680. }
  681. // Here find 4 corner points of box
  682. dVector3 avPoints[4];
  683. dVector3 vRotCol2;
  684. GETCOL(m_mHullBoxRot,iB1,vRotCol);
  685. GETCOL(m_mHullBoxRot,iB2,vRotCol2);
  686. for(int x=0;x<3;x++) {
  687. avPoints[0][x] = vCenter[x] + (m_vBoxHalfSize[iB1] * vRotCol[x]) - (m_vBoxHalfSize[iB2] * vRotCol2[x]);
  688. avPoints[1][x] = vCenter[x] - (m_vBoxHalfSize[iB1] * vRotCol[x]) - (m_vBoxHalfSize[iB2] * vRotCol2[x]);
  689. avPoints[2][x] = vCenter[x] - (m_vBoxHalfSize[iB1] * vRotCol[x]) + (m_vBoxHalfSize[iB2] * vRotCol2[x]);
  690. avPoints[3][x] = vCenter[x] + (m_vBoxHalfSize[iB1] * vRotCol[x]) + (m_vBoxHalfSize[iB2] * vRotCol2[x]);
  691. }
  692. // clip Box face with 4 planes of triangle (1 face plane, 3 egde planes)
  693. dVector3 avTempArray1[9];
  694. dVector3 avTempArray2[9];
  695. dVector4 plPlane;
  696. int iTempCnt1=0;
  697. int iTempCnt2=0;
  698. // zeroify vectors - necessary?
  699. for(int i=0; i<9; i++) {
  700. avTempArray1[i][0]=0;
  701. avTempArray1[i][1]=0;
  702. avTempArray1[i][2]=0;
  703. avTempArray2[i][0]=0;
  704. avTempArray2[i][1]=0;
  705. avTempArray2[i][2]=0;
  706. }
  707. // Normal plane
  708. dVector3 vTemp;
  709. vTemp[0]=-m_vN[0];
  710. vTemp[1]=-m_vN[1];
  711. vTemp[2]=-m_vN[2];
  712. dNormalize3(vTemp);
  713. CONSTRUCTPLANE(plPlane,vTemp,0);
  714. _cldClipPolyToPlane( avPoints, 4, avTempArray1, iTempCnt1, plPlane );
  715. // Plane p0
  716. dVector3 vTemp2;
  717. SUBTRACT(v1,v0,vTemp2);
  718. dCROSS(vTemp,=,m_vN,vTemp2);
  719. dNormalize3(vTemp);
  720. CONSTRUCTPLANE(plPlane,vTemp,0);
  721. _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane );
  722. // Plane p1
  723. SUBTRACT(v2,v1,vTemp2);
  724. dCROSS(vTemp,=,m_vN,vTemp2);
  725. dNormalize3(vTemp);
  726. SUBTRACT(v0,v2,vTemp2);
  727. CONSTRUCTPLANE(plPlane,vTemp,dDOT(vTemp2,vTemp));
  728. _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane );
  729. // Plane p2
  730. SUBTRACT(v0,v2,vTemp2);
  731. dCROSS(vTemp,=,m_vN,vTemp2);
  732. dNormalize3(vTemp);
  733. CONSTRUCTPLANE(plPlane,vTemp,0);
  734. _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane );
  735. // END of clipping polygons
  736. // for each generated contact point
  737. for ( int i=0; i<iTempCnt2; i++ ) {
  738. // calculate depth
  739. dReal fTempDepth = dDOT(vNormal2,avTempArray2[i]);
  740. // clamp depth to zero
  741. if (fTempDepth > 0) {
  742. fTempDepth = 0;
  743. }
  744. dVector3 vPntTmp;
  745. ADD(avTempArray2[i],v0,vPntTmp);
  746. #if 0 //#ifdef ORIG -- if to use conditional define, GenerateContact must be moved into #else
  747. dContactGeom* Contact = SAFECONTACT(m_iFlags, m_ContactGeoms, m_ctContacts, m_iStride);
  748. Contact->depth = -fTempDepth;
  749. SET(Contact->normal,m_vBestNormal);
  750. SET(Contact->pos,vPntTmp);
  751. Contact->g1 = Geom1;
  752. Contact->g2 = Geom2;
  753. m_ctContacts++;
  754. #endif
  755. GenerateContact(m_iFlags, m_ContactGeoms, m_iStride, m_Geom1, m_Geom2,
  756. vPntTmp, m_vBestNormal, -fTempDepth, m_ctContacts);
  757. if ((m_ctContacts | CONTACTS_UNIMPORTANT) == (m_iFlags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) {
  758. break;
  759. }
  760. }
  761. //dAASSERT(m_ctContacts>0);
  762. // if box face is the referent face, then clip triangle on box face
  763. } else { // 2 <= if iBestAxis <= 4
  764. // get normal of box face
  765. dVector3 vNormal2;
  766. SET(vNormal2,m_vBestNormal);
  767. // get indices of box axes in correct order
  768. int iA0,iA1,iA2;
  769. iA0 = m_iBestAxis-2;
  770. if ( iA0 == 0 ) {
  771. iA1 = 1; iA2 = 2;
  772. } else if ( iA0 == 1 ) {
  773. iA1 = 0; iA2 = 2;
  774. } else {
  775. iA1 = 0; iA2 = 1;
  776. }
  777. dVector3 avPoints[3];
  778. // calculate triangle vertices in box frame
  779. SUBTRACT(v0,m_vHullBoxPos,avPoints[0]);
  780. SUBTRACT(v1,m_vHullBoxPos,avPoints[1]);
  781. SUBTRACT(v2,m_vHullBoxPos,avPoints[2]);
  782. // CLIP Polygons
  783. // define temp data for clipping
  784. dVector3 avTempArray1[9];
  785. dVector3 avTempArray2[9];
  786. int iTempCnt1, iTempCnt2;
  787. // zeroify vectors - necessary?
  788. for(int i=0; i<9; i++) {
  789. avTempArray1[i][0]=0;
  790. avTempArray1[i][1]=0;
  791. avTempArray1[i][2]=0;
  792. avTempArray2[i][0]=0;
  793. avTempArray2[i][1]=0;
  794. avTempArray2[i][2]=0;
  795. }
  796. // clip triangle with 5 box planes (1 face plane, 4 edge planes)
  797. dVector4 plPlane;
  798. // Normal plane
  799. dVector3 vTemp;
  800. vTemp[0]=-vNormal2[0];
  801. vTemp[1]=-vNormal2[1];
  802. vTemp[2]=-vNormal2[2];
  803. CONSTRUCTPLANE(plPlane,vTemp,m_vBoxHalfSize[iA0]);
  804. _cldClipPolyToPlane( avPoints, 3, avTempArray1, iTempCnt1, plPlane );
  805. // Plane p0
  806. GETCOL(m_mHullBoxRot,iA1,vTemp);
  807. CONSTRUCTPLANE(plPlane,vTemp,m_vBoxHalfSize[iA1]);
  808. _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane );
  809. // Plane p1
  810. GETCOL(m_mHullBoxRot,iA1,vTemp);
  811. vTemp[0]=-vTemp[0];
  812. vTemp[1]=-vTemp[1];
  813. vTemp[2]=-vTemp[2];
  814. CONSTRUCTPLANE(plPlane,vTemp,m_vBoxHalfSize[iA1]);
  815. _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane );
  816. // Plane p2
  817. GETCOL(m_mHullBoxRot,iA2,vTemp);
  818. CONSTRUCTPLANE(plPlane,vTemp,m_vBoxHalfSize[iA2]);
  819. _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane );
  820. // Plane p3
  821. GETCOL(m_mHullBoxRot,iA2,vTemp);
  822. vTemp[0]=-vTemp[0];
  823. vTemp[1]=-vTemp[1];
  824. vTemp[2]=-vTemp[2];
  825. CONSTRUCTPLANE(plPlane,vTemp,m_vBoxHalfSize[iA2]);
  826. _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane );
  827. // for each generated contact point
  828. for ( int i=0; i<iTempCnt1; i++ ) {
  829. // calculate depth
  830. dReal fTempDepth = dDOT(vNormal2,avTempArray1[i])-m_vBoxHalfSize[iA0];
  831. // clamp depth to zero
  832. if (fTempDepth > 0) {
  833. fTempDepth = 0;
  834. }
  835. // generate contact data
  836. dVector3 vPntTmp;
  837. ADD(avTempArray1[i],m_vHullBoxPos,vPntTmp);
  838. #if 0 //#ifdef ORIG -- if to use conditional define, GenerateContact must be moved into #else
  839. dContactGeom* Contact = SAFECONTACT(m_iFlags, m_ContactGeoms, m_ctContacts, m_iStride);
  840. Contact->depth = -fTempDepth;
  841. SET(Contact->normal,m_vBestNormal);
  842. SET(Contact->pos,vPntTmp);
  843. Contact->g1 = Geom1;
  844. Contact->g2 = Geom2;
  845. m_ctContacts++;
  846. #endif
  847. GenerateContact(m_iFlags, m_ContactGeoms, m_iStride, m_Geom1, m_Geom2,
  848. vPntTmp, m_vBestNormal, -fTempDepth, m_ctContacts);
  849. if ((m_ctContacts | CONTACTS_UNIMPORTANT) == (m_iFlags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) {
  850. break;
  851. }
  852. }
  853. //dAASSERT(m_ctContacts>0);
  854. }
  855. }
  856. // test one mesh triangle on intersection with given box
  857. void sTrimeshBoxColliderData::_cldTestOneTriangle(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2)//, void *pvUser)
  858. {
  859. // do intersection test and find best separating axis
  860. if(!_cldTestSeparatingAxes(v0, v1, v2)) {
  861. // if not found do nothing
  862. return;
  863. }
  864. // if best separation axis is not found
  865. if (m_iBestAxis == 0) {
  866. // this should not happen (we should already exit in that case)
  867. //dMessage (0, "best separation axis not found");
  868. // do nothing
  869. return;
  870. }
  871. _cldClipping(v0, v1, v2);
  872. }
  873. void sTrimeshBoxColliderData::SetupInitialContext(dxTriMesh *TriMesh, dxGeom *BoxGeom,
  874. int Flags, dContactGeom* Contacts, int Stride)
  875. {
  876. // get source hull position, orientation and half size
  877. const dMatrix3& mRotBox=*(const dMatrix3*)dGeomGetRotation(BoxGeom);
  878. const dVector3& vPosBox=*(const dVector3*)dGeomGetPosition(BoxGeom);
  879. // to global
  880. SETM(m_mHullBoxRot,mRotBox);
  881. SET(m_vHullBoxPos,vPosBox);
  882. dGeomBoxGetLengths(BoxGeom, m_vBoxHalfSize);
  883. m_vBoxHalfSize[0] *= 0.5f;
  884. m_vBoxHalfSize[1] *= 0.5f;
  885. m_vBoxHalfSize[2] *= 0.5f;
  886. // get destination hull position and orientation
  887. const dVector3& vPosMesh=*(const dVector3*)dGeomGetPosition(TriMesh);
  888. // to global
  889. SET(m_vHullDstPos,vPosMesh);
  890. // global info for contact creation
  891. m_ctContacts = 0;
  892. m_iStride=Stride;
  893. m_iFlags=Flags;
  894. m_ContactGeoms=Contacts;
  895. m_Geom1=TriMesh;
  896. m_Geom2=BoxGeom;
  897. // reset stuff
  898. m_fBestDepth = MAXVALUE;
  899. m_vBestNormal[0]=0;
  900. m_vBestNormal[1]=0;
  901. m_vBestNormal[2]=0;
  902. }
  903. int sTrimeshBoxColliderData::TestCollisionForSingleTriangle(int ctContacts0, int Triint,
  904. dVector3 dv[3], bool &bOutFinishSearching)
  905. {
  906. // test this triangle
  907. _cldTestOneTriangle(dv[0],dv[1],dv[2]);
  908. // fill-in tri index for generated contacts
  909. for (; ctContacts0 < m_ctContacts; ctContacts0++)
  910. SAFECONTACT(m_iFlags, m_ContactGeoms, ctContacts0, m_iStride)->side1 = Triint;
  911. /*
  912. NOTE by Oleh_Derevenko:
  913. The function continues checking triangles after maximal number
  914. of contacts is reached because it selects maximal penetration depths.
  915. See also comments in GenerateContact()
  916. */
  917. bOutFinishSearching = ((m_ctContacts | CONTACTS_UNIMPORTANT) == (m_iFlags & (NUMC_MASK | CONTACTS_UNIMPORTANT)));
  918. return ctContacts0;
  919. }
  920. // OPCODE version of box to mesh collider
  921. #if dTRIMESH_OPCODE
  922. static void dQueryBTLPotentialCollisionTriangles(OBBCollider &Collider,
  923. const sTrimeshBoxColliderData &cData, dxTriMesh *TriMesh, dxGeom *BoxGeom,
  924. OBBCache &BoxCache)
  925. {
  926. // get source hull position, orientation and half size
  927. const dMatrix3& mRotBox=*(const dMatrix3*)dGeomGetRotation(BoxGeom);
  928. const dVector3& vPosBox=*(const dVector3*)dGeomGetPosition(BoxGeom);
  929. // Make OBB
  930. OBB Box;
  931. Box.mCenter.x = vPosBox[0];
  932. Box.mCenter.y = vPosBox[1];
  933. Box.mCenter.z = vPosBox[2];
  934. // It is a potential issue to explicitly cast to float
  935. // if custom width floating point type is introduced in OPCODE.
  936. // It is necessary to make a typedef and cast to it
  937. // (e.g. typedef float opc_float;)
  938. // However I'm not sure in what header it should be added.
  939. Box.mExtents.x = /*(float)*/cData.m_vBoxHalfSize[0];
  940. Box.mExtents.y = /*(float)*/cData.m_vBoxHalfSize[1];
  941. Box.mExtents.z = /*(float)*/cData.m_vBoxHalfSize[2];
  942. Box.mRot.m[0][0] = /*(float)*/mRotBox[0];
  943. Box.mRot.m[1][0] = /*(float)*/mRotBox[1];
  944. Box.mRot.m[2][0] = /*(float)*/mRotBox[2];
  945. Box.mRot.m[0][1] = /*(float)*/mRotBox[4];
  946. Box.mRot.m[1][1] = /*(float)*/mRotBox[5];
  947. Box.mRot.m[2][1] = /*(float)*/mRotBox[6];
  948. Box.mRot.m[0][2] = /*(float)*/mRotBox[8];
  949. Box.mRot.m[1][2] = /*(float)*/mRotBox[9];
  950. Box.mRot.m[2][2] = /*(float)*/mRotBox[10];
  951. Matrix4x4 amatrix;
  952. Matrix4x4 BoxMatrix = MakeMatrix(vPosBox, mRotBox, amatrix);
  953. Matrix4x4 InvBoxMatrix;
  954. InvertPRMatrix(InvBoxMatrix, BoxMatrix);
  955. // get destination hull position and orientation
  956. const dMatrix3& mRotMesh=*(const dMatrix3*)dGeomGetRotation(TriMesh);
  957. const dVector3& vPosMesh=*(const dVector3*)dGeomGetPosition(TriMesh);
  958. // TC results
  959. if (TriMesh->doBoxTC) {
  960. dxTriMesh::BoxTC* BoxTC = 0;
  961. for (int i = 0; i < TriMesh->BoxTCCache.size(); i++){
  962. if (TriMesh->BoxTCCache[i].Geom == BoxGeom){
  963. BoxTC = &TriMesh->BoxTCCache[i];
  964. break;
  965. }
  966. }
  967. if (!BoxTC){
  968. TriMesh->BoxTCCache.push(dxTriMesh::BoxTC());
  969. BoxTC = &TriMesh->BoxTCCache[TriMesh->BoxTCCache.size() - 1];
  970. BoxTC->Geom = BoxGeom;
  971. BoxTC->FatCoeff = 1.1f; // Pierre recommends this, instead of 1.0
  972. }
  973. // Intersect
  974. Collider.SetTemporalCoherence(true);
  975. Collider.Collide(*BoxTC, Box, TriMesh->Data->BVTree, null, &MakeMatrix(vPosMesh, mRotMesh, amatrix));
  976. }
  977. else {
  978. Collider.SetTemporalCoherence(false);
  979. Collider.Collide(BoxCache, Box, TriMesh->Data->BVTree, null,
  980. &MakeMatrix(vPosMesh, mRotMesh, amatrix));
  981. }
  982. }
  983. int dCollideBTL(dxGeom* g1, dxGeom* BoxGeom, int Flags, dContactGeom* Contacts, int Stride){
  984. dIASSERT (Stride >= (int)sizeof(dContactGeom));
  985. dIASSERT (g1->type == dTriMeshClass);
  986. dIASSERT (BoxGeom->type == dBoxClass);
  987. dIASSERT ((Flags & NUMC_MASK) >= 1);
  988. dxTriMesh* TriMesh = (dxTriMesh*)g1;
  989. sTrimeshBoxColliderData cData;
  990. cData.SetupInitialContext(TriMesh, BoxGeom, Flags, Contacts, Stride);
  991. TrimeshCollidersCache *pccColliderCache = GetTrimeshCollidersCache();
  992. OBBCollider& Collider = pccColliderCache->_OBBCollider;
  993. dQueryBTLPotentialCollisionTriangles(Collider, cData, TriMesh, BoxGeom,
  994. pccColliderCache->defaultBoxCache);
  995. if (!Collider.GetContactStatus()) {
  996. // no collision occurred
  997. return 0;
  998. }
  999. // Retrieve data
  1000. int TriCount = Collider.GetNbTouchedPrimitives();
  1001. const int* Triangles = (const int*)Collider.GetTouchedPrimitives();
  1002. if (TriCount != 0){
  1003. if (TriMesh->ArrayCallback != null){
  1004. TriMesh->ArrayCallback(TriMesh, BoxGeom, Triangles, TriCount);
  1005. }
  1006. // get destination hull position and orientation
  1007. const dMatrix3& mRotMesh=*(const dMatrix3*)dGeomGetRotation(TriMesh);
  1008. const dVector3& vPosMesh=*(const dVector3*)dGeomGetPosition(TriMesh);
  1009. int ctContacts0 = 0;
  1010. // loop through all intersecting triangles
  1011. for (int i = 0; i < TriCount; i++){
  1012. const int Triint = Triangles[i];
  1013. if (!Callback(TriMesh, BoxGeom, Triint)) continue;
  1014. dVector3 dv[3];
  1015. FetchTriangle(TriMesh, Triint, vPosMesh, mRotMesh, dv);
  1016. bool bFinishSearching;
  1017. ctContacts0 = cData.TestCollisionForSingleTriangle(ctContacts0, Triint, dv, bFinishSearching);
  1018. if (bFinishSearching) {
  1019. break;
  1020. }
  1021. }
  1022. }
  1023. return cData.m_ctContacts;
  1024. }
  1025. #endif
  1026. // GIMPACT version of box to mesh collider
  1027. #if dTRIMESH_GIMPACT
  1028. int dCollideBTL(dxGeom* g1, dxGeom* BoxGeom, int Flags, dContactGeom* Contacts, int Stride)
  1029. {
  1030. dIASSERT (Stride >= (int)sizeof(dContactGeom));
  1031. dIASSERT (g1->type == dTriMeshClass);
  1032. dIASSERT (BoxGeom->type == dBoxClass);
  1033. dIASSERT ((Flags & NUMC_MASK) >= 1);
  1034. dxTriMesh* TriMesh = (dxTriMesh*)g1;
  1035. g1 -> recomputeAABB();
  1036. BoxGeom -> recomputeAABB();
  1037. sTrimeshBoxColliderData cData;
  1038. cData.SetupInitialContext(TriMesh, BoxGeom, Flags, Contacts, Stride);
  1039. //*****at first , collide box aabb******//
  1040. GIM_TRIMESH * ptrimesh = &TriMesh->m_collision_trimesh;
  1041. aabb3f test_aabb;
  1042. test_aabb.minX = BoxGeom->aabb[0];
  1043. test_aabb.maxX = BoxGeom->aabb[1];
  1044. test_aabb.minY = BoxGeom->aabb[2];
  1045. test_aabb.maxY = BoxGeom->aabb[3];
  1046. test_aabb.minZ = BoxGeom->aabb[4];
  1047. test_aabb.maxZ = BoxGeom->aabb[5];
  1048. GDYNAMIC_ARRAY collision_result;
  1049. GIM_CREATE_BOXQUERY_LIST(collision_result);
  1050. gim_aabbset_box_collision(&test_aabb, &ptrimesh->m_aabbset , &collision_result);
  1051. if(collision_result.m_size==0)
  1052. {
  1053. GIM_DYNARRAY_DESTROY(collision_result);
  1054. return 0;
  1055. }
  1056. //*****Set globals for box collision******//
  1057. //collide triangles
  1058. GUINT * boxesresult = GIM_DYNARRAY_POINTER(GUINT,collision_result);
  1059. gim_trimesh_locks_work_data(ptrimesh);
  1060. int ctContacts0 = 0;
  1061. for(unsigned int i=0;i<collision_result.m_size;i++)
  1062. {
  1063. dVector3 dv[3];
  1064. int Triint = boxesresult[i];
  1065. gim_trimesh_get_triangle_vertices(ptrimesh, Triint, dv[0], dv[1], dv[2]);
  1066. bool bFinishSearching;
  1067. ctContacts0 = cData.TestCollisionForSingleTriangle(ctContacts0, Triint, dv, bFinishSearching);
  1068. if (bFinishSearching)
  1069. {
  1070. break;
  1071. }
  1072. }
  1073. gim_trimesh_unlocks_work_data(ptrimesh);
  1074. GIM_DYNARRAY_DESTROY(collision_result);
  1075. return cData.m_ctContacts;
  1076. }
  1077. #endif
  1078. // GenerateContact - Written by Jeff Smith ([email protected])
  1079. // Generate a "unique" contact. A unique contact has a unique
  1080. // position or normal. If the potential contact has the same
  1081. // position and normal as an existing contact, but a larger
  1082. // penetration depth, this new depth is used instead
  1083. //
  1084. static void
  1085. GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride,
  1086. dxGeom* in_g1, dxGeom* in_g2,
  1087. const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth,
  1088. int& OutTriCount)
  1089. {
  1090. /*
  1091. NOTE by Oleh_Derevenko:
  1092. This function is called after maximal number of contacts has already been
  1093. collected because it has a side effect of replacing penetration depth of
  1094. existing contact with larger penetration depth of another matching normal contact.
  1095. If this logic is not necessary any more, you can bail out on reach of contact
  1096. number maximum immediately in dCollideBTL(). You will also need to correct
  1097. conditional statements after invocations of GenerateContact() in _cldClipping().
  1098. */
  1099. do
  1100. {
  1101. dContactGeom* Contact;
  1102. dVector3 diff;
  1103. if (!(in_Flags & CONTACTS_UNIMPORTANT))
  1104. {
  1105. bool duplicate = false;
  1106. for (int i=0; i<OutTriCount; i++)
  1107. {
  1108. Contact = SAFECONTACT(in_Flags, in_Contacts, i, in_Stride);
  1109. // same position?
  1110. for (int j=0; j<3; j++)
  1111. diff[j] = in_ContactPos[j] - Contact->pos[j];
  1112. if (dDOT(diff, diff) < dEpsilon)
  1113. {
  1114. // same normal?
  1115. if (dFabs(dDOT(in_Normal, Contact->normal)) > (REAL(1.0)-dEpsilon))
  1116. {
  1117. if (in_Depth > Contact->depth)
  1118. Contact->depth = in_Depth;
  1119. duplicate = true;
  1120. /*
  1121. NOTE by Oleh_Derevenko:
  1122. There may be a case when two normals are close to each other but not duplicate
  1123. while third normal is detected to be duplicate for both of them.
  1124. This is the only reason I can think of, there is no "break" statement.
  1125. Perhaps author considered it to be logical that the third normal would
  1126. replace the depth in both of initial contacts.
  1127. However, I consider it a questionable practice which should not
  1128. be applied without deep understanding of underlaying physics.
  1129. Even more, is this situation with close normal triplet acceptable at all?
  1130. Should not be two initial contacts reduced to one (replaced with the latter)?
  1131. If you know the answers for these questions, you may want to change this code.
  1132. See the same statement in GenerateContact() of collision_trimesh_trimesh.cpp
  1133. */
  1134. }
  1135. }
  1136. }
  1137. if (duplicate || OutTriCount == (in_Flags & NUMC_MASK))
  1138. {
  1139. break;
  1140. }
  1141. }
  1142. else
  1143. {
  1144. dIASSERT(OutTriCount < (in_Flags & NUMC_MASK));
  1145. }
  1146. // Add a new contact
  1147. Contact = SAFECONTACT(in_Flags, in_Contacts, OutTriCount, in_Stride);
  1148. Contact->pos[0] = in_ContactPos[0];
  1149. Contact->pos[1] = in_ContactPos[1];
  1150. Contact->pos[2] = in_ContactPos[2];
  1151. Contact->pos[3] = 0.0;
  1152. Contact->normal[0] = in_Normal[0];
  1153. Contact->normal[1] = in_Normal[1];
  1154. Contact->normal[2] = in_Normal[2];
  1155. Contact->normal[3] = 0.0;
  1156. Contact->depth = in_Depth;
  1157. Contact->g1 = in_g1;
  1158. Contact->g2 = in_g2;
  1159. OutTriCount++;
  1160. }
  1161. while (false);
  1162. }
  1163. #endif // dTRIMESH_ENABLED