2
Bullet Continuous Collision Detection and Physics Library
3
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
5
This software is provided 'as-is', without any express or implied warranty.
6
In no event will the authors be held liable for any damages arising from the
8
Permission is granted to anyone to use this software for any purpose,
9
including commercial applications, and to alter it and redistribute it
11
subject to the following restrictions:
13
1. The origin of this software must not be misrepresented; you must not
14
claim that you wrote the original software. If you use this software in a
15
product, an acknowledgment in the product documentation would be appreciated
17
2. Altered source versions must be plainly marked as such, and must not be
18
misrepresented as being the original software.
19
3. This notice may not be removed or altered from any source distribution.
23
GJK-EPA collision solver by Nathanael Presson
28
#include <string.h> //for memset
29
#include <LinearMath/btStackAlloc.h>
31
#if defined(DEBUG) || defined (_DEBUG)
32
#include <stdio.h> //for debug printf
34
#include <spu_printf.h>
35
#define printf spu_printf
49
typedef unsigned int U;
50
typedef unsigned char U1;
51
typedef unsigned short U2;
53
typedef btVector3 Vector3;
54
typedef btMatrix3x3 Rotation;
61
#define BTLOCALSUPPORT localGetSupportingVertexWithoutMargin
63
#define BTLOCALSUPPORT localGetSupportingVertex
71
#define cstInf SIMD_INFINITY
73
#define cst2Pi SIMD_2_PI
74
#define GJK_maxiterations (128)
75
#define GJK_hashsize (1<<6)
76
#define GJK_hashmask (GJK_hashsize-1)
77
#define GJK_insimplex_eps F(0.0001)
78
#define GJK_sqinsimplex_eps (GJK_insimplex_eps*GJK_insimplex_eps)
79
#define EPA_maxiterations 256
80
#define EPA_inface_eps F(0.01)
81
#define EPA_accuracy F(0.001)
87
static inline F Abs(F v) { return(v<0?-v:v); }
88
static inline F Sign(F v) { return(F(v<0?-1:1)); }
89
template <typename T> static inline void Swap(T& a,T& b) { T
91
template <typename T> static inline T Min(const T& a,const T& b) {
93
template <typename T> static inline T Max(const T& a,const T& b) {
95
static inline void ClearMemory(void* p,U sz) { memset(p,0,(size_t)sz);
98
template <typename T> static inline void Raise(const T& object) {
101
template <typename T> static inline void Raise(const T&) {}
113
Vector3 w; /* Minkowski vertice */
123
He* table[GJK_hashsize];
124
Rotation wrotations[2];
125
Vector3 positions[2];
126
const btConvexShape* shapes[2];
134
GJK(btStackAlloc* psa,
135
const Rotation& wrot0,const Vector3& pos0,const btConvexShape* shape0,
136
const Rotation& wrot1,const Vector3& pos1,const btConvexShape* shape1,
139
wrotations[0]=wrot0;positions[0]=pos0;shapes[0]=shape0;
140
wrotations[1]=wrot1;positions[1]=pos1;shapes[1]=shape1;
142
sablock =sa->beginBlock();
149
sa->endBlock(sablock);
151
// vdh : very dumm hash
152
static inline U Hash(const Vector3& v)
154
//this doesn't compile under GCC 3.3.5, so add the ()...
155
//const U h(U(v[0]*15461)^U(v[1]*83003)^U(v[2]*15473));
156
//return(((*((const U*)&h))*169639)&GJK_hashmask);
157
const U h((U)(v[0]*15461)^(U)(v[1]*83003)^(U)(v[2]*15473));
158
return(((*((const U*)&h))*169639)&GJK_hashmask);
161
inline Vector3 LocalSupport(const Vector3& d,U i) const
163
return(wrotations[i]*shapes[i]->BTLOCALSUPPORT(d*wrotations[i])+positions[i]);
166
inline void Support(const Vector3& d,Mkv& v) const
169
v.w = LocalSupport(d,0)-LocalSupport(-d,1)+d*margin;
171
#define SPX(_i_) simplex[_i_]
172
#define SPXW(_i_) simplex[_i_].w
174
inline Z FetchSupport()
176
const U h(Hash(ray));
177
He* e = (He*)(table[h]);
178
while(e) { if(e->v==ray) { --order;return(false); } else e=e->n; }
179
e=(He*)sa->allocate(sizeof(He));e->v=ray;e->n=table[h];table[h]=e;
180
Support(ray,simplex[++order]);
181
return(ray.dot(SPXW(order))>0);
184
inline Z SolveSimplex2(const Vector3& ao,const Vector3& ab)
188
const Vector3 cabo(cross(ab,ao));
189
if(cabo.length2()>GJK_sqinsimplex_eps)
190
{ ray=cross(cabo,ab); }
195
{ order=0;SPX(0)=SPX(1);ray=ao; }
199
inline Z SolveSimplex3(const Vector3& ao,const Vector3& ab,const Vector3&
202
return(SolveSimplex3a(ao,ab,ac,cross(ab,ac)));
205
inline Z SolveSimplex3a(const Vector3& ao,const Vector3& ab,const Vector3&
206
ac,const Vector3& cabc)
208
if((cross(cabc,ab)).dot(ao)<-GJK_insimplex_eps)
209
{ order=1;SPX(0)=SPX(1);SPX(1)=SPX(2);return(SolveSimplex2(ao,ab)); }
210
else if((cross(cabc,ac)).dot(ao)>+GJK_insimplex_eps)
211
{ order=1;SPX(1)=SPX(2);return(SolveSimplex2(ao,ac)); }
214
const F d(cabc.dot(ao));
215
if(Abs(d)>GJK_insimplex_eps)
220
{ ray=-cabc;Swap(SPX(0),SPX(1)); }
226
inline Z SolveSimplex4(const Vector3& ao,const Vector3& ab,const Vector3&
227
ac,const Vector3& ad)
230
if((crs=cross(ab,ac)).dot(ao)>GJK_insimplex_eps)
232
order=2;SPX(0)=SPX(1);SPX(1)=SPX(2);SPX(2)=SPX(3);return(SolveSimplex3a(ao,ab,ac,crs));
234
else if((crs=cross(ac,ad)).dot(ao)>GJK_insimplex_eps)
235
{ order=2;SPX(2)=SPX(3);return(SolveSimplex3a(ao,ac,ad,crs)); }
236
else if((crs=cross(ad,ab)).dot(ao)>GJK_insimplex_eps)
238
order=2;SPX(1)=SPX(0);SPX(0)=SPX(2);SPX(2)=SPX(3);return(SolveSimplex3a(ao,ad,ab,crs));
243
inline Z SearchOrigin(const Vector3& initray=Vector3(1,0,0))
248
ray = initray.normalized();
249
ClearMemory(table,sizeof(void*)*GJK_hashsize);
252
for(;iterations<GJK_maxiterations;++iterations)
254
const F rl(ray.length());
261
case 1: found=SolveSimplex2(-SPXW(1),SPXW(0)-SPXW(1));break;
262
case 2: found=SolveSimplex3(-SPXW(2),SPXW(1)-SPXW(2),SPXW(0)-SPXW(2));break;
263
case 3: found=SolveSimplex4(-SPXW(3),SPXW(2)-SPXW(3),SPXW(1)-SPXW(3),SPXW(0)-SPXW(3));break;
265
if(found) return(true);
266
} else return(false);
272
inline Z EncloseOrigin()
281
const Vector3 ab(SPXW(1)-SPXW(0));
282
const Vector3 b[]={ cross(ab,Vector3(1,0,0)),
283
cross(ab,Vector3(0,1,0)),
284
cross(ab,Vector3(0,0,1))};
285
const F m[]={b[0].length2(),b[1].length2(),b[2].length2()};
286
const Rotation r(btQuaternion(ab.normalized(),cst2Pi/3));
287
Vector3 w(b[m[0]>m[1]?m[0]>m[2]?0:2:m[1]>m[2]?1:2]);
288
Support(w.normalized(),simplex[4]);w=r*w;
289
Support(w.normalized(),simplex[2]);w=r*w;
290
Support(w.normalized(),simplex[3]);w=r*w;
299
Vector3 n(cross((SPXW(1)-SPXW(0)),(SPXW(2)-SPXW(0))).normalized());
300
Support( n,simplex[3]);
301
Support(-n,simplex[4]);
307
case 3: return(true);
309
case 4: return(true);
325
const GJK::Mkv* v[3];
341
Vector3 features[2][3];
357
inline Vector3 GetCoordinates(const Face* face) const
359
const Vector3 o(face->n*-face->d);
360
const F a[]={ cross(face->v[0]->w-o,face->v[1]->w-o).length(),
361
cross(face->v[1]->w-o,face->v[2]->w-o).length(),
362
cross(face->v[2]->w-o,face->v[0]->w-o).length()};
363
const F sm(a[0]+a[1]+a[2]);
364
return(Vector3(a[1],a[2],a[0])/(sm>0?sm:1));
367
inline Face* FindBest() const
375
if(cf->d<bd) { bd=cf->d;bf=cf; }
376
} while(0!=(cf=cf->next));
381
inline Z Set(Face* f,const GJK::Mkv* a,const GJK::Mkv* b,const GJK::Mkv*
384
const Vector3 nrm(cross(b->w-a->w,c->w-a->w));
385
const F len(nrm.length());
386
const Z valid( (cross(a->w,b->w).dot(nrm)>=-EPA_inface_eps)&&
387
(cross(b->w,c->w).dot(nrm)>=-EPA_inface_eps)&&
388
(cross(c->w,a->w).dot(nrm)>=-EPA_inface_eps));
393
f->n = nrm/(len>0?len:cstInf);
394
f->d = Max<F>(0,-f->n.dot(a->w));
398
inline Face* NewFace(const GJK::Mkv* a,const GJK::Mkv* b,const GJK::Mkv* c)
400
Face* pf = (Face*)sa->allocate(sizeof(Face));
403
if(root) root->prev=pf;
416
inline void Detach(Face* face)
418
if(face->prev||face->next)
422
{ root=face->next;root->prev=0; }
426
{ face->prev->next=0; }
428
{ face->prev->next=face->next;face->next->prev=face->prev; }
430
face->prev=face->next=0;
434
inline void Link(Face* f0,U e0,Face* f1,U e1) const
436
f0->f[e0]=f1;f1->e[e1]=e0;
437
f1->f[e1]=f0;f0->e[e0]=e1;
440
GJK::Mkv* Support(const Vector3& w) const
442
GJK::Mkv* v =(GJK::Mkv*)sa->allocate(sizeof(GJK::Mkv));
447
U BuildHorizon(U markid,const GJK::Mkv* w,Face& f,U e,Face*& cf,Face*&
450
static const U mod3[]={0,1,2,0,1};
454
const U e1(mod3[e+1]);
455
if((f.n.dot(w->w)+f.d)>0)
457
Face* nf = NewFace(f.v[e1],f.v[e],w);
459
if(cf) Link(cf,1,nf,2); else ff=nf;
464
const U e2(mod3[e+2]);
467
ne += BuildHorizon(markid,w,*f.f[e1],f.e[e1],cf,ff);
468
ne += BuildHorizon(markid,w,*f.f[e2],f.e[e2],cf,ff);
474
inline F EvaluatePD(F accuracy=EPA_accuracy)
476
btBlock* sablock = sa->beginBlock();
480
normal = Vector3(0,0,0);
486
if(gjk->EncloseOrigin())
492
GJK::Mkv* basemkv[5];
498
static const U fidx[4][3]={{2,1,0},{3,0,1},{3,1,2},{3,2,0}};
500
U eidx[6][4]={{0,0,2,1},{0,1,1,1},{0,2,3,1},{1,0,3,2},{2,0,1,2},{3,0,2,2}};
501
pfidx=(const U*)fidx;nfidx=4;peidx=(const U*)eidx;neidx=6;
506
U fidx[6][3]={{2,0,4},{4,1,2},{1,4,0},{0,3,1},{0,2,3},{1,3,2}};
508
U eidx[9][4]={{0,0,4,0},{0,1,2,1},{0,2,1,2},{1,1,5,2},{1,0,2,0},{2,2,3,2},{3,1,5,0},{3,0,4,2},{5,1,4,1}};
509
pfidx=(const U*)fidx;nfidx=6;peidx=(const U*)eidx;neidx=9;
514
for( i=0;i<=gjk->order;++i) {
515
basemkv[i]=(GJK::Mkv*)sa->allocate(sizeof(GJK::Mkv));*basemkv[i]=gjk->simplex[i];
517
for( i=0;i<nfidx;++i,pfidx+=3) {
518
basefaces[i]=NewFace(basemkv[pfidx[0]],basemkv[pfidx[1]],basemkv[pfidx[2]]);
520
for( i=0;i<neidx;++i,peidx+=4) {
521
Link(basefaces[peidx[0]],peidx[1],basefaces[peidx[2]],peidx[3]); }
525
sa->endBlock(sablock);
529
for(;iterations<EPA_maxiterations;++iterations)
531
Face* bf = FindBest();
534
GJK::Mkv* w = Support(-bf->n);
535
const F d(bf->n.dot(w->w)+bf->d);
545
nf+=BuildHorizon(markid,w,*bf->f[i],bf->e[i],cf,ff); }
551
/* Extract contact */
554
const Vector3 b(GetCoordinates(bestface));
555
normal = bestface->n;
556
depth = Max<F>(0,bestface->d);
559
const F s(F(i?-1:1));
562
features[i][j]=gjk->LocalSupport(s*bestface->v[j]->r,i);
565
nearest[0] = features[0][0]*b.x()+features[0][1]*b.y()+features[0][2]*b.z();
566
nearest[1] = features[1][0]*b.x()+features[1][1]*b.y()+features[1][2]*b.z();
568
sa->endBlock(sablock);
578
using namespace gjkepa_impl;
583
bool btGjkEpaSolver::Collide(btConvexShape *shape0,const btTransform &wtrs0,
584
btConvexShape *shape1,const btTransform &wtrs1,
585
btScalar radialmargin,
586
btStackAlloc* stackAlloc,
592
results.witnesses[0] =
593
results.witnesses[1] =
594
results.normal = Vector3(0,0,0);
596
results.status = sResults::Separated;
597
results.epa_iterations = 0;
598
results.gjk_iterations = 0;
599
/* Use GJK to locate origin */
601
wtrs0.getBasis(),wtrs0.getOrigin(),shape0,
602
wtrs1.getBasis(),wtrs1.getOrigin(),shape1,
603
radialmargin+EPA_accuracy);
604
const Z collide(gjk.SearchOrigin());
605
results.gjk_iterations = gjk.iterations+1;
608
/* Then EPA for penetration depth */
610
const F pd(epa.EvaluatePD());
611
results.epa_iterations = epa.iterations+1;
614
results.status = sResults::Penetrating;
615
results.normal = epa.normal;
617
results.witnesses[0] = epa.nearest[0];
618
results.witnesses[1] = epa.nearest[1];
620
} else { if(epa.failed) results.status=sResults::EPA_Failed; }
621
} else { if(gjk.failed) results.status=sResults::GJK_Failed; }