Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/physics/src/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGjkPairDetector.cpp @ 1966

Last change on this file since 1966 was 1966, checked in by rgrieder, 16 years ago

Let's go for multithreaded physics!

  • Property svn:eol-style set to native
File size: 8.9 KB
Line 
1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15
16#include "SpuGjkPairDetector.h"
17#include "SpuConvexPenetrationDepthSolver.h"
18#include "SpuCollisionShapes.h"
19
20
21
22#if defined(DEBUG) || defined (_DEBUG)
23#include <stdio.h> //for debug printf
24#ifdef __SPU__
25#include <spu_printf.h>
26#define printf spu_printf
27#endif //__SPU__
28#endif
29
30//must be above the machine epsilon
31#define REL_ERROR2 btScalar(1.0e-6)
32
33//temp globals, to improve GJK/EPA/penetration calculations
34int gSpuNumDeepPenetrationChecks = 0;
35int gSpuNumGjkChecks = 0;
36
37
38
39SpuGjkPairDetector::SpuGjkPairDetector(void* objectA,void* objectB,int shapeTypeA, int shapeTypeB, float marginA,float marginB,SpuVoronoiSimplexSolver* simplexSolver, const SpuConvexPenetrationDepthSolver*   penetrationDepthSolver)
40:m_cachedSeparatingAxis(float(0.),float(0.),float(1.)),
41m_penetrationDepthSolver(penetrationDepthSolver),
42m_simplexSolver(simplexSolver),
43m_minkowskiA(objectA),
44m_minkowskiB(objectB),
45m_shapeTypeA(shapeTypeA),
46m_shapeTypeB(shapeTypeB),
47m_marginA(marginA),
48m_marginB(marginB),
49m_ignoreMargin(false),
50m_lastUsedMethod(-1),
51m_catchDegeneracies(1)
52{
53}
54
55void SpuGjkPairDetector::getClosestPoints(const SpuClosestPointInput& input,SpuContactResult& output)
56{
57        btScalar distance=btScalar(0.);
58        btVector3       normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
59        btVector3 pointOnA,pointOnB;
60        btTransform     localTransA = input.m_transformA;
61        btTransform localTransB = input.m_transformB;
62        btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
63        localTransA.getOrigin() -= positionOffset;
64        localTransB.getOrigin() -= positionOffset;
65
66        btScalar marginA = m_marginA;
67        btScalar marginB = m_marginB;
68
69        gSpuNumGjkChecks++;
70
71        //for CCD we don't use margins
72        if (m_ignoreMargin)
73        {
74                marginA = btScalar(0.);
75                marginB = btScalar(0.);
76        }
77
78        m_curIter = 0;
79        int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN?
80        m_cachedSeparatingAxis.setValue(0,1,0);
81
82        bool isValid = false;
83        bool checkSimplex = false;
84        bool checkPenetration = true;
85        m_degenerateSimplex = 0;
86
87        m_lastUsedMethod = -1;
88
89        {
90                btScalar squaredDistance = SIMD_INFINITY;
91                btScalar delta = btScalar(0.);
92               
93                btScalar margin = marginA + marginB;
94               
95               
96
97                m_simplexSolver->reset();
98               
99                for ( ; ; )
100                //while (true)
101                {
102
103                        btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
104                        btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
105
106//                      btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
107//                      btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
108
109                        btVector3 pInA  = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA);
110                        btVector3 qInB  = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB);
111
112
113                        btPoint3  pWorld = localTransA(pInA);   
114                        btPoint3  qWorld = localTransB(qInB);
115                       
116                        btVector3 w     = pWorld - qWorld;
117                        delta = m_cachedSeparatingAxis.dot(w);
118
119                        // potential exit, they don't overlap
120                        if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared)) 
121                        {
122                                checkPenetration = false;
123                                break;
124                        }
125
126                        //exit 0: the new point is already in the simplex, or we didn't come any closer
127                        if (m_simplexSolver->inSimplex(w))
128                        {
129                                m_degenerateSimplex = 1;
130                                checkSimplex = true;
131                                break;
132                        }
133                        // are we getting any closer ?
134                        btScalar f0 = squaredDistance - delta;
135                        btScalar f1 = squaredDistance * REL_ERROR2;
136
137                        if (f0 <= f1)
138                        {
139                                if (f0 <= btScalar(0.))
140                                {
141                                        m_degenerateSimplex = 2;
142                                }
143                                checkSimplex = true;
144                                break;
145                        }
146                        //add current vertex to simplex
147                        m_simplexSolver->addVertex(w, pWorld, qWorld);
148
149                        //calculate the closest point to the origin (update vector v)
150                        if (!m_simplexSolver->closest(m_cachedSeparatingAxis))
151                        {
152                                m_degenerateSimplex = 3;
153                                checkSimplex = true;
154                                break;
155                        }
156
157                        btScalar previousSquaredDistance = squaredDistance;
158                        squaredDistance = m_cachedSeparatingAxis.length2();
159                       
160                        //redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
161
162                        //are we getting any closer ?
163                        if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance) 
164                        { 
165                                m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
166                                checkSimplex = true;
167                                break;
168                        }
169
170                          //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject   
171              if (m_curIter++ > gGjkMaxIter)   
172              {   
173                      #if defined(DEBUG) || defined (_DEBUG)   
174
175                              printf("SpuGjkPairDetector maxIter exceeded:%i\n",m_curIter);   
176                              printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",   
177                              m_cachedSeparatingAxis.getX(),   
178                              m_cachedSeparatingAxis.getY(),   
179                              m_cachedSeparatingAxis.getZ(),   
180                              squaredDistance,   
181                                                          m_shapeTypeA,   
182                              m_shapeTypeB);
183
184                      #endif   
185                      break;   
186
187              } 
188
189
190                        bool check = (!m_simplexSolver->fullSimplex());
191                        //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
192
193                        if (!check)
194                        {
195                                //do we need this backup_closest here ?
196                                m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
197                                break;
198                        }
199                }
200
201                if (checkSimplex)
202                {
203                        m_simplexSolver->compute_points(pointOnA, pointOnB);
204                        normalInB = pointOnA-pointOnB;
205                        btScalar lenSqr = m_cachedSeparatingAxis.length2();
206                        //valid normal
207                        if (lenSqr < 0.0001)
208                        {
209                                m_degenerateSimplex = 5;
210                        } 
211                        if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
212                        {
213                                btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
214                                normalInB *= rlen; //normalize
215                                btScalar s = btSqrt(squaredDistance);
216                       
217                                btAssert(s > btScalar(0.0));
218                                pointOnA -= m_cachedSeparatingAxis * (marginA / s);
219                                pointOnB += m_cachedSeparatingAxis * (marginB / s);
220                                distance = ((btScalar(1.)/rlen) - margin);
221                                isValid = true;
222                               
223                                m_lastUsedMethod = 1;
224                        } else
225                        {
226                                m_lastUsedMethod = 2;
227                        }
228                }
229
230                bool catchDegeneratePenetrationCase = 
231                        (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
232
233                //if (checkPenetration && !isValid)
234                if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
235                {
236                        //penetration case
237               
238                        //if there is no way to handle penetrations, bail out
239                        if (m_penetrationDepthSolver)
240                        {
241                                // Penetration depth case.
242                                btVector3 tmpPointOnA,tmpPointOnB;
243                               
244                                gSpuNumDeepPenetrationChecks++;
245
246                                bool isValid2 = m_penetrationDepthSolver->calcPenDepth( 
247                                        *m_simplexSolver, 
248                                        m_minkowskiA,m_minkowskiB,
249                    m_shapeTypeA, m_shapeTypeB,
250                    marginA, marginB,
251                                        localTransA,localTransB,
252                                        m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB,
253                                        0,input.m_stackAlloc,input.m_convexVertexData[0], input.m_convexVertexData[1]
254                                        );
255
256                                if (isValid2)
257                                {
258                                        btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
259                                        btScalar lenSqr = tmpNormalInB.length2();
260                                        if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
261                                        {
262                                                tmpNormalInB /= btSqrt(lenSqr);
263                                                btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
264                                                //only replace valid penetrations when the result is deeper (check)
265                                                if (!isValid || (distance2 < distance))
266                                                {
267                                                        distance = distance2;
268                                                        pointOnA = tmpPointOnA;
269                                                        pointOnB = tmpPointOnB;
270                                                        normalInB = tmpNormalInB;
271                                                        isValid = true;
272                                                        m_lastUsedMethod = 3;
273                                                } else
274                                                {
275                                                       
276                                                }
277                                        } else
278                                        {
279                                                //isValid = false;
280                                                m_lastUsedMethod = 4;
281                                        }
282                                } else
283                                {
284                                        m_lastUsedMethod = 5;
285                                }
286                               
287                        }
288                }
289        }
290
291        if (isValid)
292        {
293#ifdef __SPU__
294                //spu_printf("distance\n");
295#endif //__SPU__
296
297
298                output.addContactPoint(
299                        normalInB,
300                        pointOnB+positionOffset,
301                        distance);
302                //printf("gjk add:%f",distance);
303        }
304
305
306}
307
308
309
310
311
Note: See TracBrowser for help on using the repository browser.