btMprPenetration.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  1. /***
  2. * ---------------------------------
  3. * Copyright (c)2012 Daniel Fiser <[email protected]>
  4. *
  5. * This file was ported from mpr.c file, part of libccd.
  6. * The Minkoski Portal Refinement implementation was ported
  7. * to OpenCL by Erwin Coumans for the Bullet 3 Physics library.
  8. * The original MPR idea and implementation is by Gary Snethen
  9. * in XenoCollide, see http://github.com/erwincoumans/xenocollide
  10. *
  11. * Distributed under the OSI-approved BSD License (the "License");
  12. * see <http://www.opensource.org/licenses/bsd-license.php>.
  13. * This software is distributed WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. * See the License for more information.
  16. */
  17. ///2014 Oct, Erwin Coumans, Use templates to avoid void* casts
  18. #ifndef BT_MPR_PENETRATION_H
  19. #define BT_MPR_PENETRATION_H
  20. #define BT_DEBUG_MPR1
  21. #include "LinearMath/btTransform.h"
  22. #include "LinearMath/btAlignedObjectArray.h"
  23. //#define MPR_AVERAGE_CONTACT_POSITIONS
  24. struct btMprCollisionDescription
  25. {
  26. btVector3 m_firstDir;
  27. int m_maxGjkIterations;
  28. btScalar m_maximumDistanceSquared;
  29. btScalar m_gjkRelError2;
  30. btMprCollisionDescription()
  31. : m_firstDir(0,1,0),
  32. m_maxGjkIterations(1000),
  33. m_maximumDistanceSquared(1e30f),
  34. m_gjkRelError2(1.0e-6)
  35. {
  36. }
  37. virtual ~btMprCollisionDescription()
  38. {
  39. }
  40. };
  41. struct btMprDistanceInfo
  42. {
  43. btVector3 m_pointOnA;
  44. btVector3 m_pointOnB;
  45. btVector3 m_normalBtoA;
  46. btScalar m_distance;
  47. };
  48. #ifdef __cplusplus
  49. #define BT_MPR_SQRT sqrtf
  50. #else
  51. #define BT_MPR_SQRT sqrt
  52. #endif
  53. #define BT_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y))
  54. #define BT_MPR_FABS fabs
  55. #define BT_MPR_TOLERANCE 1E-6f
  56. #define BT_MPR_MAX_ITERATIONS 1000
  57. struct _btMprSupport_t
  58. {
  59. btVector3 v; //!< Support point in minkowski sum
  60. btVector3 v1; //!< Support point in obj1
  61. btVector3 v2; //!< Support point in obj2
  62. };
  63. typedef struct _btMprSupport_t btMprSupport_t;
  64. struct _btMprSimplex_t
  65. {
  66. btMprSupport_t ps[4];
  67. int last; //!< index of last added point
  68. };
  69. typedef struct _btMprSimplex_t btMprSimplex_t;
  70. inline btMprSupport_t* btMprSimplexPointW(btMprSimplex_t *s, int idx)
  71. {
  72. return &s->ps[idx];
  73. }
  74. inline void btMprSimplexSetSize(btMprSimplex_t *s, int size)
  75. {
  76. s->last = size - 1;
  77. }
  78. #ifdef DEBUG_MPR
  79. inline void btPrintPortalVertex(_btMprSimplex_t* portal, int index)
  80. {
  81. printf("portal[%d].v = %f,%f,%f, v1=%f,%f,%f, v2=%f,%f,%f\n", index, portal->ps[index].v.x(),portal->ps[index].v.y(),portal->ps[index].v.z(),
  82. portal->ps[index].v1.x(),portal->ps[index].v1.y(),portal->ps[index].v1.z(),
  83. portal->ps[index].v2.x(),portal->ps[index].v2.y(),portal->ps[index].v2.z());
  84. }
  85. #endif //DEBUG_MPR
  86. inline int btMprSimplexSize(const btMprSimplex_t *s)
  87. {
  88. return s->last + 1;
  89. }
  90. inline const btMprSupport_t* btMprSimplexPoint(const btMprSimplex_t* s, int idx)
  91. {
  92. // here is no check on boundaries
  93. return &s->ps[idx];
  94. }
  95. inline void btMprSupportCopy(btMprSupport_t *d, const btMprSupport_t *s)
  96. {
  97. *d = *s;
  98. }
  99. inline void btMprSimplexSet(btMprSimplex_t *s, size_t pos, const btMprSupport_t *a)
  100. {
  101. btMprSupportCopy(s->ps + pos, a);
  102. }
  103. inline void btMprSimplexSwap(btMprSimplex_t *s, size_t pos1, size_t pos2)
  104. {
  105. btMprSupport_t supp;
  106. btMprSupportCopy(&supp, &s->ps[pos1]);
  107. btMprSupportCopy(&s->ps[pos1], &s->ps[pos2]);
  108. btMprSupportCopy(&s->ps[pos2], &supp);
  109. }
  110. inline int btMprIsZero(float val)
  111. {
  112. return BT_MPR_FABS(val) < FLT_EPSILON;
  113. }
  114. inline int btMprEq(float _a, float _b)
  115. {
  116. float ab;
  117. float a, b;
  118. ab = BT_MPR_FABS(_a - _b);
  119. if (BT_MPR_FABS(ab) < FLT_EPSILON)
  120. return 1;
  121. a = BT_MPR_FABS(_a);
  122. b = BT_MPR_FABS(_b);
  123. if (b > a){
  124. return ab < FLT_EPSILON * b;
  125. }else{
  126. return ab < FLT_EPSILON * a;
  127. }
  128. }
  129. inline int btMprVec3Eq(const btVector3* a, const btVector3 *b)
  130. {
  131. return btMprEq((*a).x(), (*b).x())
  132. && btMprEq((*a).y(), (*b).y())
  133. && btMprEq((*a).z(), (*b).z());
  134. }
  135. template <typename btConvexTemplate>
  136. inline void btFindOrigin(const btConvexTemplate& a, const btConvexTemplate& b, const btMprCollisionDescription& colDesc,btMprSupport_t *center)
  137. {
  138. center->v1 = a.getObjectCenterInWorld();
  139. center->v2 = b.getObjectCenterInWorld();
  140. center->v = center->v1 - center->v2;
  141. }
  142. inline void btMprVec3Set(btVector3 *v, float x, float y, float z)
  143. {
  144. v->setValue(x,y,z);
  145. }
  146. inline void btMprVec3Add(btVector3 *v, const btVector3 *w)
  147. {
  148. *v += *w;
  149. }
  150. inline void btMprVec3Copy(btVector3 *v, const btVector3 *w)
  151. {
  152. *v = *w;
  153. }
  154. inline void btMprVec3Scale(btVector3 *d, float k)
  155. {
  156. *d *= k;
  157. }
  158. inline float btMprVec3Dot(const btVector3 *a, const btVector3 *b)
  159. {
  160. float dot;
  161. dot = btDot(*a,*b);
  162. return dot;
  163. }
  164. inline float btMprVec3Len2(const btVector3 *v)
  165. {
  166. return btMprVec3Dot(v, v);
  167. }
  168. inline void btMprVec3Normalize(btVector3 *d)
  169. {
  170. float k = 1.f / BT_MPR_SQRT(btMprVec3Len2(d));
  171. btMprVec3Scale(d, k);
  172. }
  173. inline void btMprVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b)
  174. {
  175. *d = btCross(*a,*b);
  176. }
  177. inline void btMprVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w)
  178. {
  179. *d = *v - *w;
  180. }
  181. inline void btPortalDir(const btMprSimplex_t *portal, btVector3 *dir)
  182. {
  183. btVector3 v2v1, v3v1;
  184. btMprVec3Sub2(&v2v1, &btMprSimplexPoint(portal, 2)->v,
  185. &btMprSimplexPoint(portal, 1)->v);
  186. btMprVec3Sub2(&v3v1, &btMprSimplexPoint(portal, 3)->v,
  187. &btMprSimplexPoint(portal, 1)->v);
  188. btMprVec3Cross(dir, &v2v1, &v3v1);
  189. btMprVec3Normalize(dir);
  190. }
  191. inline int portalEncapsulesOrigin(const btMprSimplex_t *portal,
  192. const btVector3 *dir)
  193. {
  194. float dot;
  195. dot = btMprVec3Dot(dir, &btMprSimplexPoint(portal, 1)->v);
  196. return btMprIsZero(dot) || dot > 0.f;
  197. }
  198. inline int portalReachTolerance(const btMprSimplex_t *portal,
  199. const btMprSupport_t *v4,
  200. const btVector3 *dir)
  201. {
  202. float dv1, dv2, dv3, dv4;
  203. float dot1, dot2, dot3;
  204. // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4}
  205. dv1 = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, dir);
  206. dv2 = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, dir);
  207. dv3 = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, dir);
  208. dv4 = btMprVec3Dot(&v4->v, dir);
  209. dot1 = dv4 - dv1;
  210. dot2 = dv4 - dv2;
  211. dot3 = dv4 - dv3;
  212. dot1 = BT_MPR_FMIN(dot1, dot2);
  213. dot1 = BT_MPR_FMIN(dot1, dot3);
  214. return btMprEq(dot1, BT_MPR_TOLERANCE) || dot1 < BT_MPR_TOLERANCE;
  215. }
  216. inline int portalCanEncapsuleOrigin(const btMprSimplex_t *portal,
  217. const btMprSupport_t *v4,
  218. const btVector3 *dir)
  219. {
  220. float dot;
  221. dot = btMprVec3Dot(&v4->v, dir);
  222. return btMprIsZero(dot) || dot > 0.f;
  223. }
  224. inline void btExpandPortal(btMprSimplex_t *portal,
  225. const btMprSupport_t *v4)
  226. {
  227. float dot;
  228. btVector3 v4v0;
  229. btMprVec3Cross(&v4v0, &v4->v, &btMprSimplexPoint(portal, 0)->v);
  230. dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &v4v0);
  231. if (dot > 0.f){
  232. dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &v4v0);
  233. if (dot > 0.f){
  234. btMprSimplexSet(portal, 1, v4);
  235. }else{
  236. btMprSimplexSet(portal, 3, v4);
  237. }
  238. }else{
  239. dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &v4v0);
  240. if (dot > 0.f){
  241. btMprSimplexSet(portal, 2, v4);
  242. }else{
  243. btMprSimplexSet(portal, 1, v4);
  244. }
  245. }
  246. }
  247. template <typename btConvexTemplate>
  248. inline void btMprSupport(const btConvexTemplate& a, const btConvexTemplate& b,
  249. const btMprCollisionDescription& colDesc,
  250. const btVector3& dir, btMprSupport_t *supp)
  251. {
  252. btVector3 seperatingAxisInA = dir* a.getWorldTransform().getBasis();
  253. btVector3 seperatingAxisInB = -dir* b.getWorldTransform().getBasis();
  254. btVector3 pInA = a.getLocalSupportWithMargin(seperatingAxisInA);
  255. btVector3 qInB = b.getLocalSupportWithMargin(seperatingAxisInB);
  256. supp->v1 = a.getWorldTransform()(pInA);
  257. supp->v2 = b.getWorldTransform()(qInB);
  258. supp->v = supp->v1 - supp->v2;
  259. }
  260. template <typename btConvexTemplate>
  261. static int btDiscoverPortal(const btConvexTemplate& a, const btConvexTemplate& b,
  262. const btMprCollisionDescription& colDesc,
  263. btMprSimplex_t *portal)
  264. {
  265. btVector3 dir, va, vb;
  266. float dot;
  267. int cont;
  268. // vertex 0 is center of portal
  269. btFindOrigin(a,b,colDesc, btMprSimplexPointW(portal, 0));
  270. // vertex 0 is center of portal
  271. btMprSimplexSetSize(portal, 1);
  272. btVector3 zero = btVector3(0,0,0);
  273. btVector3* org = &zero;
  274. if (btMprVec3Eq(&btMprSimplexPoint(portal, 0)->v, org)){
  275. // Portal's center lies on origin (0,0,0) => we know that objects
  276. // intersect but we would need to know penetration info.
  277. // So move center little bit...
  278. btMprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f);
  279. btMprVec3Add(&btMprSimplexPointW(portal, 0)->v, &va);
  280. }
  281. // vertex 1 = support in direction of origin
  282. btMprVec3Copy(&dir, &btMprSimplexPoint(portal, 0)->v);
  283. btMprVec3Scale(&dir, -1.f);
  284. btMprVec3Normalize(&dir);
  285. btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 1));
  286. btMprSimplexSetSize(portal, 2);
  287. // test if origin isn't outside of v1
  288. dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &dir);
  289. if (btMprIsZero(dot) || dot < 0.f)
  290. return -1;
  291. // vertex 2
  292. btMprVec3Cross(&dir, &btMprSimplexPoint(portal, 0)->v,
  293. &btMprSimplexPoint(portal, 1)->v);
  294. if (btMprIsZero(btMprVec3Len2(&dir))){
  295. if (btMprVec3Eq(&btMprSimplexPoint(portal, 1)->v, org)){
  296. // origin lies on v1
  297. return 1;
  298. }else{
  299. // origin lies on v0-v1 segment
  300. return 2;
  301. }
  302. }
  303. btMprVec3Normalize(&dir);
  304. btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 2));
  305. dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &dir);
  306. if (btMprIsZero(dot) || dot < 0.f)
  307. return -1;
  308. btMprSimplexSetSize(portal, 3);
  309. // vertex 3 direction
  310. btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
  311. &btMprSimplexPoint(portal, 0)->v);
  312. btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
  313. &btMprSimplexPoint(portal, 0)->v);
  314. btMprVec3Cross(&dir, &va, &vb);
  315. btMprVec3Normalize(&dir);
  316. // it is better to form portal faces to be oriented "outside" origin
  317. dot = btMprVec3Dot(&dir, &btMprSimplexPoint(portal, 0)->v);
  318. if (dot > 0.f){
  319. btMprSimplexSwap(portal, 1, 2);
  320. btMprVec3Scale(&dir, -1.f);
  321. }
  322. while (btMprSimplexSize(portal) < 4){
  323. btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 3));
  324. dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &dir);
  325. if (btMprIsZero(dot) || dot < 0.f)
  326. return -1;
  327. cont = 0;
  328. // test if origin is outside (v1, v0, v3) - set v2 as v3 and
  329. // continue
  330. btMprVec3Cross(&va, &btMprSimplexPoint(portal, 1)->v,
  331. &btMprSimplexPoint(portal, 3)->v);
  332. dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
  333. if (dot < 0.f && !btMprIsZero(dot)){
  334. btMprSimplexSet(portal, 2, btMprSimplexPoint(portal, 3));
  335. cont = 1;
  336. }
  337. if (!cont){
  338. // test if origin is outside (v3, v0, v2) - set v1 as v3 and
  339. // continue
  340. btMprVec3Cross(&va, &btMprSimplexPoint(portal, 3)->v,
  341. &btMprSimplexPoint(portal, 2)->v);
  342. dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
  343. if (dot < 0.f && !btMprIsZero(dot)){
  344. btMprSimplexSet(portal, 1, btMprSimplexPoint(portal, 3));
  345. cont = 1;
  346. }
  347. }
  348. if (cont){
  349. btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
  350. &btMprSimplexPoint(portal, 0)->v);
  351. btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
  352. &btMprSimplexPoint(portal, 0)->v);
  353. btMprVec3Cross(&dir, &va, &vb);
  354. btMprVec3Normalize(&dir);
  355. }else{
  356. btMprSimplexSetSize(portal, 4);
  357. }
  358. }
  359. return 0;
  360. }
  361. template <typename btConvexTemplate>
  362. static int btRefinePortal(const btConvexTemplate& a, const btConvexTemplate& b,const btMprCollisionDescription& colDesc,
  363. btMprSimplex_t *portal)
  364. {
  365. btVector3 dir;
  366. btMprSupport_t v4;
  367. for (int i=0;i<BT_MPR_MAX_ITERATIONS;i++)
  368. //while (1)
  369. {
  370. // compute direction outside the portal (from v0 throught v1,v2,v3
  371. // face)
  372. btPortalDir(portal, &dir);
  373. // test if origin is inside the portal
  374. if (portalEncapsulesOrigin(portal, &dir))
  375. return 0;
  376. // get next support point
  377. btMprSupport(a,b,colDesc, dir, &v4);
  378. // test if v4 can expand portal to contain origin and if portal
  379. // expanding doesn't reach given tolerance
  380. if (!portalCanEncapsuleOrigin(portal, &v4, &dir)
  381. || portalReachTolerance(portal, &v4, &dir))
  382. {
  383. return -1;
  384. }
  385. // v1-v2-v3 triangle must be rearranged to face outside Minkowski
  386. // difference (direction from v0).
  387. btExpandPortal(portal, &v4);
  388. }
  389. return -1;
  390. }
  391. static void btFindPos(const btMprSimplex_t *portal, btVector3 *pos)
  392. {
  393. btVector3 zero = btVector3(0,0,0);
  394. btVector3* origin = &zero;
  395. btVector3 dir;
  396. size_t i;
  397. float b[4], sum, inv;
  398. btVector3 vec, p1, p2;
  399. btPortalDir(portal, &dir);
  400. // use barycentric coordinates of tetrahedron to find origin
  401. btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
  402. &btMprSimplexPoint(portal, 2)->v);
  403. b[0] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
  404. btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
  405. &btMprSimplexPoint(portal, 2)->v);
  406. b[1] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
  407. btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 0)->v,
  408. &btMprSimplexPoint(portal, 1)->v);
  409. b[2] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
  410. btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
  411. &btMprSimplexPoint(portal, 1)->v);
  412. b[3] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
  413. sum = b[0] + b[1] + b[2] + b[3];
  414. if (btMprIsZero(sum) || sum < 0.f){
  415. b[0] = 0.f;
  416. btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
  417. &btMprSimplexPoint(portal, 3)->v);
  418. b[1] = btMprVec3Dot(&vec, &dir);
  419. btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
  420. &btMprSimplexPoint(portal, 1)->v);
  421. b[2] = btMprVec3Dot(&vec, &dir);
  422. btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
  423. &btMprSimplexPoint(portal, 2)->v);
  424. b[3] = btMprVec3Dot(&vec, &dir);
  425. sum = b[1] + b[2] + b[3];
  426. }
  427. inv = 1.f / sum;
  428. btMprVec3Copy(&p1, origin);
  429. btMprVec3Copy(&p2, origin);
  430. for (i = 0; i < 4; i++){
  431. btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v1);
  432. btMprVec3Scale(&vec, b[i]);
  433. btMprVec3Add(&p1, &vec);
  434. btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v2);
  435. btMprVec3Scale(&vec, b[i]);
  436. btMprVec3Add(&p2, &vec);
  437. }
  438. btMprVec3Scale(&p1, inv);
  439. btMprVec3Scale(&p2, inv);
  440. #ifdef MPR_AVERAGE_CONTACT_POSITIONS
  441. btMprVec3Copy(pos, &p1);
  442. btMprVec3Add(pos, &p2);
  443. btMprVec3Scale(pos, 0.5);
  444. #else
  445. btMprVec3Copy(pos, &p2);
  446. #endif//MPR_AVERAGE_CONTACT_POSITIONS
  447. }
  448. inline float btMprVec3Dist2(const btVector3 *a, const btVector3 *b)
  449. {
  450. btVector3 ab;
  451. btMprVec3Sub2(&ab, a, b);
  452. return btMprVec3Len2(&ab);
  453. }
  454. inline float _btMprVec3PointSegmentDist2(const btVector3 *P,
  455. const btVector3 *x0,
  456. const btVector3 *b,
  457. btVector3 *witness)
  458. {
  459. // The computation comes from solving equation of segment:
  460. // S(t) = x0 + t.d
  461. // where - x0 is initial point of segment
  462. // - d is direction of segment from x0 (|d| > 0)
  463. // - t belongs to <0, 1> interval
  464. //
  465. // Than, distance from a segment to some point P can be expressed:
  466. // D(t) = |x0 + t.d - P|^2
  467. // which is distance from any point on segment. Minimization
  468. // of this function brings distance from P to segment.
  469. // Minimization of D(t) leads to simple quadratic equation that's
  470. // solving is straightforward.
  471. //
  472. // Bonus of this method is witness point for free.
  473. float dist, t;
  474. btVector3 d, a;
  475. // direction of segment
  476. btMprVec3Sub2(&d, b, x0);
  477. // precompute vector from P to x0
  478. btMprVec3Sub2(&a, x0, P);
  479. t = -1.f * btMprVec3Dot(&a, &d);
  480. t /= btMprVec3Len2(&d);
  481. if (t < 0.f || btMprIsZero(t)){
  482. dist = btMprVec3Dist2(x0, P);
  483. if (witness)
  484. btMprVec3Copy(witness, x0);
  485. }else if (t > 1.f || btMprEq(t, 1.f)){
  486. dist = btMprVec3Dist2(b, P);
  487. if (witness)
  488. btMprVec3Copy(witness, b);
  489. }else{
  490. if (witness){
  491. btMprVec3Copy(witness, &d);
  492. btMprVec3Scale(witness, t);
  493. btMprVec3Add(witness, x0);
  494. dist = btMprVec3Dist2(witness, P);
  495. }else{
  496. // recycling variables
  497. btMprVec3Scale(&d, t);
  498. btMprVec3Add(&d, &a);
  499. dist = btMprVec3Len2(&d);
  500. }
  501. }
  502. return dist;
  503. }
  504. inline float btMprVec3PointTriDist2(const btVector3 *P,
  505. const btVector3 *x0, const btVector3 *B,
  506. const btVector3 *C,
  507. btVector3 *witness)
  508. {
  509. // Computation comes from analytic expression for triangle (x0, B, C)
  510. // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and
  511. // Then equation for distance is:
  512. // D(s, t) = | T(s, t) - P |^2
  513. // This leads to minimization of quadratic function of two variables.
  514. // The solution from is taken only if s is between 0 and 1, t is
  515. // between 0 and 1 and t + s < 1, otherwise distance from segment is
  516. // computed.
  517. btVector3 d1, d2, a;
  518. float u, v, w, p, q, r;
  519. float s, t, dist, dist2;
  520. btVector3 witness2;
  521. btMprVec3Sub2(&d1, B, x0);
  522. btMprVec3Sub2(&d2, C, x0);
  523. btMprVec3Sub2(&a, x0, P);
  524. u = btMprVec3Dot(&a, &a);
  525. v = btMprVec3Dot(&d1, &d1);
  526. w = btMprVec3Dot(&d2, &d2);
  527. p = btMprVec3Dot(&a, &d1);
  528. q = btMprVec3Dot(&a, &d2);
  529. r = btMprVec3Dot(&d1, &d2);
  530. btScalar div = (w * v - r * r);
  531. if (btMprIsZero(div))
  532. {
  533. s=-1;
  534. } else
  535. {
  536. s = (q * r - w * p) / div;
  537. t = (-s * r - q) / w;
  538. }
  539. if ((btMprIsZero(s) || s > 0.f)
  540. && (btMprEq(s, 1.f) || s < 1.f)
  541. && (btMprIsZero(t) || t > 0.f)
  542. && (btMprEq(t, 1.f) || t < 1.f)
  543. && (btMprEq(t + s, 1.f) || t + s < 1.f)){
  544. if (witness){
  545. btMprVec3Scale(&d1, s);
  546. btMprVec3Scale(&d2, t);
  547. btMprVec3Copy(witness, x0);
  548. btMprVec3Add(witness, &d1);
  549. btMprVec3Add(witness, &d2);
  550. dist = btMprVec3Dist2(witness, P);
  551. }else{
  552. dist = s * s * v;
  553. dist += t * t * w;
  554. dist += 2.f * s * t * r;
  555. dist += 2.f * s * p;
  556. dist += 2.f * t * q;
  557. dist += u;
  558. }
  559. }else{
  560. dist = _btMprVec3PointSegmentDist2(P, x0, B, witness);
  561. dist2 = _btMprVec3PointSegmentDist2(P, x0, C, &witness2);
  562. if (dist2 < dist){
  563. dist = dist2;
  564. if (witness)
  565. btMprVec3Copy(witness, &witness2);
  566. }
  567. dist2 = _btMprVec3PointSegmentDist2(P, B, C, &witness2);
  568. if (dist2 < dist){
  569. dist = dist2;
  570. if (witness)
  571. btMprVec3Copy(witness, &witness2);
  572. }
  573. }
  574. return dist;
  575. }
  576. template <typename btConvexTemplate>
  577. static void btFindPenetr(const btConvexTemplate& a, const btConvexTemplate& b,
  578. const btMprCollisionDescription& colDesc,
  579. btMprSimplex_t *portal,
  580. float *depth, btVector3 *pdir, btVector3 *pos)
  581. {
  582. btVector3 dir;
  583. btMprSupport_t v4;
  584. unsigned long iterations;
  585. btVector3 zero = btVector3(0,0,0);
  586. btVector3* origin = &zero;
  587. iterations = 1UL;
  588. for (int i=0;i<BT_MPR_MAX_ITERATIONS;i++)
  589. //while (1)
  590. {
  591. // compute portal direction and obtain next support point
  592. btPortalDir(portal, &dir);
  593. btMprSupport(a,b,colDesc, dir, &v4);
  594. // reached tolerance -> find penetration info
  595. if (portalReachTolerance(portal, &v4, &dir)
  596. || iterations ==BT_MPR_MAX_ITERATIONS)
  597. {
  598. *depth = btMprVec3PointTriDist2(origin,&btMprSimplexPoint(portal, 1)->v,&btMprSimplexPoint(portal, 2)->v,&btMprSimplexPoint(portal, 3)->v,pdir);
  599. *depth = BT_MPR_SQRT(*depth);
  600. if (btMprIsZero((*pdir).x()) && btMprIsZero((*pdir).y()) && btMprIsZero((*pdir).z()))
  601. {
  602. *pdir = dir;
  603. }
  604. btMprVec3Normalize(pdir);
  605. // barycentric coordinates:
  606. btFindPos(portal, pos);
  607. return;
  608. }
  609. btExpandPortal(portal, &v4);
  610. iterations++;
  611. }
  612. }
  613. static void btFindPenetrTouch(btMprSimplex_t *portal,float *depth, btVector3 *dir, btVector3 *pos)
  614. {
  615. // Touching contact on portal's v1 - so depth is zero and direction
  616. // is unimportant and pos can be guessed
  617. *depth = 0.f;
  618. btVector3 zero = btVector3(0,0,0);
  619. btVector3* origin = &zero;
  620. btMprVec3Copy(dir, origin);
  621. #ifdef MPR_AVERAGE_CONTACT_POSITIONS
  622. btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
  623. btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
  624. btMprVec3Scale(pos, 0.5);
  625. #else
  626. btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
  627. #endif
  628. }
  629. static void btFindPenetrSegment(btMprSimplex_t *portal,
  630. float *depth, btVector3 *dir, btVector3 *pos)
  631. {
  632. // Origin lies on v0-v1 segment.
  633. // Depth is distance to v1, direction also and position must be
  634. // computed
  635. #ifdef MPR_AVERAGE_CONTACT_POSITIONS
  636. btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
  637. btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
  638. btMprVec3Scale(pos, 0.5f);
  639. #else
  640. btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
  641. #endif//MPR_AVERAGE_CONTACT_POSITIONS
  642. btMprVec3Copy(dir, &btMprSimplexPoint(portal, 1)->v);
  643. *depth = BT_MPR_SQRT(btMprVec3Len2(dir));
  644. btMprVec3Normalize(dir);
  645. }
  646. template <typename btConvexTemplate>
  647. inline int btMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b,
  648. const btMprCollisionDescription& colDesc,
  649. float *depthOut, btVector3* dirOut, btVector3* posOut)
  650. {
  651. btMprSimplex_t portal;
  652. // Phase 1: Portal discovery
  653. int result = btDiscoverPortal(a,b,colDesc, &portal);
  654. //sepAxis[pairIndex] = *pdir;//or -dir?
  655. switch (result)
  656. {
  657. case 0:
  658. {
  659. // Phase 2: Portal refinement
  660. result = btRefinePortal(a,b,colDesc, &portal);
  661. if (result < 0)
  662. return -1;
  663. // Phase 3. Penetration info
  664. btFindPenetr(a,b,colDesc, &portal, depthOut, dirOut, posOut);
  665. break;
  666. }
  667. case 1:
  668. {
  669. // Touching contact on portal's v1.
  670. btFindPenetrTouch(&portal, depthOut, dirOut, posOut);
  671. result=0;
  672. break;
  673. }
  674. case 2:
  675. {
  676. btFindPenetrSegment( &portal, depthOut, dirOut, posOut);
  677. result=0;
  678. break;
  679. }
  680. default:
  681. {
  682. //if (res < 0)
  683. //{
  684. // Origin isn't inside portal - no collision.
  685. result = -1;
  686. //}
  687. }
  688. };
  689. return result;
  690. };
  691. template<typename btConvexTemplate, typename btMprDistanceTemplate>
  692. inline int btComputeMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b, const
  693. btMprCollisionDescription& colDesc, btMprDistanceTemplate* distInfo)
  694. {
  695. btVector3 dir,pos;
  696. float depth;
  697. int res = btMprPenetration(a,b,colDesc,&depth, &dir, &pos);
  698. if (res==0)
  699. {
  700. distInfo->m_distance = -depth;
  701. distInfo->m_pointOnB = pos;
  702. distInfo->m_normalBtoA = -dir;
  703. distInfo->m_pointOnA = pos-distInfo->m_distance*dir;
  704. return 0;
  705. }
  706. return -1;
  707. }
  708. #endif //BT_MPR_PENETRATION_H