123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885 |
- /***
- * ---------------------------------
- * Copyright (c)2012 Daniel Fiser <danfis@danfis.cz>
- *
- * This file was ported from mpr.c file, part of libccd.
- * The Minkoski Portal Refinement implementation was ported
- * to OpenCL by Erwin Coumans for the Bullet 3 Physics library.
- * The original MPR idea and implementation is by Gary Snethen
- * in XenoCollide, see http://github.com/erwincoumans/xenocollide
- *
- * Distributed under the OSI-approved BSD License (the "License");
- * see <http://www.opensource.org/licenses/bsd-license.php>.
- * This software is distributed WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the License for more information.
- */
- ///2014 Oct, Erwin Coumans, Use templates to avoid void* casts
- #ifndef BT_MPR_PENETRATION_H
- #define BT_MPR_PENETRATION_H
- #define BT_DEBUG_MPR1
- #include "LinearMath/btTransform.h"
- #include "LinearMath/btAlignedObjectArray.h"
- //#define MPR_AVERAGE_CONTACT_POSITIONS
- struct btMprCollisionDescription
- {
- btVector3 m_firstDir;
- int m_maxGjkIterations;
- btScalar m_maximumDistanceSquared;
- btScalar m_gjkRelError2;
- btMprCollisionDescription()
- : m_firstDir(0, 1, 0),
- m_maxGjkIterations(1000),
- m_maximumDistanceSquared(1e30f),
- m_gjkRelError2(1.0e-6)
- {
- }
- virtual ~btMprCollisionDescription()
- {
- }
- };
- struct btMprDistanceInfo
- {
- btVector3 m_pointOnA;
- btVector3 m_pointOnB;
- btVector3 m_normalBtoA;
- btScalar m_distance;
- };
- #ifdef __cplusplus
- #define BT_MPR_SQRT sqrtf
- #else
- #define BT_MPR_SQRT sqrt
- #endif
- #define BT_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y))
- #define BT_MPR_FABS fabs
- #define BT_MPR_TOLERANCE 1E-6f
- #define BT_MPR_MAX_ITERATIONS 1000
- struct _btMprSupport_t
- {
- btVector3 v; //!< Support point in minkowski sum
- btVector3 v1; //!< Support point in obj1
- btVector3 v2; //!< Support point in obj2
- };
- typedef struct _btMprSupport_t btMprSupport_t;
- struct _btMprSimplex_t
- {
- btMprSupport_t ps[4];
- int last; //!< index of last added point
- };
- typedef struct _btMprSimplex_t btMprSimplex_t;
- inline btMprSupport_t *btMprSimplexPointW(btMprSimplex_t *s, int idx)
- {
- return &s->ps[idx];
- }
- inline void btMprSimplexSetSize(btMprSimplex_t *s, int size)
- {
- s->last = size - 1;
- }
- #ifdef DEBUG_MPR
- inline void btPrintPortalVertex(_btMprSimplex_t *portal, int index)
- {
- 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(),
- portal->ps[index].v1.x(), portal->ps[index].v1.y(), portal->ps[index].v1.z(),
- portal->ps[index].v2.x(), portal->ps[index].v2.y(), portal->ps[index].v2.z());
- }
- #endif //DEBUG_MPR
- inline int btMprSimplexSize(const btMprSimplex_t *s)
- {
- return s->last + 1;
- }
- inline const btMprSupport_t *btMprSimplexPoint(const btMprSimplex_t *s, int idx)
- {
- // here is no check on boundaries
- return &s->ps[idx];
- }
- inline void btMprSupportCopy(btMprSupport_t *d, const btMprSupport_t *s)
- {
- *d = *s;
- }
- inline void btMprSimplexSet(btMprSimplex_t *s, size_t pos, const btMprSupport_t *a)
- {
- btMprSupportCopy(s->ps + pos, a);
- }
- inline void btMprSimplexSwap(btMprSimplex_t *s, size_t pos1, size_t pos2)
- {
- btMprSupport_t supp;
- btMprSupportCopy(&supp, &s->ps[pos1]);
- btMprSupportCopy(&s->ps[pos1], &s->ps[pos2]);
- btMprSupportCopy(&s->ps[pos2], &supp);
- }
- inline int btMprIsZero(float val)
- {
- return BT_MPR_FABS(val) < FLT_EPSILON;
- }
- inline int btMprEq(float _a, float _b)
- {
- float ab;
- float a, b;
- ab = BT_MPR_FABS(_a - _b);
- if (BT_MPR_FABS(ab) < FLT_EPSILON)
- return 1;
- a = BT_MPR_FABS(_a);
- b = BT_MPR_FABS(_b);
- if (b > a)
- {
- return ab < FLT_EPSILON * b;
- }
- else
- {
- return ab < FLT_EPSILON * a;
- }
- }
- inline int btMprVec3Eq(const btVector3 *a, const btVector3 *b)
- {
- return btMprEq((*a).x(), (*b).x()) && btMprEq((*a).y(), (*b).y()) && btMprEq((*a).z(), (*b).z());
- }
- template <typename btConvexTemplate>
- inline void btFindOrigin(const btConvexTemplate &a, const btConvexTemplate &b, const btMprCollisionDescription &colDesc, btMprSupport_t *center)
- {
- center->v1 = a.getObjectCenterInWorld();
- center->v2 = b.getObjectCenterInWorld();
- center->v = center->v1 - center->v2;
- }
- inline void btMprVec3Set(btVector3 *v, float x, float y, float z)
- {
- v->setValue(x, y, z);
- }
- inline void btMprVec3Add(btVector3 *v, const btVector3 *w)
- {
- *v += *w;
- }
- inline void btMprVec3Copy(btVector3 *v, const btVector3 *w)
- {
- *v = *w;
- }
- inline void btMprVec3Scale(btVector3 *d, float k)
- {
- *d *= k;
- }
- inline float btMprVec3Dot(const btVector3 *a, const btVector3 *b)
- {
- float dot;
- dot = btDot(*a, *b);
- return dot;
- }
- inline float btMprVec3Len2(const btVector3 *v)
- {
- return btMprVec3Dot(v, v);
- }
- inline void btMprVec3Normalize(btVector3 *d)
- {
- float k = 1.f / BT_MPR_SQRT(btMprVec3Len2(d));
- btMprVec3Scale(d, k);
- }
- inline void btMprVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b)
- {
- *d = btCross(*a, *b);
- }
- inline void btMprVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w)
- {
- *d = *v - *w;
- }
- inline void btPortalDir(const btMprSimplex_t *portal, btVector3 *dir)
- {
- btVector3 v2v1, v3v1;
- btMprVec3Sub2(&v2v1, &btMprSimplexPoint(portal, 2)->v,
- &btMprSimplexPoint(portal, 1)->v);
- btMprVec3Sub2(&v3v1, &btMprSimplexPoint(portal, 3)->v,
- &btMprSimplexPoint(portal, 1)->v);
- btMprVec3Cross(dir, &v2v1, &v3v1);
- btMprVec3Normalize(dir);
- }
- inline int portalEncapsulesOrigin(const btMprSimplex_t *portal,
- const btVector3 *dir)
- {
- float dot;
- dot = btMprVec3Dot(dir, &btMprSimplexPoint(portal, 1)->v);
- return btMprIsZero(dot) || dot > 0.f;
- }
- inline int portalReachTolerance(const btMprSimplex_t *portal,
- const btMprSupport_t *v4,
- const btVector3 *dir)
- {
- float dv1, dv2, dv3, dv4;
- float dot1, dot2, dot3;
- // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4}
- dv1 = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, dir);
- dv2 = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, dir);
- dv3 = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, dir);
- dv4 = btMprVec3Dot(&v4->v, dir);
- dot1 = dv4 - dv1;
- dot2 = dv4 - dv2;
- dot3 = dv4 - dv3;
- dot1 = BT_MPR_FMIN(dot1, dot2);
- dot1 = BT_MPR_FMIN(dot1, dot3);
- return btMprEq(dot1, BT_MPR_TOLERANCE) || dot1 < BT_MPR_TOLERANCE;
- }
- inline int portalCanEncapsuleOrigin(const btMprSimplex_t *portal,
- const btMprSupport_t *v4,
- const btVector3 *dir)
- {
- float dot;
- dot = btMprVec3Dot(&v4->v, dir);
- return btMprIsZero(dot) || dot > 0.f;
- }
- inline void btExpandPortal(btMprSimplex_t *portal,
- const btMprSupport_t *v4)
- {
- float dot;
- btVector3 v4v0;
- btMprVec3Cross(&v4v0, &v4->v, &btMprSimplexPoint(portal, 0)->v);
- dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &v4v0);
- if (dot > 0.f)
- {
- dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &v4v0);
- if (dot > 0.f)
- {
- btMprSimplexSet(portal, 1, v4);
- }
- else
- {
- btMprSimplexSet(portal, 3, v4);
- }
- }
- else
- {
- dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &v4v0);
- if (dot > 0.f)
- {
- btMprSimplexSet(portal, 2, v4);
- }
- else
- {
- btMprSimplexSet(portal, 1, v4);
- }
- }
- }
- template <typename btConvexTemplate>
- inline void btMprSupport(const btConvexTemplate &a, const btConvexTemplate &b,
- const btMprCollisionDescription &colDesc,
- const btVector3 &dir, btMprSupport_t *supp)
- {
- btVector3 separatingAxisInA = dir * a.getWorldTransform().getBasis();
- btVector3 separatingAxisInB = -dir * b.getWorldTransform().getBasis();
- btVector3 pInA = a.getLocalSupportWithMargin(separatingAxisInA);
- btVector3 qInB = b.getLocalSupportWithMargin(separatingAxisInB);
- supp->v1 = a.getWorldTransform()(pInA);
- supp->v2 = b.getWorldTransform()(qInB);
- supp->v = supp->v1 - supp->v2;
- }
- template <typename btConvexTemplate>
- static int btDiscoverPortal(const btConvexTemplate &a, const btConvexTemplate &b,
- const btMprCollisionDescription &colDesc,
- btMprSimplex_t *portal)
- {
- btVector3 dir, va, vb;
- float dot;
- int cont;
- // vertex 0 is center of portal
- btFindOrigin(a, b, colDesc, btMprSimplexPointW(portal, 0));
- // vertex 0 is center of portal
- btMprSimplexSetSize(portal, 1);
- btVector3 zero = btVector3(0, 0, 0);
- btVector3 *org = &zero;
- if (btMprVec3Eq(&btMprSimplexPoint(portal, 0)->v, org))
- {
- // Portal's center lies on origin (0,0,0) => we know that objects
- // intersect but we would need to know penetration info.
- // So move center little bit...
- btMprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f);
- btMprVec3Add(&btMprSimplexPointW(portal, 0)->v, &va);
- }
- // vertex 1 = support in direction of origin
- btMprVec3Copy(&dir, &btMprSimplexPoint(portal, 0)->v);
- btMprVec3Scale(&dir, -1.f);
- btMprVec3Normalize(&dir);
- btMprSupport(a, b, colDesc, dir, btMprSimplexPointW(portal, 1));
- btMprSimplexSetSize(portal, 2);
- // test if origin isn't outside of v1
- dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &dir);
- if (btMprIsZero(dot) || dot < 0.f)
- return -1;
- // vertex 2
- btMprVec3Cross(&dir, &btMprSimplexPoint(portal, 0)->v,
- &btMprSimplexPoint(portal, 1)->v);
- if (btMprIsZero(btMprVec3Len2(&dir)))
- {
- if (btMprVec3Eq(&btMprSimplexPoint(portal, 1)->v, org))
- {
- // origin lies on v1
- return 1;
- }
- else
- {
- // origin lies on v0-v1 segment
- return 2;
- }
- }
- btMprVec3Normalize(&dir);
- btMprSupport(a, b, colDesc, dir, btMprSimplexPointW(portal, 2));
- dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &dir);
- if (btMprIsZero(dot) || dot < 0.f)
- return -1;
- btMprSimplexSetSize(portal, 3);
- // vertex 3 direction
- btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
- &btMprSimplexPoint(portal, 0)->v);
- btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
- &btMprSimplexPoint(portal, 0)->v);
- btMprVec3Cross(&dir, &va, &vb);
- btMprVec3Normalize(&dir);
- // it is better to form portal faces to be oriented "outside" origin
- dot = btMprVec3Dot(&dir, &btMprSimplexPoint(portal, 0)->v);
- if (dot > 0.f)
- {
- btMprSimplexSwap(portal, 1, 2);
- btMprVec3Scale(&dir, -1.f);
- }
- while (btMprSimplexSize(portal) < 4)
- {
- btMprSupport(a, b, colDesc, dir, btMprSimplexPointW(portal, 3));
- dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &dir);
- if (btMprIsZero(dot) || dot < 0.f)
- return -1;
- cont = 0;
- // test if origin is outside (v1, v0, v3) - set v2 as v3 and
- // continue
- btMprVec3Cross(&va, &btMprSimplexPoint(portal, 1)->v,
- &btMprSimplexPoint(portal, 3)->v);
- dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
- if (dot < 0.f && !btMprIsZero(dot))
- {
- btMprSimplexSet(portal, 2, btMprSimplexPoint(portal, 3));
- cont = 1;
- }
- if (!cont)
- {
- // test if origin is outside (v3, v0, v2) - set v1 as v3 and
- // continue
- btMprVec3Cross(&va, &btMprSimplexPoint(portal, 3)->v,
- &btMprSimplexPoint(portal, 2)->v);
- dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
- if (dot < 0.f && !btMprIsZero(dot))
- {
- btMprSimplexSet(portal, 1, btMprSimplexPoint(portal, 3));
- cont = 1;
- }
- }
- if (cont)
- {
- btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
- &btMprSimplexPoint(portal, 0)->v);
- btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
- &btMprSimplexPoint(portal, 0)->v);
- btMprVec3Cross(&dir, &va, &vb);
- btMprVec3Normalize(&dir);
- }
- else
- {
- btMprSimplexSetSize(portal, 4);
- }
- }
- return 0;
- }
- template <typename btConvexTemplate>
- static int btRefinePortal(const btConvexTemplate &a, const btConvexTemplate &b, const btMprCollisionDescription &colDesc,
- btMprSimplex_t *portal)
- {
- btVector3 dir;
- btMprSupport_t v4;
- for (int i = 0; i < BT_MPR_MAX_ITERATIONS; i++)
- //while (1)
- {
- // compute direction outside the portal (from v0 through v1,v2,v3
- // face)
- btPortalDir(portal, &dir);
- // test if origin is inside the portal
- if (portalEncapsulesOrigin(portal, &dir))
- return 0;
- // get next support point
- btMprSupport(a, b, colDesc, dir, &v4);
- // test if v4 can expand portal to contain origin and if portal
- // expanding doesn't reach given tolerance
- if (!portalCanEncapsuleOrigin(portal, &v4, &dir) || portalReachTolerance(portal, &v4, &dir))
- {
- return -1;
- }
- // v1-v2-v3 triangle must be rearranged to face outside Minkowski
- // difference (direction from v0).
- btExpandPortal(portal, &v4);
- }
- return -1;
- }
- static void btFindPos(const btMprSimplex_t *portal, btVector3 *pos)
- {
- btVector3 zero = btVector3(0, 0, 0);
- btVector3 *origin = &zero;
- btVector3 dir;
- size_t i;
- float b[4], sum, inv;
- btVector3 vec, p1, p2;
- btPortalDir(portal, &dir);
- // use barycentric coordinates of tetrahedron to find origin
- btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
- &btMprSimplexPoint(portal, 2)->v);
- b[0] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
- btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
- &btMprSimplexPoint(portal, 2)->v);
- b[1] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
- btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 0)->v,
- &btMprSimplexPoint(portal, 1)->v);
- b[2] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
- btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
- &btMprSimplexPoint(portal, 1)->v);
- b[3] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
- sum = b[0] + b[1] + b[2] + b[3];
- if (btMprIsZero(sum) || sum < 0.f)
- {
- b[0] = 0.f;
- btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
- &btMprSimplexPoint(portal, 3)->v);
- b[1] = btMprVec3Dot(&vec, &dir);
- btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
- &btMprSimplexPoint(portal, 1)->v);
- b[2] = btMprVec3Dot(&vec, &dir);
- btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
- &btMprSimplexPoint(portal, 2)->v);
- b[3] = btMprVec3Dot(&vec, &dir);
- sum = b[1] + b[2] + b[3];
- }
- inv = 1.f / sum;
- btMprVec3Copy(&p1, origin);
- btMprVec3Copy(&p2, origin);
- for (i = 0; i < 4; i++)
- {
- btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v1);
- btMprVec3Scale(&vec, b[i]);
- btMprVec3Add(&p1, &vec);
- btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v2);
- btMprVec3Scale(&vec, b[i]);
- btMprVec3Add(&p2, &vec);
- }
- btMprVec3Scale(&p1, inv);
- btMprVec3Scale(&p2, inv);
- #ifdef MPR_AVERAGE_CONTACT_POSITIONS
- btMprVec3Copy(pos, &p1);
- btMprVec3Add(pos, &p2);
- btMprVec3Scale(pos, 0.5);
- #else
- btMprVec3Copy(pos, &p2);
- #endif //MPR_AVERAGE_CONTACT_POSITIONS
- }
- inline float btMprVec3Dist2(const btVector3 *a, const btVector3 *b)
- {
- btVector3 ab;
- btMprVec3Sub2(&ab, a, b);
- return btMprVec3Len2(&ab);
- }
- inline float _btMprVec3PointSegmentDist2(const btVector3 *P,
- const btVector3 *x0,
- const btVector3 *b,
- btVector3 *witness)
- {
- // The computation comes from solving equation of segment:
- // S(t) = x0 + t.d
- // where - x0 is initial point of segment
- // - d is direction of segment from x0 (|d| > 0)
- // - t belongs to <0, 1> interval
- //
- // Than, distance from a segment to some point P can be expressed:
- // D(t) = |x0 + t.d - P|^2
- // which is distance from any point on segment. Minimization
- // of this function brings distance from P to segment.
- // Minimization of D(t) leads to simple quadratic equation that's
- // solving is straightforward.
- //
- // Bonus of this method is witness point for free.
- float dist, t;
- btVector3 d, a;
- // direction of segment
- btMprVec3Sub2(&d, b, x0);
- // precompute vector from P to x0
- btMprVec3Sub2(&a, x0, P);
- t = -1.f * btMprVec3Dot(&a, &d);
- t /= btMprVec3Len2(&d);
- if (t < 0.f || btMprIsZero(t))
- {
- dist = btMprVec3Dist2(x0, P);
- if (witness)
- btMprVec3Copy(witness, x0);
- }
- else if (t > 1.f || btMprEq(t, 1.f))
- {
- dist = btMprVec3Dist2(b, P);
- if (witness)
- btMprVec3Copy(witness, b);
- }
- else
- {
- if (witness)
- {
- btMprVec3Copy(witness, &d);
- btMprVec3Scale(witness, t);
- btMprVec3Add(witness, x0);
- dist = btMprVec3Dist2(witness, P);
- }
- else
- {
- // recycling variables
- btMprVec3Scale(&d, t);
- btMprVec3Add(&d, &a);
- dist = btMprVec3Len2(&d);
- }
- }
- return dist;
- }
- inline float btMprVec3PointTriDist2(const btVector3 *P,
- const btVector3 *x0, const btVector3 *B,
- const btVector3 *C,
- btVector3 *witness)
- {
- // Computation comes from analytic expression for triangle (x0, B, C)
- // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and
- // Then equation for distance is:
- // D(s, t) = | T(s, t) - P |^2
- // This leads to minimization of quadratic function of two variables.
- // The solution from is taken only if s is between 0 and 1, t is
- // between 0 and 1 and t + s < 1, otherwise distance from segment is
- // computed.
- btVector3 d1, d2, a;
- float u, v, w, p, q, r;
- float s, t, dist, dist2;
- btVector3 witness2;
- btMprVec3Sub2(&d1, B, x0);
- btMprVec3Sub2(&d2, C, x0);
- btMprVec3Sub2(&a, x0, P);
- u = btMprVec3Dot(&a, &a);
- v = btMprVec3Dot(&d1, &d1);
- w = btMprVec3Dot(&d2, &d2);
- p = btMprVec3Dot(&a, &d1);
- q = btMprVec3Dot(&a, &d2);
- r = btMprVec3Dot(&d1, &d2);
- btScalar div = (w * v - r * r);
- if (btMprIsZero(div))
- {
- s = -1;
- }
- else
- {
- s = (q * r - w * p) / div;
- t = (-s * r - q) / w;
- }
- if ((btMprIsZero(s) || s > 0.f) && (btMprEq(s, 1.f) || s < 1.f) && (btMprIsZero(t) || t > 0.f) && (btMprEq(t, 1.f) || t < 1.f) && (btMprEq(t + s, 1.f) || t + s < 1.f))
- {
- if (witness)
- {
- btMprVec3Scale(&d1, s);
- btMprVec3Scale(&d2, t);
- btMprVec3Copy(witness, x0);
- btMprVec3Add(witness, &d1);
- btMprVec3Add(witness, &d2);
- dist = btMprVec3Dist2(witness, P);
- }
- else
- {
- dist = s * s * v;
- dist += t * t * w;
- dist += 2.f * s * t * r;
- dist += 2.f * s * p;
- dist += 2.f * t * q;
- dist += u;
- }
- }
- else
- {
- dist = _btMprVec3PointSegmentDist2(P, x0, B, witness);
- dist2 = _btMprVec3PointSegmentDist2(P, x0, C, &witness2);
- if (dist2 < dist)
- {
- dist = dist2;
- if (witness)
- btMprVec3Copy(witness, &witness2);
- }
- dist2 = _btMprVec3PointSegmentDist2(P, B, C, &witness2);
- if (dist2 < dist)
- {
- dist = dist2;
- if (witness)
- btMprVec3Copy(witness, &witness2);
- }
- }
- return dist;
- }
- template <typename btConvexTemplate>
- static void btFindPenetr(const btConvexTemplate &a, const btConvexTemplate &b,
- const btMprCollisionDescription &colDesc,
- btMprSimplex_t *portal,
- float *depth, btVector3 *pdir, btVector3 *pos)
- {
- btVector3 dir;
- btMprSupport_t v4;
- unsigned long iterations;
- btVector3 zero = btVector3(0, 0, 0);
- btVector3 *origin = &zero;
- iterations = 1UL;
- for (int i = 0; i < BT_MPR_MAX_ITERATIONS; i++)
- //while (1)
- {
- // compute portal direction and obtain next support point
- btPortalDir(portal, &dir);
- btMprSupport(a, b, colDesc, dir, &v4);
- // reached tolerance -> find penetration info
- if (portalReachTolerance(portal, &v4, &dir) || iterations == BT_MPR_MAX_ITERATIONS)
- {
- *depth = btMprVec3PointTriDist2(origin, &btMprSimplexPoint(portal, 1)->v, &btMprSimplexPoint(portal, 2)->v, &btMprSimplexPoint(portal, 3)->v, pdir);
- *depth = BT_MPR_SQRT(*depth);
- if (btMprIsZero((*pdir).x()) && btMprIsZero((*pdir).y()) && btMprIsZero((*pdir).z()))
- {
- *pdir = dir;
- }
- btMprVec3Normalize(pdir);
- // barycentric coordinates:
- btFindPos(portal, pos);
- return;
- }
- btExpandPortal(portal, &v4);
- iterations++;
- }
- }
- static void btFindPenetrTouch(btMprSimplex_t *portal, float *depth, btVector3 *dir, btVector3 *pos)
- {
- // Touching contact on portal's v1 - so depth is zero and direction
- // is unimportant and pos can be guessed
- *depth = 0.f;
- btVector3 zero = btVector3(0, 0, 0);
- btVector3 *origin = &zero;
- btMprVec3Copy(dir, origin);
- #ifdef MPR_AVERAGE_CONTACT_POSITIONS
- btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
- btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
- btMprVec3Scale(pos, 0.5);
- #else
- btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
- #endif
- }
- static void btFindPenetrSegment(btMprSimplex_t *portal,
- float *depth, btVector3 *dir, btVector3 *pos)
- {
- // Origin lies on v0-v1 segment.
- // Depth is distance to v1, direction also and position must be
- // computed
- #ifdef MPR_AVERAGE_CONTACT_POSITIONS
- btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
- btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
- btMprVec3Scale(pos, 0.5f);
- #else
- btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
- #endif //MPR_AVERAGE_CONTACT_POSITIONS
- btMprVec3Copy(dir, &btMprSimplexPoint(portal, 1)->v);
- *depth = BT_MPR_SQRT(btMprVec3Len2(dir));
- btMprVec3Normalize(dir);
- }
- template <typename btConvexTemplate>
- inline int btMprPenetration(const btConvexTemplate &a, const btConvexTemplate &b,
- const btMprCollisionDescription &colDesc,
- float *depthOut, btVector3 *dirOut, btVector3 *posOut)
- {
- btMprSimplex_t portal;
- // Phase 1: Portal discovery
- int result = btDiscoverPortal(a, b, colDesc, &portal);
- //sepAxis[pairIndex] = *pdir;//or -dir?
- switch (result)
- {
- case 0:
- {
- // Phase 2: Portal refinement
- result = btRefinePortal(a, b, colDesc, &portal);
- if (result < 0)
- return -1;
- // Phase 3. Penetration info
- btFindPenetr(a, b, colDesc, &portal, depthOut, dirOut, posOut);
- break;
- }
- case 1:
- {
- // Touching contact on portal's v1.
- btFindPenetrTouch(&portal, depthOut, dirOut, posOut);
- result = 0;
- break;
- }
- case 2:
- {
- btFindPenetrSegment(&portal, depthOut, dirOut, posOut);
- result = 0;
- break;
- }
- default:
- {
- //if (res < 0)
- //{
- // Origin isn't inside portal - no collision.
- result = -1;
- //}
- }
- };
- return result;
- };
- template <typename btConvexTemplate, typename btMprDistanceTemplate>
- inline int btComputeMprPenetration(const btConvexTemplate &a, const btConvexTemplate &b, const btMprCollisionDescription &colDesc, btMprDistanceTemplate *distInfo)
- {
- btVector3 dir, pos;
- float depth;
- int res = btMprPenetration(a, b, colDesc, &depth, &dir, &pos);
- if (res == 0)
- {
- distInfo->m_distance = -depth;
- distInfo->m_pointOnB = pos;
- distInfo->m_normalBtoA = -dir;
- distInfo->m_pointOnA = pos - distInfo->m_distance * dir;
- return 0;
- }
- return -1;
- }
- #endif //BT_MPR_PENETRATION_H
|