Bullet Collision Detection & Physics Library
btPolyhedralConvexShape.cpp
Go to the documentation of this file.
1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
4 
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 use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 1. 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 
17 #include "btConvexPolyhedron.h"
19 #include <new>
22 
23 
25 m_polyhedron(0)
26 {
27 
28 }
29 
31 {
32  if (m_polyhedron)
33  {
36  }
37 }
38 
39 
41 {
42 
43  if (m_polyhedron)
44  {
47  }
48 
49  void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron),16);
50  m_polyhedron = new (mem) btConvexPolyhedron;
51 
53 
54  for (int i=0;i<getNumVertices();i++)
55  {
56  btVector3& newVertex = orgVertices.expand();
57  getVertex(i,newVertex);
58  }
59 
61 
62  if (shiftVerticesByMargin)
63  {
64  btAlignedObjectArray<btVector3> planeEquations;
65  btGeometryUtil::getPlaneEquationsFromVertices(orgVertices,planeEquations);
66 
67  btAlignedObjectArray<btVector3> shiftedPlaneEquations;
68  for (int p=0;p<planeEquations.size();p++)
69  {
70  btVector3 plane = planeEquations[p];
71  // btScalar margin = getMargin();
72  plane[3] -= getMargin();
73  shiftedPlaneEquations.push_back(plane);
74  }
75 
77 
78  btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,tmpVertices);
79 
80  conv.compute(&tmpVertices[0].getX(), sizeof(btVector3),tmpVertices.size(),0.f,0.f);
81  } else
82  {
83 
84  conv.compute(&orgVertices[0].getX(), sizeof(btVector3),orgVertices.size(),0.f,0.f);
85  }
86 
87 
88 
90  int numFaces = conv.faces.size();
91  faceNormals.resize(numFaces);
92  btConvexHullComputer* convexUtil = &conv;
93 
94 
96  tmpFaces.resize(numFaces);
97 
98  int numVertices = convexUtil->vertices.size();
99  m_polyhedron->m_vertices.resize(numVertices);
100  for (int p=0;p<numVertices;p++)
101  {
102  m_polyhedron->m_vertices[p] = convexUtil->vertices[p];
103  }
104 
105 
106  for (int i=0;i<numFaces;i++)
107  {
108  int face = convexUtil->faces[i];
109  //printf("face=%d\n",face);
110  const btConvexHullComputer::Edge* firstEdge = &convexUtil->edges[face];
111  const btConvexHullComputer::Edge* edge = firstEdge;
112 
113  btVector3 edges[3];
114  int numEdges = 0;
115  //compute face normals
116 
117  do
118  {
119 
120  int src = edge->getSourceVertex();
121  tmpFaces[i].m_indices.push_back(src);
122  int targ = edge->getTargetVertex();
123  btVector3 wa = convexUtil->vertices[src];
124 
125  btVector3 wb = convexUtil->vertices[targ];
126  btVector3 newEdge = wb-wa;
127  newEdge.normalize();
128  if (numEdges<2)
129  edges[numEdges++] = newEdge;
130 
131  edge = edge->getNextEdgeOfFace();
132  } while (edge!=firstEdge);
133 
134  btScalar planeEq = 1e30f;
135 
136 
137  if (numEdges==2)
138  {
139  faceNormals[i] = edges[0].cross(edges[1]);
140  faceNormals[i].normalize();
141  tmpFaces[i].m_plane[0] = faceNormals[i].getX();
142  tmpFaces[i].m_plane[1] = faceNormals[i].getY();
143  tmpFaces[i].m_plane[2] = faceNormals[i].getZ();
144  tmpFaces[i].m_plane[3] = planeEq;
145 
146  }
147  else
148  {
149  btAssert(0);//degenerate?
150  faceNormals[i].setZero();
151  }
152 
153  for (int v=0;v<tmpFaces[i].m_indices.size();v++)
154  {
155  btScalar eq = m_polyhedron->m_vertices[tmpFaces[i].m_indices[v]].dot(faceNormals[i]);
156  if (planeEq>eq)
157  {
158  planeEq=eq;
159  }
160  }
161  tmpFaces[i].m_plane[3] = -planeEq;
162  }
163 
164  //merge coplanar faces and copy them to m_polyhedron
165 
166  btScalar faceWeldThreshold= 0.999f;
167  btAlignedObjectArray<int> todoFaces;
168  for (int i=0;i<tmpFaces.size();i++)
169  todoFaces.push_back(i);
170 
171  while (todoFaces.size())
172  {
173  btAlignedObjectArray<int> coplanarFaceGroup;
174  int refFace = todoFaces[todoFaces.size()-1];
175 
176  coplanarFaceGroup.push_back(refFace);
177  btFace& faceA = tmpFaces[refFace];
178  todoFaces.pop_back();
179 
180  btVector3 faceNormalA(faceA.m_plane[0],faceA.m_plane[1],faceA.m_plane[2]);
181  for (int j=todoFaces.size()-1;j>=0;j--)
182  {
183  int i = todoFaces[j];
184  btFace& faceB = tmpFaces[i];
185  btVector3 faceNormalB(faceB.m_plane[0],faceB.m_plane[1],faceB.m_plane[2]);
186  if (faceNormalA.dot(faceNormalB)>faceWeldThreshold)
187  {
188  coplanarFaceGroup.push_back(i);
189  todoFaces.remove(i);
190  }
191  }
192 
193 
194  bool did_merge = false;
195  if (coplanarFaceGroup.size()>1)
196  {
197  //do the merge: use Graham Scan 2d convex hull
198 
200  btVector3 averageFaceNormal(0,0,0);
201 
202  for (int i=0;i<coplanarFaceGroup.size();i++)
203  {
204 // m_polyhedron->m_faces.push_back(tmpFaces[coplanarFaceGroup[i]]);
205 
206  btFace& face = tmpFaces[coplanarFaceGroup[i]];
207  btVector3 faceNormal(face.m_plane[0],face.m_plane[1],face.m_plane[2]);
208  averageFaceNormal+=faceNormal;
209  for (int f=0;f<face.m_indices.size();f++)
210  {
211  int orgIndex = face.m_indices[f];
212  btVector3 pt = m_polyhedron->m_vertices[orgIndex];
213 
214  bool found = false;
215 
216  for (int i=0;i<orgpoints.size();i++)
217  {
218  //if ((orgpoints[i].m_orgIndex == orgIndex) || ((rotatedPt-orgpoints[i]).length2()<0.0001))
219  if (orgpoints[i].m_orgIndex == orgIndex)
220  {
221  found=true;
222  break;
223  }
224  }
225  if (!found)
226  orgpoints.push_back(GrahamVector3(pt,orgIndex));
227  }
228  }
229 
230 
231 
232  btFace combinedFace;
233  for (int i=0;i<4;i++)
234  combinedFace.m_plane[i] = tmpFaces[coplanarFaceGroup[0]].m_plane[i];
235 
237 
238  averageFaceNormal.normalize();
239  GrahamScanConvexHull2D(orgpoints,hull,averageFaceNormal);
240 
241  for (int i=0;i<hull.size();i++)
242  {
243  combinedFace.m_indices.push_back(hull[i].m_orgIndex);
244  for(int k = 0; k < orgpoints.size(); k++)
245  {
246  if(orgpoints[k].m_orgIndex == hull[i].m_orgIndex)
247  {
248  orgpoints[k].m_orgIndex = -1; // invalidate...
249  break;
250  }
251  }
252  }
253 
254  // are there rejected vertices?
255  bool reject_merge = false;
256 
257 
258 
259  for(int i = 0; i < orgpoints.size(); i++) {
260  if(orgpoints[i].m_orgIndex == -1)
261  continue; // this is in the hull...
262  // this vertex is rejected -- is anybody else using this vertex?
263  for(int j = 0; j < tmpFaces.size(); j++) {
264 
265  btFace& face = tmpFaces[j];
266  // is this a face of the current coplanar group?
267  bool is_in_current_group = false;
268  for(int k = 0; k < coplanarFaceGroup.size(); k++) {
269  if(coplanarFaceGroup[k] == j) {
270  is_in_current_group = true;
271  break;
272  }
273  }
274  if(is_in_current_group) // ignore this face...
275  continue;
276  // does this face use this rejected vertex?
277  for(int v = 0; v < face.m_indices.size(); v++) {
278  if(face.m_indices[v] == orgpoints[i].m_orgIndex) {
279  // this rejected vertex is used in another face -- reject merge
280  reject_merge = true;
281  break;
282  }
283  }
284  if(reject_merge)
285  break;
286  }
287  if(reject_merge)
288  break;
289  }
290 
291  if (!reject_merge)
292  {
293  // do this merge!
294  did_merge = true;
295  m_polyhedron->m_faces.push_back(combinedFace);
296  }
297  }
298  if(!did_merge)
299  {
300  for (int i=0;i<coplanarFaceGroup.size();i++)
301  {
302  btFace face = tmpFaces[coplanarFaceGroup[i]];
304  }
305 
306  }
307 
308 
309 
310  }
311 
313 
314  return true;
315 }
316 
317 #ifndef MIN
318  #define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
319 #endif
320 
322 {
323 
324 
325  btVector3 supVec(0,0,0);
326 #ifndef __SPU__
327  int i;
328  btScalar maxDot(btScalar(-BT_LARGE_FLOAT));
329 
330  btVector3 vec = vec0;
331  btScalar lenSqr = vec.length2();
332  if (lenSqr < btScalar(0.0001))
333  {
334  vec.setValue(1,0,0);
335  } else
336  {
337  btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
338  vec *= rlen;
339  }
340 
341  btVector3 vtx;
342  btScalar newDot;
343 
344  for( int k = 0; k < getNumVertices(); k += 128 )
345  {
346  btVector3 temp[128];
347  int inner_count = MIN(getNumVertices() - k, 128);
348  for( i = 0; i < inner_count; i++ )
349  getVertex(i,temp[i]);
350  i = (int) vec.maxDot( temp, inner_count, newDot);
351  if (newDot > maxDot)
352  {
353  maxDot = newDot;
354  supVec = temp[i];
355  }
356  }
357 
358 #endif //__SPU__
359  return supVec;
360 }
361 
362 
363 
364 void btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const
365 {
366 #ifndef __SPU__
367  int i;
368 
369  btVector3 vtx;
370  btScalar newDot;
371 
372  for (i=0;i<numVectors;i++)
373  {
374  supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT);
375  }
376 
377  for (int j=0;j<numVectors;j++)
378  {
379  const btVector3& vec = vectors[j];
380 
381  for( int k = 0; k < getNumVertices(); k += 128 )
382  {
383  btVector3 temp[128];
384  int inner_count = MIN(getNumVertices() - k, 128);
385  for( i = 0; i < inner_count; i++ )
386  getVertex(i,temp[i]);
387  i = (int) vec.maxDot( temp, inner_count, newDot);
388  if (newDot > supportVerticesOut[j][3])
389  {
390  supportVerticesOut[j] = temp[i];
391  supportVerticesOut[j][3] = newDot;
392  }
393  }
394  }
395 
396 #endif //__SPU__
397 }
398 
399 
400 
402 {
403 #ifndef __SPU__
404  //not yet, return box inertia
405 
406  btScalar margin = getMargin();
407 
408  btTransform ident;
409  ident.setIdentity();
410  btVector3 aabbMin,aabbMax;
411  getAabb(ident,aabbMin,aabbMax);
412  btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5);
413 
414  btScalar lx=btScalar(2.)*(halfExtents.x()+margin);
415  btScalar ly=btScalar(2.)*(halfExtents.y()+margin);
416  btScalar lz=btScalar(2.)*(halfExtents.z()+margin);
417  const btScalar x2 = lx*lx;
418  const btScalar y2 = ly*ly;
419  const btScalar z2 = lz*lz;
420  const btScalar scaledmass = mass * btScalar(0.08333333);
421 
422  inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2));
423 #endif //__SPU__
424 }
425 
426 
427 
429 {
431  recalcLocalAabb();
432 }
433 
436 m_localAabbMin(1,1,1),
437 m_localAabbMax(-1,-1,-1),
438 m_isLocalAabbValid(false)
439 {
440 }
441 
443 {
444  getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin());
445 }
446 
448 {
449  m_isLocalAabbValid = true;
450 
451  #if 1
452  static const btVector3 _directions[] =
453  {
454  btVector3( 1., 0., 0.),
455  btVector3( 0., 1., 0.),
456  btVector3( 0., 0., 1.),
457  btVector3( -1., 0., 0.),
458  btVector3( 0., -1., 0.),
459  btVector3( 0., 0., -1.)
460  };
461 
462  btVector3 _supporting[] =
463  {
464  btVector3( 0., 0., 0.),
465  btVector3( 0., 0., 0.),
466  btVector3( 0., 0., 0.),
467  btVector3( 0., 0., 0.),
468  btVector3( 0., 0., 0.),
469  btVector3( 0., 0., 0.)
470  };
471 
472  batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6);
473 
474  for ( int i = 0; i < 3; ++i )
475  {
476  m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin;
477  m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin;
478  }
479 
480  #else
481 
482  for (int i=0;i<3;i++)
483  {
484  btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.));
485  vec[i] = btScalar(1.);
487  m_localAabbMax[i] = tmp[i];
488  vec[i] = btScalar(-1.);
489  tmp = localGetSupportingVertex(vec);
490  m_localAabbMin[i] = tmp[i];
491  }
492  #endif
493 }
494 
495 
496 
497