123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- // The core algorithms in this file are inspired by public papers written
- // by G. van den Bergen for his interference detection library,
- // "SOLID 2.0"
- #include "core/dataChunker.h"
- #include "collision/collision.h"
- #include "scene/sceneObject.h"
- #include "collision/convex.h"
- #include "collision/gjk.h"
- //----------------------------------------------------------------------------
- static F32 rel_error = 1E-5f; // relative error in the computed distance
- static F32 sTolerance = 1E-3f; // Distance tolerance
- static F32 sEpsilon2 = 1E-20f; // Zero length vector
- static U32 sIteration = 15; // Stuck in a loop?
- S32 num_iterations = 0;
- S32 num_irregularities = 0;
- //----------------------------------------------------------------------------
- GjkCollisionState::GjkCollisionState()
- {
- mBits = 0;
- mAll_bits = 0;
- U32 x, y;
- for (x = 0; x < 16; x++)
- for (y = 0; y < 4; y++)
- mDet[x][y] = 0.0f;
- for (x = 0; x < 4; x++)
- for (y = 0; y < 4; y++)
- mDP[x][y] = 0.0f;
- mLast = 0;
- mLast_bit = 0;
- mA = mB = 0;
- }
- GjkCollisionState::~GjkCollisionState()
- {
- }
- //----------------------------------------------------------------------------
- void GjkCollisionState::swap()
- {
- Convex* t = mA; mA = mB; mB = t;
- CollisionStateList* l = mLista; mLista = mListb; mListb = l;
- mDistvec.neg();
- }
- //----------------------------------------------------------------------------
- void GjkCollisionState::compute_det()
- {
- // Dot new point with current set
- for (S32 i = 0, bit = 1; i < 4; ++i, bit <<=1)
- if (mBits & bit)
- mDP[i][mLast] = mDP[mLast][i] = mDot(mY[i], mY[mLast]);
- mDP[mLast][mLast] = mDot(mY[mLast], mY[mLast]);
- // Calulate the determinent
- mDet[mLast_bit][mLast] = 1;
- for (S32 j = 0, sj = 1; j < 4; ++j, sj <<= 1) {
- if (mBits & sj) {
- S32 s2 = sj | mLast_bit;
- mDet[s2][j] = mDP[mLast][mLast] - mDP[mLast][j];
- mDet[s2][mLast] = mDP[j][j] - mDP[j][mLast];
- for (S32 k = 0, sk = 1; k < j; ++k, sk <<= 1) {
- if (mBits & sk) {
- S32 s3 = sk | s2;
- mDet[s3][k] = mDet[s2][j] * (mDP[j][j] - mDP[j][k]) +
- mDet[s2][mLast] * (mDP[mLast][j] - mDP[mLast][k]);
- mDet[s3][j] = mDet[sk | mLast_bit][k] * (mDP[k][k] - mDP[k][j]) +
- mDet[sk | mLast_bit][mLast] * (mDP[mLast][k] - mDP[mLast][j]);
- mDet[s3][mLast] = mDet[sk | sj][k] * (mDP[k][k] - mDP[k][mLast]) +
- mDet[sk | sj][j] * (mDP[j][k] - mDP[j][mLast]);
- }
- }
- }
- }
- if (mAll_bits == 15) {
- mDet[15][0] = mDet[14][1] * (mDP[1][1] - mDP[1][0]) +
- mDet[14][2] * (mDP[2][1] - mDP[2][0]) +
- mDet[14][3] * (mDP[3][1] - mDP[3][0]);
- mDet[15][1] = mDet[13][0] * (mDP[0][0] - mDP[0][1]) +
- mDet[13][2] * (mDP[2][0] - mDP[2][1]) +
- mDet[13][3] * (mDP[3][0] - mDP[3][1]);
- mDet[15][2] = mDet[11][0] * (mDP[0][0] - mDP[0][2]) +
- mDet[11][1] * (mDP[1][0] - mDP[1][2]) +
- mDet[11][3] * (mDP[3][0] - mDP[3][2]);
- mDet[15][3] = mDet[7][0] * (mDP[0][0] - mDP[0][3]) +
- mDet[7][1] * (mDP[1][0] - mDP[1][3]) +
- mDet[7][2] * (mDP[2][0] - mDP[2][3]);
- }
- }
- //----------------------------------------------------------------------------
- inline void GjkCollisionState::compute_vector(S32 bits, VectorF& v)
- {
- F32 sum = 0;
- v.set(0, 0, 0);
- for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
- if (bits & bit) {
- sum += mDet[bits][i];
- v += mY[i] * mDet[bits][i];
- }
- }
- v *= 1 / sum;
- }
- //----------------------------------------------------------------------------
- inline bool GjkCollisionState::valid(S32 s)
- {
- for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
- if (mAll_bits & bit) {
- if (s & bit) {
- if (mDet[s][i] <= 0)
- return false;
- }
- else
- if (mDet[s | bit][i] > 0)
- return false;
- }
- }
- return true;
- }
- //----------------------------------------------------------------------------
- inline bool GjkCollisionState::closest(VectorF& v)
- {
- compute_det();
- for (S32 s = mBits; s; --s) {
- if ((s & mBits) == s) {
- if (valid(s | mLast_bit)) {
- mBits = s | mLast_bit;
- if (mBits != 15)
- compute_vector(mBits, v);
- return true;
- }
- }
- }
- if (valid(mLast_bit)) {
- mBits = mLast_bit;
- v = mY[mLast];
- return true;
- }
- return false;
- }
- //----------------------------------------------------------------------------
- inline bool GjkCollisionState::degenerate(const VectorF& w)
- {
- for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1)
- if ((mAll_bits & bit) && mY[i] == w)
- return true;
- return false;
- }
- //----------------------------------------------------------------------------
- inline void GjkCollisionState::nextBit()
- {
- mLast = 0;
- mLast_bit = 1;
- while (mBits & mLast_bit) {
- ++mLast;
- mLast_bit <<= 1;
- }
- }
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- void GjkCollisionState::set(Convex* aa, Convex* bb,
- const MatrixF& a2w, const MatrixF& b2w)
- {
- mA = aa;
- mB = bb;
- mBits = 0;
- mAll_bits = 0;
- reset(a2w,b2w);
- // link
- mLista = CollisionStateList::alloc();
- mLista->mState = this;
- mListb = CollisionStateList::alloc();
- mListb->mState = this;
- }
- //----------------------------------------------------------------------------
- void GjkCollisionState::reset(const MatrixF& a2w, const MatrixF& b2w)
- {
- VectorF zero(0,0,0),sa,sb;
- a2w.mulP(mA->support(zero),&sa);
- b2w.mulP(mB->support(zero),&sb);
- mDistvec = sa - sb;
- mDist = mDistvec.len();
- }
- //----------------------------------------------------------------------------
- void GjkCollisionState::getCollisionInfo(const MatrixF& mat, Collision* info)
- {
- AssertFatal(false, "GjkCollisionState::getCollisionInfo() - There remain scaling problems here.");
- // This assumes that the shapes do not intersect
- Point3F pa,pb;
- if (mBits) {
- getClosestPoints(pa,pb);
- mat.mulP(pa,&info->point);
- mB->getTransform().mulP(pb,&pa);
- info->normal = info->point - pa;
- }
- else {
- mat.mulP(mP[mLast],&info->point);
- info->normal = mDistvec;
- }
- info->normal.normalize();
- info->object = mB->getObject();
- }
- void GjkCollisionState::getClosestPoints(Point3F& p1, Point3F& p2)
- {
- F32 sum = 0;
- p1.set(0, 0, 0);
- p2.set(0, 0, 0);
- for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
- if (mBits & bit) {
- sum += mDet[mBits][i];
- p1 += mP[i] * mDet[mBits][i];
- p2 += mQ[i] * mDet[mBits][i];
- }
- }
- F32 s = 1 / sum;
- p1 *= s;
- p2 *= s;
- }
- //----------------------------------------------------------------------------
- bool GjkCollisionState::intersect(const MatrixF& a2w, const MatrixF& b2w)
- {
- num_iterations = 0;
- MatrixF w2a,w2b;
- w2a = a2w;
- w2b = b2w;
- w2a.inverse();
- w2b.inverse();
- reset(a2w,b2w);
- mBits = 0;
- mAll_bits = 0;
- do {
- nextBit();
- VectorF va,sa;
- w2a.mulV(-mDistvec,&va);
- mP[mLast] = mA->support(va);
- a2w.mulP(mP[mLast],&sa);
- VectorF vb,sb;
- w2b.mulV(mDistvec,&vb);
- mQ[mLast] = mB->support(vb);
- b2w.mulP(mQ[mLast],&sb);
- VectorF w = sa - sb;
- if (mDot(mDistvec,w) > 0)
- return false;
- if (degenerate(w)) {
- ++num_irregularities;
- return false;
- }
- mY[mLast] = w;
- mAll_bits = mBits | mLast_bit;
- ++num_iterations;
- if (!closest(mDistvec) || num_iterations > sIteration) {
- ++num_irregularities;
- return false;
- }
- }
- while (mBits < 15 && mDistvec.lenSquared() > sEpsilon2);
- return true;
- }
- F32 GjkCollisionState::distance(const MatrixF& a2w, const MatrixF& b2w,
- const F32 dontCareDist, const MatrixF* _w2a, const MatrixF* _w2b)
- {
- num_iterations = 0;
- MatrixF w2a,w2b;
- if (_w2a == NULL || _w2b == NULL) {
- w2a = a2w;
- w2b = b2w;
- w2a.inverse();
- w2b.inverse();
- }
- else {
- w2a = *_w2a;
- w2b = *_w2b;
- }
- reset(a2w,b2w);
- mBits = 0;
- mAll_bits = 0;
- F32 mu = 0;
- do {
- nextBit();
- VectorF va,sa;
- w2a.mulV(-mDistvec,&va);
- mP[mLast] = mA->support(va);
- a2w.mulP(mP[mLast],&sa);
- VectorF vb,sb;
- w2b.mulV(mDistvec,&vb);
- mQ[mLast] = mB->support(vb);
- b2w.mulP(mQ[mLast],&sb);
- VectorF w = sa - sb;
- F32 nm = mDot(mDistvec, w) / mDist;
- if (nm > mu)
- mu = nm;
- if (mu > dontCareDist)
- return mu;
- if (mFabs(mDist - mu) <= mDist * rel_error)
- return mDist;
- ++num_iterations;
- if (degenerate(w) || num_iterations > sIteration) {
- ++num_irregularities;
- return mDist;
- }
- mY[mLast] = w;
- mAll_bits = mBits | mLast_bit;
- if (!closest(mDistvec)) {
- ++num_irregularities;
- return mDist;
- }
- mDist = mDistvec.len();
- }
- while (mBits < 15 && mDist > sTolerance) ;
- if (mBits == 15 && mu <= 0)
- mDist = 0;
- return mDist;
- }
|