void VoronoiFractureDemo::voronoiBBShatter(const btAlignedObjectArray<btVector3>& points, const btVector3& bbmin, const btVector3& bbmax, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) { // points define voronoi cells in world space (avoid duplicates) // bbmin & bbmax = bounding box min and max in local space // bbq & bbt = bounding box quaternion rotation and translation // matDensity = Material density for voronoi shard mass calculation btVector3 bbvx = quatRotate(bbq, btVector3(1.0, 0.0, 0.0)); btVector3 bbvy = quatRotate(bbq, btVector3(0.0, 1.0, 0.0)); btVector3 bbvz = quatRotate(bbq, btVector3(0.0, 0.0, 1.0)); btQuaternion bbiq = bbq.inverse(); btConvexHullComputer* convexHC = new btConvexHullComputer(); btAlignedObjectArray<btVector3> vertices; btVector3 rbb, nrbb; btScalar nlength, maxDistance, distance; btAlignedObjectArray<btVector3> sortedVoronoiPoints; sortedVoronoiPoints.copyFromArray(points); btVector3 normal, plane; btAlignedObjectArray<btVector3> planes; std::set<int> planeIndices; std::set<int>::iterator planeIndicesIter; int numplaneIndices; int cellnum = 0; int i, j, k; int numpoints = points.size(); for (i=0; i < numpoints ;i++) { curVoronoiPoint = points[i]; btVector3 icp = quatRotate(bbiq, curVoronoiPoint - bbt); rbb = icp - bbmax; nrbb = bbmin - icp; planes.resize(6); planes[0] = bbvx; planes[0][3] = rbb.x(); planes[1] = bbvy; planes[1][3] = rbb.y(); planes[2] = bbvz; planes[2][3] = rbb.z(); planes[3] = -bbvx; planes[3][3] = nrbb.x(); planes[4] = -bbvy; planes[4][3] = nrbb.y(); planes[5] = -bbvz; planes[5][3] = nrbb.z(); maxDistance = SIMD_INFINITY; sortedVoronoiPoints.heapSort(pointCmp()); for (j=1; j < numpoints; j++) { normal = sortedVoronoiPoints[j] - curVoronoiPoint; nlength = normal.length(); if (nlength > maxDistance) break; plane = normal.normalized(); plane[3] = -nlength / btScalar(2.); planes.push_back(plane); getVerticesInsidePlanes(planes, vertices, planeIndices); if (vertices.size() == 0) break; numplaneIndices = planeIndices.size(); if (numplaneIndices != planes.size()) { planeIndicesIter = planeIndices.begin(); for (k=0; k < numplaneIndices; k++) { if (k != *planeIndicesIter) planes[k] = planes[*planeIndicesIter]; planeIndicesIter++; } planes.resize(numplaneIndices); } maxDistance = vertices[0].length(); for (k=1; k < vertices.size(); k++) { distance = vertices[k].length(); if (maxDistance < distance) maxDistance = distance; } maxDistance *= btScalar(2.); } if (vertices.size() == 0) continue; // Clean-up voronoi convex shard vertices and generate edges & faces convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),CONVEX_MARGIN,0.0); // At this point we have a complete 3D voronoi shard mesh contained in convexHC // Calculate volume and center of mass (Stan Melax volume integration) int numFaces = convexHC->faces.size(); int v0, v1, v2; // Triangle vertices btScalar volume = btScalar(0.); btVector3 com(0., 0., 0.); for (j=0; j < numFaces; j++) { const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]]; v0 = edge->getSourceVertex(); v1 = edge->getTargetVertex(); edge = edge->getNextEdgeOfFace(); v2 = edge->getTargetVertex(); while (v2 != v0) { // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here... btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]); volume += vol; com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]); edge = edge->getNextEdgeOfFace(); v1 = v2; v2 = edge->getTargetVertex(); } } com /= volume * btScalar(4.); volume /= btScalar(6.); // Shift all vertices relative to center of mass int numVerts = convexHC->vertices.size(); for (j=0; j < numVerts; j++) { convexHC->vertices[j] -= com; } // Note: // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks), // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks. // Use the mesh in convexHC for visual display or to perform boolean operations with. // Create Bullet Physics rigid body shards btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size()); shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this m_collisionShapes.push_back(shardShape); btTransform shardTransform; shardTransform.setIdentity(); shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform); btScalar shardMass(volume * matDensity); btVector3 shardInertia(0.,0.,0.); shardShape->calculateLocalInertia(shardMass, shardInertia); btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia); btRigidBody* shardBody = new btRigidBody(shardRBInfo); m_dynamicsWorld->addRigidBody(shardBody); cellnum ++; } printf("Generated %d voronoi btRigidBody shards\n", cellnum); }
void Voronoi::voronoiBBShatter(const vector<btVector3>& points, const btVector3& bbmin, const btVector3& bbmax, const btQuaternion& bbq, const btVector3& bbt) { // points define voronoi cells in world space (avoid duplicates) // bbmin & bbmax = bounding box min and max in local space // bbq & bbt = bounding box quaternion rotation and translation // matDensity = Material density for voronoi shard mass calculation btVector3 bbvx = quatRotate(bbq, btVector3(1.0, 0.0, 0.0)); btVector3 bbvy = quatRotate(bbq, btVector3(0.0, 1.0, 0.0)); btVector3 bbvz = quatRotate(bbq, btVector3(0.0, 0.0, 1.0)); btQuaternion bbiq = bbq.inverse(); btConvexHullComputer* convexHC = new btConvexHullComputer(); vector<btVector3> vertices; btVector3 rbb, nrbb; btScalar nlength, maxDistance, distance; vector<btVector3> sortedVoronoiPoints; for(unsigned int i = 0; i < points.size(); i++) sortedVoronoiPoints.push_back(points[i]); btVector3 normal, plane; vector<btVector3> planes; std::set<int> planeIndices; std::set<int>::iterator planeIndicesIter; int numplaneIndices; int cellnum = 0; int i, j, k; int numpoints = points.size(); for (i=0; i < numpoints ;i++) { curVoronoiPoint = points[i]; btVector3 icp = quatRotate(bbiq, curVoronoiPoint - bbt); rbb = icp - bbmax; nrbb = bbmin - icp; planes.resize(6); planes[0] = bbvx; planes[0][3] = rbb.x(); planes[1] = bbvy; planes[1][3] = rbb.y(); planes[2] = bbvz; planes[2][3] = rbb.z(); planes[3] = -bbvx; planes[3][3] = nrbb.x(); planes[4] = -bbvy; planes[4][3] = nrbb.y(); planes[5] = -bbvz; planes[5][3] = nrbb.z(); maxDistance = SIMD_INFINITY; sort(sortedVoronoiPoints.begin(), sortedVoronoiPoints.end(), pointCompare); //sortedVoronoiPoints(pointCmp()); for (j=1; j < numpoints; j++) { normal = sortedVoronoiPoints[j] - curVoronoiPoint; nlength = normal.length(); if (nlength > maxDistance) break; plane = normal.normalized(); plane[3] = -nlength / btScalar(2.); planes.push_back(plane); getVerticesInsidePlanes(planes, vertices, planeIndices); if (vertices.size() == 0) break; numplaneIndices = planeIndices.size(); if (numplaneIndices != planes.size()) { planeIndicesIter = planeIndices.begin(); for (k=0; k < numplaneIndices; k++) { if (k != *planeIndicesIter) planes[k] = planes[*planeIndicesIter]; planeIndicesIter++; } planes.resize(numplaneIndices); } maxDistance = vertices[0].length(); for (k=1; k < vertices.size(); k++) { distance = vertices[k].length(); if (maxDistance < distance) maxDistance = distance; } maxDistance *= btScalar(2.); } if (vertices.size() == 0) continue; // Clean-up voronoi convex shard vertices and generate edges & faces convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(), CONVEX_MARGIN,0.0); // At this point we have a complete 3D voronoi shard mesh contained in convexHC // Calculate volume and center of mass (Stan Melax volume integration) int numFaces = convexHC->faces.size(); int v0, v1, v2; // Triangle vertices btScalar volume = btScalar(0.); btVector3 com(0., 0., 0.); for (j=0; j < numFaces; j++) { const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]]; v0 = edge->getSourceVertex(); v1 = edge->getTargetVertex(); edge = edge->getNextEdgeOfFace(); v2 = edge->getTargetVertex(); while (v2 != v0) { // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here... btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]); volume += vol; com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]); edge = edge->getNextEdgeOfFace(); v1 = v2; v2 = edge->getTargetVertex(); } } com /= volume * btScalar(4.); volume /= btScalar(6.); // Shift all vertices relative to center of mass int numVerts = convexHC->vertices.size(); for (j=0; j < numVerts; j++) { convexHC->vertices[j] -= com; } cellnum ++; } }
void QuaternionDiff(const btQuaternion &p, const btQuaternion &q, btQuaternion &qt) { btQuaternion q2 = q.inverse(); qt = q2 * p; qt.normalize(); }