| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- #ifndef B3_CONTACT_CONVEX_CONVEX_SAT_H
- #define B3_CONTACT_CONVEX_CONVEX_SAT_H
- #include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h"
- #include "Bullet3Collision/NarrowPhaseCollision/shared/b3FindSeparatingAxis.h"
- #include "Bullet3Collision/NarrowPhaseCollision/shared/b3ReduceContacts.h"
- #define B3_MAX_VERTS 1024
- inline b3Float4 b3Lerp3(const b3Float4& a, const b3Float4& b, float t)
- {
- return b3MakeVector3(a.x + (b.x - a.x) * t,
- a.y + (b.y - a.y) * t,
- a.z + (b.z - a.z) * t,
- 0.f);
- }
- // Clips a face to the back of a plane, return the number of vertices out, stored in ppVtxOut
- inline int b3ClipFace(const b3Float4* pVtxIn, int numVertsIn, b3Float4& planeNormalWS, float planeEqWS, b3Float4* ppVtxOut)
- {
- int ve;
- float ds, de;
- int numVertsOut = 0;
- if (numVertsIn < 2)
- return 0;
- b3Float4 firstVertex = pVtxIn[numVertsIn - 1];
- b3Float4 endVertex = pVtxIn[0];
- ds = b3Dot3F4(planeNormalWS, firstVertex) + planeEqWS;
- for (ve = 0; ve < numVertsIn; ve++)
- {
- endVertex = pVtxIn[ve];
- de = b3Dot3F4(planeNormalWS, endVertex) + planeEqWS;
- if (ds < 0)
- {
- if (de < 0)
- {
- // Start < 0, end < 0, so output endVertex
- ppVtxOut[numVertsOut++] = endVertex;
- }
- else
- {
- // Start < 0, end >= 0, so output intersection
- ppVtxOut[numVertsOut++] = b3Lerp3(firstVertex, endVertex, (ds * 1.f / (ds - de)));
- }
- }
- else
- {
- if (de < 0)
- {
- // Start >= 0, end < 0 so output intersection and end
- ppVtxOut[numVertsOut++] = b3Lerp3(firstVertex, endVertex, (ds * 1.f / (ds - de)));
- ppVtxOut[numVertsOut++] = endVertex;
- }
- }
- firstVertex = endVertex;
- ds = de;
- }
- return numVertsOut;
- }
- inline int b3ClipFaceAgainstHull(const b3Float4& separatingNormal, const b3ConvexPolyhedronData* hullA,
- const b3Float4& posA, const b3Quaternion& ornA, b3Float4* worldVertsB1, int numWorldVertsB1,
- b3Float4* worldVertsB2, int capacityWorldVertsB2,
- const float minDist, float maxDist,
- const b3AlignedObjectArray<b3Float4>& verticesA, const b3AlignedObjectArray<b3GpuFace>& facesA, const b3AlignedObjectArray<int>& indicesA,
- //const b3Float4* verticesB, const b3GpuFace* facesB, const int* indicesB,
- b3Float4* contactsOut,
- int contactCapacity)
- {
- int numContactsOut = 0;
- b3Float4* pVtxIn = worldVertsB1;
- b3Float4* pVtxOut = worldVertsB2;
- int numVertsIn = numWorldVertsB1;
- int numVertsOut = 0;
- int closestFaceA = -1;
- {
- float dmin = FLT_MAX;
- for (int face = 0; face < hullA->m_numFaces; face++)
- {
- const b3Float4 Normal = b3MakeVector3(
- facesA[hullA->m_faceOffset + face].m_plane.x,
- facesA[hullA->m_faceOffset + face].m_plane.y,
- facesA[hullA->m_faceOffset + face].m_plane.z, 0.f);
- const b3Float4 faceANormalWS = b3QuatRotate(ornA, Normal);
- float d = b3Dot3F4(faceANormalWS, separatingNormal);
- if (d < dmin)
- {
- dmin = d;
- closestFaceA = face;
- }
- }
- }
- if (closestFaceA < 0)
- return numContactsOut;
- b3GpuFace polyA = facesA[hullA->m_faceOffset + closestFaceA];
- // clip polygon to back of planes of all faces of hull A that are adjacent to witness face
- //int numContacts = numWorldVertsB1;
- int numVerticesA = polyA.m_numIndices;
- for (int e0 = 0; e0 < numVerticesA; e0++)
- {
- const b3Float4 a = verticesA[hullA->m_vertexOffset + indicesA[polyA.m_indexOffset + e0]];
- const b3Float4 b = verticesA[hullA->m_vertexOffset + indicesA[polyA.m_indexOffset + ((e0 + 1) % numVerticesA)]];
- const b3Float4 edge0 = a - b;
- const b3Float4 WorldEdge0 = b3QuatRotate(ornA, edge0);
- b3Float4 planeNormalA = b3MakeFloat4(polyA.m_plane.x, polyA.m_plane.y, polyA.m_plane.z, 0.f);
- b3Float4 worldPlaneAnormal1 = b3QuatRotate(ornA, planeNormalA);
- b3Float4 planeNormalWS1 = -b3Cross3(WorldEdge0, worldPlaneAnormal1);
- b3Float4 worldA1 = b3TransformPoint(a, posA, ornA);
- float planeEqWS1 = -b3Dot3F4(worldA1, planeNormalWS1);
- b3Float4 planeNormalWS = planeNormalWS1;
- float planeEqWS = planeEqWS1;
- //clip face
- //clipFace(*pVtxIn, *pVtxOut,planeNormalWS,planeEqWS);
- numVertsOut = b3ClipFace(pVtxIn, numVertsIn, planeNormalWS, planeEqWS, pVtxOut);
- //btSwap(pVtxIn,pVtxOut);
- b3Float4* tmp = pVtxOut;
- pVtxOut = pVtxIn;
- pVtxIn = tmp;
- numVertsIn = numVertsOut;
- numVertsOut = 0;
- }
- // only keep points that are behind the witness face
- {
- b3Float4 localPlaneNormal = b3MakeFloat4(polyA.m_plane.x, polyA.m_plane.y, polyA.m_plane.z, 0.f);
- float localPlaneEq = polyA.m_plane.w;
- b3Float4 planeNormalWS = b3QuatRotate(ornA, localPlaneNormal);
- float planeEqWS = localPlaneEq - b3Dot3F4(planeNormalWS, posA);
- for (int i = 0; i < numVertsIn; i++)
- {
- float depth = b3Dot3F4(planeNormalWS, pVtxIn[i]) + planeEqWS;
- if (depth <= minDist)
- {
- depth = minDist;
- }
- if (numContactsOut < contactCapacity)
- {
- if (depth <= maxDist)
- {
- b3Float4 pointInWorld = pVtxIn[i];
- //resultOut.addContactPoint(separatingNormal,point,depth);
- contactsOut[numContactsOut++] = b3MakeVector3(pointInWorld.x, pointInWorld.y, pointInWorld.z, depth);
- //printf("depth=%f\n",depth);
- }
- }
- else
- {
- b3Error("exceeding contact capacity (%d,%df)\n", numContactsOut, contactCapacity);
- }
- }
- }
- return numContactsOut;
- }
- inline int b3ClipHullAgainstHull(const b3Float4& separatingNormal,
- const b3ConvexPolyhedronData& hullA, const b3ConvexPolyhedronData& hullB,
- const b3Float4& posA, const b3Quaternion& ornA, const b3Float4& posB, const b3Quaternion& ornB,
- b3Float4* worldVertsB1, b3Float4* worldVertsB2, int capacityWorldVerts,
- const float minDist, float maxDist,
- const b3AlignedObjectArray<b3Float4>& verticesA, const b3AlignedObjectArray<b3GpuFace>& facesA, const b3AlignedObjectArray<int>& indicesA,
- const b3AlignedObjectArray<b3Float4>& verticesB, const b3AlignedObjectArray<b3GpuFace>& facesB, const b3AlignedObjectArray<int>& indicesB,
- b3Float4* contactsOut,
- int contactCapacity)
- {
- int numContactsOut = 0;
- int numWorldVertsB1 = 0;
- B3_PROFILE("clipHullAgainstHull");
- //float curMaxDist=maxDist;
- int closestFaceB = -1;
- float dmax = -FLT_MAX;
- {
- //B3_PROFILE("closestFaceB");
- if (hullB.m_numFaces != 1)
- {
- //printf("wtf\n");
- }
- static bool once = true;
- //printf("separatingNormal=%f,%f,%f\n",separatingNormal.x,separatingNormal.y,separatingNormal.z);
- for (int face = 0; face < hullB.m_numFaces; face++)
- {
- #ifdef BT_DEBUG_SAT_FACE
- if (once)
- printf("face %d\n", face);
- const b3GpuFace* faceB = &facesB[hullB.m_faceOffset + face];
- if (once)
- {
- for (int i = 0; i < faceB->m_numIndices; i++)
- {
- b3Float4 vert = verticesB[hullB.m_vertexOffset + indicesB[faceB->m_indexOffset + i]];
- printf("vert[%d] = %f,%f,%f\n", i, vert.x, vert.y, vert.z);
- }
- }
- #endif //BT_DEBUG_SAT_FACE \
- //if (facesB[hullB.m_faceOffset+face].m_numIndices>2)
- {
- const b3Float4 Normal = b3MakeVector3(facesB[hullB.m_faceOffset + face].m_plane.x,
- facesB[hullB.m_faceOffset + face].m_plane.y, facesB[hullB.m_faceOffset + face].m_plane.z, 0.f);
- const b3Float4 WorldNormal = b3QuatRotate(ornB, Normal);
- #ifdef BT_DEBUG_SAT_FACE
- if (once)
- printf("faceNormal = %f,%f,%f\n", Normal.x, Normal.y, Normal.z);
- #endif
- float d = b3Dot3F4(WorldNormal, separatingNormal);
- if (d > dmax)
- {
- dmax = d;
- closestFaceB = face;
- }
- }
- }
- once = false;
- }
- b3Assert(closestFaceB >= 0);
- {
- //B3_PROFILE("worldVertsB1");
- const b3GpuFace& polyB = facesB[hullB.m_faceOffset + closestFaceB];
- const int numVertices = polyB.m_numIndices;
- for (int e0 = 0; e0 < numVertices; e0++)
- {
- const b3Float4& b = verticesB[hullB.m_vertexOffset + indicesB[polyB.m_indexOffset + e0]];
- worldVertsB1[numWorldVertsB1++] = b3TransformPoint(b, posB, ornB);
- }
- }
- if (closestFaceB >= 0)
- {
- //B3_PROFILE("clipFaceAgainstHull");
- numContactsOut = b3ClipFaceAgainstHull((b3Float4&)separatingNormal, &hullA,
- posA, ornA,
- worldVertsB1, numWorldVertsB1, worldVertsB2, capacityWorldVerts, minDist, maxDist,
- verticesA, facesA, indicesA,
- contactsOut, contactCapacity);
- }
- return numContactsOut;
- }
- inline int b3ClipHullHullSingle(
- int bodyIndexA, int bodyIndexB,
- const b3Float4& posA,
- const b3Quaternion& ornA,
- const b3Float4& posB,
- const b3Quaternion& ornB,
- int collidableIndexA, int collidableIndexB,
- const b3AlignedObjectArray<b3RigidBodyData>* bodyBuf,
- b3AlignedObjectArray<b3Contact4Data>* globalContactOut,
- int& nContacts,
- const b3AlignedObjectArray<b3ConvexPolyhedronData>& hostConvexDataA,
- const b3AlignedObjectArray<b3ConvexPolyhedronData>& hostConvexDataB,
- const b3AlignedObjectArray<b3Vector3>& verticesA,
- const b3AlignedObjectArray<b3Vector3>& uniqueEdgesA,
- const b3AlignedObjectArray<b3GpuFace>& facesA,
- const b3AlignedObjectArray<int>& indicesA,
- const b3AlignedObjectArray<b3Vector3>& verticesB,
- const b3AlignedObjectArray<b3Vector3>& uniqueEdgesB,
- const b3AlignedObjectArray<b3GpuFace>& facesB,
- const b3AlignedObjectArray<int>& indicesB,
- const b3AlignedObjectArray<b3Collidable>& hostCollidablesA,
- const b3AlignedObjectArray<b3Collidable>& hostCollidablesB,
- const b3Vector3& sepNormalWorldSpace,
- int maxContactCapacity)
- {
- int contactIndex = -1;
- b3ConvexPolyhedronData hullA, hullB;
- b3Collidable colA = hostCollidablesA[collidableIndexA];
- hullA = hostConvexDataA[colA.m_shapeIndex];
- //printf("numvertsA = %d\n",hullA.m_numVertices);
- b3Collidable colB = hostCollidablesB[collidableIndexB];
- hullB = hostConvexDataB[colB.m_shapeIndex];
- //printf("numvertsB = %d\n",hullB.m_numVertices);
- b3Float4 contactsOut[B3_MAX_VERTS];
- int localContactCapacity = B3_MAX_VERTS;
- #ifdef _WIN32
- b3Assert(_finite(bodyBuf->at(bodyIndexA).m_pos.x));
- b3Assert(_finite(bodyBuf->at(bodyIndexB).m_pos.x));
- #endif
- {
- b3Float4 worldVertsB1[B3_MAX_VERTS];
- b3Float4 worldVertsB2[B3_MAX_VERTS];
- int capacityWorldVerts = B3_MAX_VERTS;
- b3Float4 hostNormal = b3MakeFloat4(sepNormalWorldSpace.x, sepNormalWorldSpace.y, sepNormalWorldSpace.z, 0.f);
- int shapeA = hostCollidablesA[collidableIndexA].m_shapeIndex;
- int shapeB = hostCollidablesB[collidableIndexB].m_shapeIndex;
- b3Scalar minDist = -1;
- b3Scalar maxDist = 0.;
- b3Transform trA, trB;
- {
- //B3_PROFILE("b3TransformPoint computation");
- //trA.setIdentity();
- trA.setOrigin(b3MakeVector3(posA.x, posA.y, posA.z));
- trA.setRotation(b3Quaternion(ornA.x, ornA.y, ornA.z, ornA.w));
- //trB.setIdentity();
- trB.setOrigin(b3MakeVector3(posB.x, posB.y, posB.z));
- trB.setRotation(b3Quaternion(ornB.x, ornB.y, ornB.z, ornB.w));
- }
- b3Quaternion trAorn = trA.getRotation();
- b3Quaternion trBorn = trB.getRotation();
- int numContactsOut = b3ClipHullAgainstHull(hostNormal,
- hostConvexDataA.at(shapeA),
- hostConvexDataB.at(shapeB),
- (b3Float4&)trA.getOrigin(), (b3Quaternion&)trAorn,
- (b3Float4&)trB.getOrigin(), (b3Quaternion&)trBorn,
- worldVertsB1, worldVertsB2, capacityWorldVerts,
- minDist, maxDist,
- verticesA, facesA, indicesA,
- verticesB, facesB, indicesB,
- contactsOut, localContactCapacity);
- if (numContactsOut > 0)
- {
- B3_PROFILE("overlap");
- b3Float4 normalOnSurfaceB = (b3Float4&)hostNormal;
- // b3Float4 centerOut;
- b3Int4 contactIdx;
- contactIdx.x = 0;
- contactIdx.y = 1;
- contactIdx.z = 2;
- contactIdx.w = 3;
- int numPoints = 0;
- {
- B3_PROFILE("extractManifold");
- numPoints = b3ReduceContacts(contactsOut, numContactsOut, normalOnSurfaceB, &contactIdx);
- }
- b3Assert(numPoints);
- if (nContacts < maxContactCapacity)
- {
- contactIndex = nContacts;
- globalContactOut->expand();
- b3Contact4Data& contact = globalContactOut->at(nContacts);
- contact.m_batchIdx = 0; //i;
- contact.m_bodyAPtrAndSignBit = (bodyBuf->at(bodyIndexA).m_invMass == 0) ? -bodyIndexA : bodyIndexA;
- contact.m_bodyBPtrAndSignBit = (bodyBuf->at(bodyIndexB).m_invMass == 0) ? -bodyIndexB : bodyIndexB;
- contact.m_frictionCoeffCmp = 45874;
- contact.m_restituitionCoeffCmp = 0;
- // float distance = 0.f;
- for (int p = 0; p < numPoints; p++)
- {
- contact.m_worldPosB[p] = contactsOut[contactIdx.s[p]]; //check if it is actually on B
- contact.m_worldNormalOnB = normalOnSurfaceB;
- }
- //printf("bodyIndexA %d,bodyIndexB %d,normal=%f,%f,%f numPoints %d\n",bodyIndexA,bodyIndexB,normalOnSurfaceB.x,normalOnSurfaceB.y,normalOnSurfaceB.z,numPoints);
- contact.m_worldNormalOnB.w = (b3Scalar)numPoints;
- nContacts++;
- }
- else
- {
- b3Error("Error: exceeding contact capacity (%d/%d)\n", nContacts, maxContactCapacity);
- }
- }
- }
- return contactIndex;
- }
- inline int b3ContactConvexConvexSAT(
- int pairIndex,
- int bodyIndexA, int bodyIndexB,
- int collidableIndexA, int collidableIndexB,
- const b3AlignedObjectArray<b3RigidBodyData>& rigidBodies,
- const b3AlignedObjectArray<b3Collidable>& collidables,
- const b3AlignedObjectArray<b3ConvexPolyhedronData>& convexShapes,
- const b3AlignedObjectArray<b3Float4>& convexVertices,
- const b3AlignedObjectArray<b3Float4>& uniqueEdges,
- const b3AlignedObjectArray<int>& convexIndices,
- const b3AlignedObjectArray<b3GpuFace>& faces,
- b3AlignedObjectArray<b3Contact4Data>& globalContactsOut,
- int& nGlobalContactsOut,
- int maxContactCapacity)
- {
- int contactIndex = -1;
- b3Float4 posA = rigidBodies[bodyIndexA].m_pos;
- b3Quaternion ornA = rigidBodies[bodyIndexA].m_quat;
- b3Float4 posB = rigidBodies[bodyIndexB].m_pos;
- b3Quaternion ornB = rigidBodies[bodyIndexB].m_quat;
- b3ConvexPolyhedronData hullA, hullB;
- b3Float4 sepNormalWorldSpace;
- b3Collidable colA = collidables[collidableIndexA];
- hullA = convexShapes[colA.m_shapeIndex];
- //printf("numvertsA = %d\n",hullA.m_numVertices);
- b3Collidable colB = collidables[collidableIndexB];
- hullB = convexShapes[colB.m_shapeIndex];
- //printf("numvertsB = %d\n",hullB.m_numVertices);
- #ifdef _WIN32
- b3Assert(_finite(rigidBodies[bodyIndexA].m_pos.x));
- b3Assert(_finite(rigidBodies[bodyIndexB].m_pos.x));
- #endif
- bool foundSepAxis = b3FindSeparatingAxis(hullA, hullB,
- posA,
- ornA,
- posB,
- ornB,
- convexVertices, uniqueEdges, faces, convexIndices,
- convexVertices, uniqueEdges, faces, convexIndices,
- sepNormalWorldSpace);
- if (foundSepAxis)
- {
- contactIndex = b3ClipHullHullSingle(
- bodyIndexA, bodyIndexB,
- posA, ornA,
- posB, ornB,
- collidableIndexA, collidableIndexB,
- &rigidBodies,
- &globalContactsOut,
- nGlobalContactsOut,
- convexShapes,
- convexShapes,
- convexVertices,
- uniqueEdges,
- faces,
- convexIndices,
- convexVertices,
- uniqueEdges,
- faces,
- convexIndices,
- collidables,
- collidables,
- sepNormalWorldSpace,
- maxContactCapacity);
- }
- return contactIndex;
- }
- #endif //B3_CONTACT_CONVEX_CONVEX_SAT_H
|