gjk.cpp

Engine/source/collision/gjk.cpp

More...

Detailed Description

Public Variables

S32 num_irregularities 
S32 num_iterations 
F32 rel_error 
F32 sEpsilon2 
U32 sIteration 
F32 sTolerance 
  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24// The core algorithms in this file are inspired by public papers written
 25// by G. van den Bergen for his interference detection library,
 26// "SOLID 2.0"
 27
 28#include "core/dataChunker.h"
 29#include "collision/collision.h"
 30#include "scene/sceneObject.h"
 31#include "collision/convex.h"
 32#include "collision/gjk.h"
 33
 34
 35//----------------------------------------------------------------------------
 36
 37static F32 rel_error = 1E-5f;     // relative error in the computed distance
 38static F32 sTolerance = 1E-3f;    // Distance tolerance
 39static F32 sEpsilon2 = 1E-20f;    // Zero length vector
 40static U32 sIteration = 15;       // Stuck in a loop?
 41
 42S32 num_iterations = 0;
 43S32 num_irregularities = 0;
 44
 45
 46//----------------------------------------------------------------------------
 47
 48GjkCollisionState::GjkCollisionState()
 49{
 50   mBits = 0;
 51   mAll_bits = 0;
 52   U32 x, y;
 53   for (x = 0; x < 16; x++)
 54      for (y = 0; y < 4; y++)
 55         mDet[x][y] = 0.0f;
 56
 57   for (x = 0; x < 4; x++)
 58      for (y = 0; y < 4; y++)
 59         mDP[x][y] = 0.0f;
 60
 61   mLast = 0;
 62   mLast_bit = 0;
 63   mA = mB = 0;
 64}
 65
 66GjkCollisionState::~GjkCollisionState()
 67{
 68}
 69
 70
 71//----------------------------------------------------------------------------
 72
 73void GjkCollisionState::swap()
 74{
 75   Convex* t = mA; mA = mB; mB = t;
 76   CollisionStateList* l = mLista; mLista = mListb; mListb = l;
 77   mDistvec.neg();
 78}
 79
 80
 81//----------------------------------------------------------------------------
 82
 83void GjkCollisionState::compute_det()
 84{
 85   // Dot new point with current set
 86   for (S32 i = 0, bit = 1; i < 4; ++i, bit <<=1)
 87      if (mBits & bit)
 88        mDP[i][mLast] = mDP[mLast][i] = mDot(mY[i], mY[mLast]);
 89   mDP[mLast][mLast] = mDot(mY[mLast], mY[mLast]);
 90
 91   // Calulate the determinent
 92   mDet[mLast_bit][mLast] = 1;
 93   for (S32 j = 0, sj = 1; j < 4; ++j, sj <<= 1) {
 94      if (mBits & sj) {
 95         S32 s2 = sj | mLast_bit;
 96       mDet[s2][j] = mDP[mLast][mLast] - mDP[mLast][j];
 97       mDet[s2][mLast] = mDP[j][j] - mDP[j][mLast];
 98         for (S32 k = 0, sk = 1; k < j; ++k, sk <<= 1) {
 99            if (mBits & sk) {
100              S32 s3 = sk | s2;
101           mDet[s3][k] = mDet[s2][j] * (mDP[j][j] - mDP[j][k]) +
102                            mDet[s2][mLast] * (mDP[mLast][j] - mDP[mLast][k]);
103           mDet[s3][j] = mDet[sk | mLast_bit][k] * (mDP[k][k] - mDP[k][j]) +
104                            mDet[sk | mLast_bit][mLast] * (mDP[mLast][k] - mDP[mLast][j]);
105           mDet[s3][mLast] = mDet[sk | sj][k] * (mDP[k][k] - mDP[k][mLast]) +
106                                mDet[sk | sj][j] * (mDP[j][k] - mDP[j][mLast]);
107            }
108         }
109      }
110   }
111
112   if (mAll_bits == 15) {
113     mDet[15][0] = mDet[14][1] * (mDP[1][1] - mDP[1][0]) +
114                   mDet[14][2] * (mDP[2][1] - mDP[2][0]) +
115                   mDet[14][3] * (mDP[3][1] - mDP[3][0]);
116    mDet[15][1] = mDet[13][0] * (mDP[0][0] - mDP[0][1]) +
117                   mDet[13][2] * (mDP[2][0] - mDP[2][1]) +
118                   mDet[13][3] * (mDP[3][0] - mDP[3][1]);
119    mDet[15][2] = mDet[11][0] * (mDP[0][0] - mDP[0][2]) +
120                   mDet[11][1] * (mDP[1][0] - mDP[1][2]) +
121                   mDet[11][3] * (mDP[3][0] - mDP[3][2]);
122    mDet[15][3] = mDet[7][0] * (mDP[0][0] - mDP[0][3]) +
123                   mDet[7][1] * (mDP[1][0] - mDP[1][3]) +
124                   mDet[7][2] * (mDP[2][0] - mDP[2][3]);
125   }
126}
127
128
129//----------------------------------------------------------------------------
130
131inline void GjkCollisionState::compute_vector(S32 bits, VectorF& v)
132{
133   F32 sum = 0;
134   v.set(0, 0, 0);
135   for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
136      if (bits & bit) {
137         sum += mDet[bits][i];
138         v += mY[i] * mDet[bits][i];
139      }
140   }
141   v *= 1 / sum;
142}
143
144
145//----------------------------------------------------------------------------
146
147inline bool GjkCollisionState::valid(S32 s)
148{
149   for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
150      if (mAll_bits & bit) {
151         if (s & bit) {
152            if (mDet[s][i] <= 0)
153               return false;
154         }
155         else
156            if (mDet[s | bit][i] > 0)
157               return false;
158      }
159   }
160   return true;
161}
162
163
164//----------------------------------------------------------------------------
165
166inline bool GjkCollisionState::closest(VectorF& v)
167{
168   compute_det();
169   for (S32 s = mBits; s; --s) {
170      if ((s & mBits) == s) {
171         if (valid(s | mLast_bit)) {
172          mBits = s | mLast_bit;
173            if (mBits != 15)
174               compute_vector(mBits, v);
175            return true;
176         }
177      }
178   }
179   if (valid(mLast_bit)) {
180      mBits = mLast_bit;
181      v = mY[mLast];
182      return true;
183   }
184   return false;
185}
186
187
188//----------------------------------------------------------------------------
189
190inline bool GjkCollisionState::degenerate(const VectorF& w)
191{
192  for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1)
193   if ((mAll_bits & bit) && mY[i] == w)
194      return true;
195  return false;
196}
197
198
199//----------------------------------------------------------------------------
200
201inline void GjkCollisionState::nextBit()
202{
203   mLast = 0;
204   mLast_bit = 1;
205   while (mBits & mLast_bit) {
206      ++mLast;
207     mLast_bit <<= 1;
208   }
209}
210
211
212//----------------------------------------------------------------------------
213//----------------------------------------------------------------------------
214
215//----------------------------------------------------------------------------
216
217void GjkCollisionState::set(Convex* aa, Convex* bb,
218   const MatrixF& a2w, const MatrixF& b2w)
219{
220   mA = aa;
221   mB = bb;
222
223   mBits = 0;
224   mAll_bits = 0;
225   reset(a2w,b2w);
226
227   // link
228   mLista = CollisionStateList::alloc();
229   mLista->mState = this;
230   mListb = CollisionStateList::alloc();
231   mListb->mState = this;
232}
233
234
235//----------------------------------------------------------------------------
236
237void GjkCollisionState::reset(const MatrixF& a2w, const MatrixF& b2w)
238{
239   VectorF zero(0,0,0),sa,sb;
240   a2w.mulP(mA->support(zero),&sa);
241   b2w.mulP(mB->support(zero),&sb);
242   mDistvec = sa - sb;
243   mDist = mDistvec.len();
244}
245
246
247//----------------------------------------------------------------------------
248
249void GjkCollisionState::getCollisionInfo(const MatrixF& mat, Collision* info)
250{
251   AssertFatal(false, "GjkCollisionState::getCollisionInfo() - There remain scaling problems here.");
252   // This assumes that the shapes do not intersect
253   Point3F pa,pb;
254   if (mBits) {
255      getClosestPoints(pa,pb);
256      mat.mulP(pa,&info->point);
257     mB->getTransform().mulP(pb,&pa);
258      info->normal = info->point - pa;
259   }
260   else {
261      mat.mulP(mP[mLast],&info->point);
262      info->normal = mDistvec;
263   }
264   info->normal.normalize();
265   info->object = mB->getObject();
266}
267
268void GjkCollisionState::getClosestPoints(Point3F& p1, Point3F& p2)
269{
270   F32 sum = 0;
271   p1.set(0, 0, 0);
272   p2.set(0, 0, 0);
273   for (S32 i = 0, bit = 1; i < 4; ++i, bit <<= 1) {
274      if (mBits & bit) {
275         sum += mDet[mBits][i];
276         p1 += mP[i] * mDet[mBits][i];
277         p2 += mQ[i] * mDet[mBits][i];
278      }
279   }
280   F32 s = 1 / sum;
281   p1 *= s;
282   p2 *= s;
283}
284
285
286//----------------------------------------------------------------------------
287
288bool GjkCollisionState::intersect(const MatrixF& a2w, const MatrixF& b2w)
289{
290   num_iterations = 0;
291   MatrixF w2a,w2b;
292
293   w2a = a2w;
294   w2b = b2w;
295   w2a.inverse();
296   w2b.inverse();
297   reset(a2w,b2w);
298
299   mBits = 0;
300   mAll_bits = 0;
301
302   do {
303      nextBit();
304
305      VectorF va,sa;
306      w2a.mulV(-mDistvec,&va);
307     mP[mLast] = mA->support(va);
308      a2w.mulP(mP[mLast],&sa);
309
310      VectorF vb,sb;
311      w2b.mulV(mDistvec,&vb);
312     mQ[mLast] = mB->support(vb);
313      b2w.mulP(mQ[mLast],&sb);
314
315      VectorF w = sa - sb;
316      if (mDot(mDistvec,w) > 0)
317         return false;
318      if (degenerate(w)) {
319         ++num_irregularities;
320         return false;
321      }
322
323     mY[mLast] = w;
324     mAll_bits = mBits | mLast_bit;
325
326      ++num_iterations;
327      if (!closest(mDistvec) || num_iterations > sIteration) {
328         ++num_irregularities;
329         return false;
330      }
331   }
332   while (mBits < 15 && mDistvec.lenSquared() > sEpsilon2);
333   return true;
334}
335
336F32 GjkCollisionState::distance(const MatrixF& a2w, const MatrixF& b2w,
337   const F32 dontCareDist, const MatrixF* _w2a, const MatrixF* _w2b)
338{
339   num_iterations = 0;
340   MatrixF w2a,w2b;
341
342   if (_w2a == NULL || _w2b == NULL) {
343      w2a = a2w;
344      w2b = b2w;
345      w2a.inverse();
346      w2b.inverse();
347   }
348   else {
349      w2a = *_w2a;
350      w2b = *_w2b;
351   }
352
353   reset(a2w,b2w);
354   mBits = 0;
355   mAll_bits = 0;
356   F32 mu = 0;
357
358   do {
359      nextBit();
360
361      VectorF va,sa;
362      w2a.mulV(-mDistvec,&va);
363     mP[mLast] = mA->support(va);
364      a2w.mulP(mP[mLast],&sa);
365
366      VectorF vb,sb;
367      w2b.mulV(mDistvec,&vb);
368     mQ[mLast] = mB->support(vb);
369      b2w.mulP(mQ[mLast],&sb);
370
371      VectorF w = sa - sb;
372      F32 nm = mDot(mDistvec, w) / mDist;
373      if (nm > mu)
374         mu = nm;
375      if (mu > dontCareDist)
376         return mu;
377      if (mFabs(mDist - mu) <= mDist * rel_error)
378         return mDist;
379
380      ++num_iterations;
381      if (degenerate(w) || num_iterations > sIteration) {
382         ++num_irregularities;
383         return mDist;
384      }
385
386     mY[mLast] = w;
387     mAll_bits = mBits | mLast_bit;
388
389      if (!closest(mDistvec)) {
390         ++num_irregularities;
391         return mDist;
392      }
393
394     mDist = mDistvec.len();
395   }
396   while (mBits < 15 && mDist > sTolerance) ;
397
398   if (mBits == 15 && mu <= 0)
399      mDist = 0;
400   return mDist;
401}
402