|
Bullet Collision Detection & Physics Library
|
00001 /* 00002 Bullet Continuous Collision Detection and Physics Library 00003 Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 00004 00005 This software is provided 'as-is', without any express or implied warranty. 00006 In no event will the authors be held liable for any damages arising from the use of this software. 00007 Permission is granted to anyone to use this software for any purpose, 00008 including commercial applications, and to alter it and redistribute it freely, 00009 subject to the following restrictions: 00010 00011 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. 00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 00013 3. This notice may not be removed or altered from any source distribution. 00014 */ 00015 00016 #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" 00017 #include "btConvexPolyhedron.h" 00018 #include "LinearMath/btConvexHullComputer.h" 00019 #include <new> 00020 #include "LinearMath/btGeometryUtil.h" 00021 #include "LinearMath/btGrahamScan2dConvexHull.h" 00022 00023 00024 btPolyhedralConvexShape::btPolyhedralConvexShape() :btConvexInternalShape(), 00025 m_polyhedron(0) 00026 { 00027 00028 } 00029 00030 btPolyhedralConvexShape::~btPolyhedralConvexShape() 00031 { 00032 if (m_polyhedron) 00033 { 00034 btAlignedFree(m_polyhedron); 00035 } 00036 } 00037 00038 00039 bool btPolyhedralConvexShape::initializePolyhedralFeatures() 00040 { 00041 00042 if (m_polyhedron) 00043 btAlignedFree(m_polyhedron); 00044 00045 void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron),16); 00046 m_polyhedron = new (mem) btConvexPolyhedron; 00047 00048 btAlignedObjectArray<btVector3> orgVertices; 00049 00050 for (int i=0;i<getNumVertices();i++) 00051 { 00052 btVector3& newVertex = orgVertices.expand(); 00053 getVertex(i,newVertex); 00054 } 00055 00056 #if 0 00057 btAlignedObjectArray<btVector3> planeEquations; 00058 btGeometryUtil::getPlaneEquationsFromVertices(orgVertices,planeEquations); 00059 00060 btAlignedObjectArray<btVector3> shiftedPlaneEquations; 00061 for (int p=0;p<planeEquations.size();p++) 00062 { 00063 btVector3 plane = planeEquations[p]; 00064 plane[3] -= getMargin(); 00065 shiftedPlaneEquations.push_back(plane); 00066 } 00067 00068 btAlignedObjectArray<btVector3> tmpVertices; 00069 00070 btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,tmpVertices); 00071 btConvexHullComputer conv; 00072 conv.compute(&tmpVertices[0].getX(), sizeof(btVector3),tmpVertices.size(),0.f,0.f); 00073 00074 #else 00075 btConvexHullComputer conv; 00076 conv.compute(&orgVertices[0].getX(), sizeof(btVector3),orgVertices.size(),0.f,0.f); 00077 00078 #endif 00079 00080 00081 00082 btAlignedObjectArray<btVector3> faceNormals; 00083 int numFaces = conv.faces.size(); 00084 faceNormals.resize(numFaces); 00085 btConvexHullComputer* convexUtil = &conv; 00086 00087 00088 btAlignedObjectArray<btFace> tmpFaces; 00089 tmpFaces.resize(numFaces); 00090 00091 int numVertices = convexUtil->vertices.size(); 00092 m_polyhedron->m_vertices.resize(numVertices); 00093 for (int p=0;p<numVertices;p++) 00094 { 00095 m_polyhedron->m_vertices[p] = convexUtil->vertices[p]; 00096 } 00097 00098 00099 for (int i=0;i<numFaces;i++) 00100 { 00101 int face = convexUtil->faces[i]; 00102 //printf("face=%d\n",face); 00103 const btConvexHullComputer::Edge* firstEdge = &convexUtil->edges[face]; 00104 const btConvexHullComputer::Edge* edge = firstEdge; 00105 00106 btVector3 edges[3]; 00107 int numEdges = 0; 00108 //compute face normals 00109 00110 btScalar maxCross2 = 0.f; 00111 int chosenEdge = -1; 00112 00113 do 00114 { 00115 00116 int src = edge->getSourceVertex(); 00117 tmpFaces[i].m_indices.push_back(src); 00118 int targ = edge->getTargetVertex(); 00119 btVector3 wa = convexUtil->vertices[src]; 00120 00121 btVector3 wb = convexUtil->vertices[targ]; 00122 btVector3 newEdge = wb-wa; 00123 newEdge.normalize(); 00124 if (numEdges<2) 00125 edges[numEdges++] = newEdge; 00126 00127 edge = edge->getNextEdgeOfFace(); 00128 } while (edge!=firstEdge); 00129 00130 btScalar planeEq = 1e30f; 00131 00132 00133 if (numEdges==2) 00134 { 00135 faceNormals[i] = edges[0].cross(edges[1]); 00136 faceNormals[i].normalize(); 00137 tmpFaces[i].m_plane[0] = faceNormals[i].getX(); 00138 tmpFaces[i].m_plane[1] = faceNormals[i].getY(); 00139 tmpFaces[i].m_plane[2] = faceNormals[i].getZ(); 00140 tmpFaces[i].m_plane[3] = planeEq; 00141 00142 } 00143 else 00144 { 00145 btAssert(0);//degenerate? 00146 faceNormals[i].setZero(); 00147 } 00148 00149 for (int v=0;v<tmpFaces[i].m_indices.size();v++) 00150 { 00151 btScalar eq = m_polyhedron->m_vertices[tmpFaces[i].m_indices[v]].dot(faceNormals[i]); 00152 if (planeEq>eq) 00153 { 00154 planeEq=eq; 00155 } 00156 } 00157 tmpFaces[i].m_plane[3] = -planeEq; 00158 } 00159 00160 //merge coplanar faces and copy them to m_polyhedron 00161 00162 btScalar faceWeldThreshold= 0.999f; 00163 btAlignedObjectArray<int> todoFaces; 00164 for (int i=0;i<tmpFaces.size();i++) 00165 todoFaces.push_back(i); 00166 00167 while (todoFaces.size()) 00168 { 00169 btAlignedObjectArray<int> coplanarFaceGroup; 00170 int refFace = todoFaces[todoFaces.size()-1]; 00171 00172 coplanarFaceGroup.push_back(refFace); 00173 btFace& faceA = tmpFaces[refFace]; 00174 todoFaces.pop_back(); 00175 00176 btVector3 faceNormalA(faceA.m_plane[0],faceA.m_plane[1],faceA.m_plane[2]); 00177 for (int j=todoFaces.size()-1;j>=0;j--) 00178 { 00179 int i = todoFaces[j]; 00180 btFace& faceB = tmpFaces[i]; 00181 btVector3 faceNormalB(faceB.m_plane[0],faceB.m_plane[1],faceB.m_plane[2]); 00182 if (faceNormalA.dot(faceNormalB)>faceWeldThreshold) 00183 { 00184 coplanarFaceGroup.push_back(i); 00185 todoFaces.remove(i); 00186 } 00187 } 00188 00189 00190 bool did_merge = false; 00191 if (coplanarFaceGroup.size()>1) 00192 { 00193 //do the merge: use Graham Scan 2d convex hull 00194 00195 btAlignedObjectArray<GrahamVector2> orgpoints; 00196 00197 for (int i=0;i<coplanarFaceGroup.size();i++) 00198 { 00199 // m_polyhedron->m_faces.push_back(tmpFaces[coplanarFaceGroup[i]]); 00200 00201 btFace& face = tmpFaces[coplanarFaceGroup[i]]; 00202 btVector3 faceNormal(face.m_plane[0],face.m_plane[1],face.m_plane[2]); 00203 btVector3 xyPlaneNormal(0,0,1); 00204 00205 btQuaternion rotationArc = shortestArcQuat(faceNormal,xyPlaneNormal); 00206 00207 for (int f=0;f<face.m_indices.size();f++) 00208 { 00209 int orgIndex = face.m_indices[f]; 00210 btVector3 pt = m_polyhedron->m_vertices[orgIndex]; 00211 btVector3 rotatedPt = quatRotate(rotationArc,pt); 00212 rotatedPt.setZ(0); 00213 bool found = false; 00214 00215 for (int i=0;i<orgpoints.size();i++) 00216 { 00217 //if ((orgpoints[i].m_orgIndex == orgIndex) || ((rotatedPt-orgpoints[i]).length2()<0.0001)) 00218 if (orgpoints[i].m_orgIndex == orgIndex) 00219 { 00220 found=true; 00221 break; 00222 } 00223 } 00224 if (!found) 00225 orgpoints.push_back(GrahamVector2(rotatedPt,orgIndex)); 00226 } 00227 } 00228 00229 btFace combinedFace; 00230 for (int i=0;i<4;i++) 00231 combinedFace.m_plane[i] = tmpFaces[coplanarFaceGroup[0]].m_plane[i]; 00232 00233 btAlignedObjectArray<GrahamVector2> hull; 00234 GrahamScanConvexHull2D(orgpoints,hull); 00235 00236 for (int i=0;i<hull.size();i++) 00237 { 00238 combinedFace.m_indices.push_back(hull[i].m_orgIndex); 00239 for(int k = 0; k < orgpoints.size(); k++) { 00240 if(orgpoints[k].m_orgIndex == hull[i].m_orgIndex) { 00241 orgpoints[k].m_orgIndex = -1; // invalidate... 00242 break; 00243 } 00244 } 00245 } 00246 // are there rejected vertices? 00247 bool reject_merge = false; 00248 for(int i = 0; i < orgpoints.size(); i++) { 00249 if(orgpoints[i].m_orgIndex == -1) 00250 continue; // this is in the hull... 00251 // this vertex is rejected -- is anybody else using this vertex? 00252 for(int j = 0; j < tmpFaces.size(); j++) { 00253 btFace& face = tmpFaces[j]; 00254 // is this a face of the current coplanar group? 00255 bool is_in_current_group = false; 00256 for(int k = 0; k < coplanarFaceGroup.size(); k++) { 00257 if(coplanarFaceGroup[k] == j) { 00258 is_in_current_group = true; 00259 break; 00260 } 00261 } 00262 if(is_in_current_group) // ignore this face... 00263 continue; 00264 // does this face use this rejected vertex? 00265 for(int v = 0; v < face.m_indices.size(); v++) { 00266 if(face.m_indices[v] == orgpoints[i].m_orgIndex) { 00267 // this rejected vertex is used in another face -- reject merge 00268 reject_merge = true; 00269 break; 00270 } 00271 } 00272 if(reject_merge) 00273 break; 00274 } 00275 if(reject_merge) 00276 break; 00277 } 00278 if(!reject_merge) { 00279 // do this merge! 00280 did_merge = true; 00281 m_polyhedron->m_faces.push_back(combinedFace); 00282 } 00283 } 00284 if(!did_merge) 00285 { 00286 for (int i=0;i<coplanarFaceGroup.size();i++) 00287 { 00288 m_polyhedron->m_faces.push_back(tmpFaces[coplanarFaceGroup[i]]); 00289 } 00290 00291 } 00292 00293 00294 00295 } 00296 00297 m_polyhedron->initialize(); 00298 00299 return true; 00300 } 00301 00302 00303 btVector3 btPolyhedralConvexShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const 00304 { 00305 00306 00307 btVector3 supVec(0,0,0); 00308 #ifndef __SPU__ 00309 int i; 00310 btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); 00311 00312 btVector3 vec = vec0; 00313 btScalar lenSqr = vec.length2(); 00314 if (lenSqr < btScalar(0.0001)) 00315 { 00316 vec.setValue(1,0,0); 00317 } else 00318 { 00319 btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); 00320 vec *= rlen; 00321 } 00322 00323 btVector3 vtx; 00324 btScalar newDot; 00325 00326 for (i=0;i<getNumVertices();i++) 00327 { 00328 getVertex(i,vtx); 00329 newDot = vec.dot(vtx); 00330 if (newDot > maxDot) 00331 { 00332 maxDot = newDot; 00333 supVec = vtx; 00334 } 00335 } 00336 00337 00338 #endif //__SPU__ 00339 return supVec; 00340 } 00341 00342 00343 00344 void btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const 00345 { 00346 #ifndef __SPU__ 00347 int i; 00348 00349 btVector3 vtx; 00350 btScalar newDot; 00351 00352 for (i=0;i<numVectors;i++) 00353 { 00354 supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT); 00355 } 00356 00357 for (int j=0;j<numVectors;j++) 00358 { 00359 00360 const btVector3& vec = vectors[j]; 00361 00362 for (i=0;i<getNumVertices();i++) 00363 { 00364 getVertex(i,vtx); 00365 newDot = vec.dot(vtx); 00366 if (newDot > supportVerticesOut[j][3]) 00367 { 00368 //WARNING: don't swap next lines, the w component would get overwritten! 00369 supportVerticesOut[j] = vtx; 00370 supportVerticesOut[j][3] = newDot; 00371 } 00372 } 00373 } 00374 #endif //__SPU__ 00375 } 00376 00377 00378 00379 void btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const 00380 { 00381 #ifndef __SPU__ 00382 //not yet, return box inertia 00383 00384 btScalar margin = getMargin(); 00385 00386 btTransform ident; 00387 ident.setIdentity(); 00388 btVector3 aabbMin,aabbMax; 00389 getAabb(ident,aabbMin,aabbMax); 00390 btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); 00391 00392 btScalar lx=btScalar(2.)*(halfExtents.x()+margin); 00393 btScalar ly=btScalar(2.)*(halfExtents.y()+margin); 00394 btScalar lz=btScalar(2.)*(halfExtents.z()+margin); 00395 const btScalar x2 = lx*lx; 00396 const btScalar y2 = ly*ly; 00397 const btScalar z2 = lz*lz; 00398 const btScalar scaledmass = mass * btScalar(0.08333333); 00399 00400 inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); 00401 #endif //__SPU__ 00402 } 00403 00404 00405 00406 void btPolyhedralConvexAabbCachingShape::setLocalScaling(const btVector3& scaling) 00407 { 00408 btConvexInternalShape::setLocalScaling(scaling); 00409 recalcLocalAabb(); 00410 } 00411 00412 btPolyhedralConvexAabbCachingShape::btPolyhedralConvexAabbCachingShape() 00413 :btPolyhedralConvexShape(), 00414 m_localAabbMin(1,1,1), 00415 m_localAabbMax(-1,-1,-1), 00416 m_isLocalAabbValid(false) 00417 { 00418 } 00419 00420 void btPolyhedralConvexAabbCachingShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const 00421 { 00422 getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin()); 00423 } 00424 00425 void btPolyhedralConvexAabbCachingShape::recalcLocalAabb() 00426 { 00427 m_isLocalAabbValid = true; 00428 00429 #if 1 00430 static const btVector3 _directions[] = 00431 { 00432 btVector3( 1., 0., 0.), 00433 btVector3( 0., 1., 0.), 00434 btVector3( 0., 0., 1.), 00435 btVector3( -1., 0., 0.), 00436 btVector3( 0., -1., 0.), 00437 btVector3( 0., 0., -1.) 00438 }; 00439 00440 btVector3 _supporting[] = 00441 { 00442 btVector3( 0., 0., 0.), 00443 btVector3( 0., 0., 0.), 00444 btVector3( 0., 0., 0.), 00445 btVector3( 0., 0., 0.), 00446 btVector3( 0., 0., 0.), 00447 btVector3( 0., 0., 0.) 00448 }; 00449 00450 batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6); 00451 00452 for ( int i = 0; i < 3; ++i ) 00453 { 00454 m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin; 00455 m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin; 00456 } 00457 00458 #else 00459 00460 for (int i=0;i<3;i++) 00461 { 00462 btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); 00463 vec[i] = btScalar(1.); 00464 btVector3 tmp = localGetSupportingVertex(vec); 00465 m_localAabbMax[i] = tmp[i]; 00466 vec[i] = btScalar(-1.); 00467 tmp = localGetSupportingVertex(vec); 00468 m_localAabbMin[i] = tmp[i]; 00469 } 00470 #endif 00471 } 00472 00473 00474 00475