123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- /*
- Bullet Continuous Collision Detection and Physics Library
- Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it freely,
- subject to the following restrictions:
- 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.
- 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #if defined(_WIN32) || defined(__i386__)
- #define BT_USE_SSE_IN_API
- #endif
- #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h"
- #include "btConvexPolyhedron.h"
- #include "LinearMath/btConvexHullComputer.h"
- #include <new>
- #include "LinearMath/btGeometryUtil.h"
- #include "LinearMath/btGrahamScan2dConvexHull.h"
- btPolyhedralConvexShape::btPolyhedralConvexShape() : btConvexInternalShape(),
- m_polyhedron(0)
- {
- }
- btPolyhedralConvexShape::~btPolyhedralConvexShape()
- {
- if (m_polyhedron)
- {
- m_polyhedron->~btConvexPolyhedron();
- btAlignedFree(m_polyhedron);
- }
- }
- void btPolyhedralConvexShape::setPolyhedralFeatures(btConvexPolyhedron& polyhedron)
- {
- if (m_polyhedron)
- {
- *m_polyhedron = polyhedron;
- }
- else
- {
- void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron), 16);
- m_polyhedron = new (mem) btConvexPolyhedron(polyhedron);
- }
- }
- bool btPolyhedralConvexShape::initializePolyhedralFeatures(int shiftVerticesByMargin)
- {
- if (m_polyhedron)
- {
- m_polyhedron->~btConvexPolyhedron();
- btAlignedFree(m_polyhedron);
- }
- void* mem = btAlignedAlloc(sizeof(btConvexPolyhedron), 16);
- m_polyhedron = new (mem) btConvexPolyhedron;
- btAlignedObjectArray<btVector3> orgVertices;
- for (int i = 0; i < getNumVertices(); i++)
- {
- btVector3& newVertex = orgVertices.expand();
- getVertex(i, newVertex);
- }
- btConvexHullComputer conv;
- if (shiftVerticesByMargin)
- {
- btAlignedObjectArray<btVector3> planeEquations;
- btGeometryUtil::getPlaneEquationsFromVertices(orgVertices, planeEquations);
- btAlignedObjectArray<btVector3> shiftedPlaneEquations;
- for (int p = 0; p < planeEquations.size(); p++)
- {
- btVector3 plane = planeEquations[p];
- // btScalar margin = getMargin();
- plane[3] -= getMargin();
- shiftedPlaneEquations.push_back(plane);
- }
- btAlignedObjectArray<btVector3> tmpVertices;
- btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations, tmpVertices);
- conv.compute(&tmpVertices[0].getX(), sizeof(btVector3), tmpVertices.size(), 0.f, 0.f);
- }
- else
- {
- conv.compute(&orgVertices[0].getX(), sizeof(btVector3), orgVertices.size(), 0.f, 0.f);
- }
- #ifndef BT_RECONSTRUCT_FACES
- int numVertices = conv.vertices.size();
- m_polyhedron->m_vertices.resize(numVertices);
- for (int p = 0; p < numVertices; p++)
- {
- m_polyhedron->m_vertices[p] = conv.vertices[p];
- }
- int v0, v1;
- for (int j = 0; j < conv.faces.size(); j++)
- {
- btVector3 edges[3];
- int numEdges = 0;
- btFace combinedFace;
- const btConvexHullComputer::Edge* edge = &conv.edges[conv.faces[j]];
- v0 = edge->getSourceVertex();
- int prevVertex = v0;
- combinedFace.m_indices.push_back(v0);
- v1 = edge->getTargetVertex();
- while (v1 != v0)
- {
- btVector3 wa = conv.vertices[prevVertex];
- btVector3 wb = conv.vertices[v1];
- btVector3 newEdge = wb - wa;
- newEdge.normalize();
- if (numEdges < 2)
- edges[numEdges++] = newEdge;
- //face->addIndex(v1);
- combinedFace.m_indices.push_back(v1);
- edge = edge->getNextEdgeOfFace();
- prevVertex = v1;
- int v01 = edge->getSourceVertex();
- v1 = edge->getTargetVertex();
- }
- btAssert(combinedFace.m_indices.size() > 2);
- btVector3 faceNormal = edges[0].cross(edges[1]);
- faceNormal.normalize();
- btScalar planeEq = 1e30f;
- for (int v = 0; v < combinedFace.m_indices.size(); v++)
- {
- btScalar eq = m_polyhedron->m_vertices[combinedFace.m_indices[v]].dot(faceNormal);
- if (planeEq > eq)
- {
- planeEq = eq;
- }
- }
- combinedFace.m_plane[0] = faceNormal.getX();
- combinedFace.m_plane[1] = faceNormal.getY();
- combinedFace.m_plane[2] = faceNormal.getZ();
- combinedFace.m_plane[3] = -planeEq;
- m_polyhedron->m_faces.push_back(combinedFace);
- }
- #else //BT_RECONSTRUCT_FACES
- btAlignedObjectArray<btVector3> faceNormals;
- int numFaces = conv.faces.size();
- faceNormals.resize(numFaces);
- btConvexHullComputer* convexUtil = &conv;
- btAlignedObjectArray<btFace> tmpFaces;
- tmpFaces.resize(numFaces);
- int numVertices = convexUtil->vertices.size();
- m_polyhedron->m_vertices.resize(numVertices);
- for (int p = 0; p < numVertices; p++)
- {
- m_polyhedron->m_vertices[p] = convexUtil->vertices[p];
- }
- for (int i = 0; i < numFaces; i++)
- {
- int face = convexUtil->faces[i];
- //printf("face=%d\n",face);
- const btConvexHullComputer::Edge* firstEdge = &convexUtil->edges[face];
- const btConvexHullComputer::Edge* edge = firstEdge;
- btVector3 edges[3];
- int numEdges = 0;
- //compute face normals
- do
- {
- int src = edge->getSourceVertex();
- tmpFaces[i].m_indices.push_back(src);
- int targ = edge->getTargetVertex();
- btVector3 wa = convexUtil->vertices[src];
- btVector3 wb = convexUtil->vertices[targ];
- btVector3 newEdge = wb - wa;
- newEdge.normalize();
- if (numEdges < 2)
- edges[numEdges++] = newEdge;
- edge = edge->getNextEdgeOfFace();
- } while (edge != firstEdge);
- btScalar planeEq = 1e30f;
- if (numEdges == 2)
- {
- faceNormals[i] = edges[0].cross(edges[1]);
- faceNormals[i].normalize();
- tmpFaces[i].m_plane[0] = faceNormals[i].getX();
- tmpFaces[i].m_plane[1] = faceNormals[i].getY();
- tmpFaces[i].m_plane[2] = faceNormals[i].getZ();
- tmpFaces[i].m_plane[3] = planeEq;
- }
- else
- {
- btAssert(0); //degenerate?
- faceNormals[i].setZero();
- }
- for (int v = 0; v < tmpFaces[i].m_indices.size(); v++)
- {
- btScalar eq = m_polyhedron->m_vertices[tmpFaces[i].m_indices[v]].dot(faceNormals[i]);
- if (planeEq > eq)
- {
- planeEq = eq;
- }
- }
- tmpFaces[i].m_plane[3] = -planeEq;
- }
- //merge coplanar faces and copy them to m_polyhedron
- btScalar faceWeldThreshold = 0.999f;
- btAlignedObjectArray<int> todoFaces;
- for (int i = 0; i < tmpFaces.size(); i++)
- todoFaces.push_back(i);
- while (todoFaces.size())
- {
- btAlignedObjectArray<int> coplanarFaceGroup;
- int refFace = todoFaces[todoFaces.size() - 1];
- coplanarFaceGroup.push_back(refFace);
- btFace& faceA = tmpFaces[refFace];
- todoFaces.pop_back();
- btVector3 faceNormalA(faceA.m_plane[0], faceA.m_plane[1], faceA.m_plane[2]);
- for (int j = todoFaces.size() - 1; j >= 0; j--)
- {
- int i = todoFaces[j];
- btFace& faceB = tmpFaces[i];
- btVector3 faceNormalB(faceB.m_plane[0], faceB.m_plane[1], faceB.m_plane[2]);
- if (faceNormalA.dot(faceNormalB) > faceWeldThreshold)
- {
- coplanarFaceGroup.push_back(i);
- todoFaces.remove(i);
- }
- }
- bool did_merge = false;
- if (coplanarFaceGroup.size() > 1)
- {
- //do the merge: use Graham Scan 2d convex hull
- btAlignedObjectArray<GrahamVector3> orgpoints;
- btVector3 averageFaceNormal(0, 0, 0);
- for (int i = 0; i < coplanarFaceGroup.size(); i++)
- {
- // m_polyhedron->m_faces.push_back(tmpFaces[coplanarFaceGroup[i]]);
- btFace& face = tmpFaces[coplanarFaceGroup[i]];
- btVector3 faceNormal(face.m_plane[0], face.m_plane[1], face.m_plane[2]);
- averageFaceNormal += faceNormal;
- for (int f = 0; f < face.m_indices.size(); f++)
- {
- int orgIndex = face.m_indices[f];
- btVector3 pt = m_polyhedron->m_vertices[orgIndex];
- bool found = false;
- for (int i = 0; i < orgpoints.size(); i++)
- {
- //if ((orgpoints[i].m_orgIndex == orgIndex) || ((rotatedPt-orgpoints[i]).length2()<0.0001))
- if (orgpoints[i].m_orgIndex == orgIndex)
- {
- found = true;
- break;
- }
- }
- if (!found)
- orgpoints.push_back(GrahamVector3(pt, orgIndex));
- }
- }
- btFace combinedFace;
- for (int i = 0; i < 4; i++)
- combinedFace.m_plane[i] = tmpFaces[coplanarFaceGroup[0]].m_plane[i];
- btAlignedObjectArray<GrahamVector3> hull;
- averageFaceNormal.normalize();
- GrahamScanConvexHull2D(orgpoints, hull, averageFaceNormal);
- for (int i = 0; i < hull.size(); i++)
- {
- combinedFace.m_indices.push_back(hull[i].m_orgIndex);
- for (int k = 0; k < orgpoints.size(); k++)
- {
- if (orgpoints[k].m_orgIndex == hull[i].m_orgIndex)
- {
- orgpoints[k].m_orgIndex = -1; // invalidate...
- break;
- }
- }
- }
- // are there rejected vertices?
- bool reject_merge = false;
- for (int i = 0; i < orgpoints.size(); i++)
- {
- if (orgpoints[i].m_orgIndex == -1)
- continue; // this is in the hull...
- // this vertex is rejected -- is anybody else using this vertex?
- for (int j = 0; j < tmpFaces.size(); j++)
- {
- btFace& face = tmpFaces[j];
- // is this a face of the current coplanar group?
- bool is_in_current_group = false;
- for (int k = 0; k < coplanarFaceGroup.size(); k++)
- {
- if (coplanarFaceGroup[k] == j)
- {
- is_in_current_group = true;
- break;
- }
- }
- if (is_in_current_group) // ignore this face...
- continue;
- // does this face use this rejected vertex?
- for (int v = 0; v < face.m_indices.size(); v++)
- {
- if (face.m_indices[v] == orgpoints[i].m_orgIndex)
- {
- // this rejected vertex is used in another face -- reject merge
- reject_merge = true;
- break;
- }
- }
- if (reject_merge)
- break;
- }
- if (reject_merge)
- break;
- }
- if (!reject_merge)
- {
- // do this merge!
- did_merge = true;
- m_polyhedron->m_faces.push_back(combinedFace);
- }
- }
- if (!did_merge)
- {
- for (int i = 0; i < coplanarFaceGroup.size(); i++)
- {
- btFace face = tmpFaces[coplanarFaceGroup[i]];
- m_polyhedron->m_faces.push_back(face);
- }
- }
- }
- #endif //BT_RECONSTRUCT_FACES
- m_polyhedron->initialize();
- return true;
- }
- #ifndef MIN
- #define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
- #endif
- btVector3 btPolyhedralConvexShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0) const
- {
- btVector3 supVec(0, 0, 0);
- #ifndef __SPU__
- int i;
- btScalar maxDot(btScalar(-BT_LARGE_FLOAT));
- btVector3 vec = vec0;
- btScalar lenSqr = vec.length2();
- if (lenSqr < btScalar(0.0001))
- {
- vec.setValue(1, 0, 0);
- }
- else
- {
- btScalar rlen = btScalar(1.) / btSqrt(lenSqr);
- vec *= rlen;
- }
- btVector3 vtx;
- btScalar newDot;
- for (int k = 0; k < getNumVertices(); k += 128)
- {
- btVector3 temp[128];
- int inner_count = MIN(getNumVertices() - k, 128);
- for (i = 0; i < inner_count; i++)
- getVertex(i, temp[i]);
- i = (int)vec.maxDot(temp, inner_count, newDot);
- if (newDot > maxDot)
- {
- maxDot = newDot;
- supVec = temp[i];
- }
- }
- #endif //__SPU__
- return supVec;
- }
- void btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors, btVector3* supportVerticesOut, int numVectors) const
- {
- #ifndef __SPU__
- int i;
- btVector3 vtx;
- btScalar newDot;
- for (i = 0; i < numVectors; i++)
- {
- supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT);
- }
- for (int j = 0; j < numVectors; j++)
- {
- const btVector3& vec = vectors[j];
- for (int k = 0; k < getNumVertices(); k += 128)
- {
- btVector3 temp[128];
- int inner_count = MIN(getNumVertices() - k, 128);
- for (i = 0; i < inner_count; i++)
- getVertex(i, temp[i]);
- i = (int)vec.maxDot(temp, inner_count, newDot);
- if (newDot > supportVerticesOut[j][3])
- {
- supportVerticesOut[j] = temp[i];
- supportVerticesOut[j][3] = newDot;
- }
- }
- }
- #endif //__SPU__
- }
- void btPolyhedralConvexShape::calculateLocalInertia(btScalar mass, btVector3& inertia) const
- {
- #ifndef __SPU__
- //not yet, return box inertia
- btScalar margin = getMargin();
- btTransform ident;
- ident.setIdentity();
- btVector3 aabbMin, aabbMax;
- getAabb(ident, aabbMin, aabbMax);
- btVector3 halfExtents = (aabbMax - aabbMin) * btScalar(0.5);
- btScalar lx = btScalar(2.) * (halfExtents.x() + margin);
- btScalar ly = btScalar(2.) * (halfExtents.y() + margin);
- btScalar lz = btScalar(2.) * (halfExtents.z() + margin);
- const btScalar x2 = lx * lx;
- const btScalar y2 = ly * ly;
- const btScalar z2 = lz * lz;
- const btScalar scaledmass = mass * btScalar(0.08333333);
- inertia = scaledmass * (btVector3(y2 + z2, x2 + z2, x2 + y2));
- #endif //__SPU__
- }
- void btPolyhedralConvexAabbCachingShape::setLocalScaling(const btVector3& scaling)
- {
- btConvexInternalShape::setLocalScaling(scaling);
- recalcLocalAabb();
- }
- btPolyhedralConvexAabbCachingShape::btPolyhedralConvexAabbCachingShape()
- : btPolyhedralConvexShape(),
- m_localAabbMin(1, 1, 1),
- m_localAabbMax(-1, -1, -1),
- m_isLocalAabbValid(false)
- {
- }
- void btPolyhedralConvexAabbCachingShape::getAabb(const btTransform& trans, btVector3& aabbMin, btVector3& aabbMax) const
- {
- getNonvirtualAabb(trans, aabbMin, aabbMax, getMargin());
- }
- void btPolyhedralConvexAabbCachingShape::recalcLocalAabb()
- {
- m_isLocalAabbValid = true;
- #if 1
- static const btVector3 _directions[] =
- {
- btVector3(1., 0., 0.),
- btVector3(0., 1., 0.),
- btVector3(0., 0., 1.),
- btVector3(-1., 0., 0.),
- btVector3(0., -1., 0.),
- btVector3(0., 0., -1.)};
- btVector3 _supporting[] =
- {
- btVector3(0., 0., 0.),
- btVector3(0., 0., 0.),
- btVector3(0., 0., 0.),
- btVector3(0., 0., 0.),
- btVector3(0., 0., 0.),
- btVector3(0., 0., 0.)};
- batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6);
- for (int i = 0; i < 3; ++i)
- {
- m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin;
- m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin;
- }
- #else
- for (int i = 0; i < 3; i++)
- {
- btVector3 vec(btScalar(0.), btScalar(0.), btScalar(0.));
- vec[i] = btScalar(1.);
- btVector3 tmp = localGetSupportingVertex(vec);
- m_localAabbMax[i] = tmp[i];
- vec[i] = btScalar(-1.);
- tmp = localGetSupportingVertex(vec);
- m_localAabbMin[i] = tmp[i];
- }
- #endif
- }
|