// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2018 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #include "foundation/PxMemory.h" #include "CmPhysXCommon.h" #include "GuPersistentContactManifold.h" #include "GuContactBuffer.h" #include "PsAllocator.h" #include "PsVecTransform.h" #include "PsUtilities.h" using namespace physx; namespace physx { namespace Gu { /* This local function is to avoid DLL call */ static Ps::aos::FloatV distancePointSegmentSquaredLocal(const Ps::aos::Vec3VArg a, const Ps::aos::Vec3VArg b, const Ps::aos::Vec3VArg p) { using namespace Ps::aos; const FloatV zero = FZero(); const FloatV one = FOne(); const Vec3V ap = V3Sub(p, a); const Vec3V ab = V3Sub(b, a); const FloatV nom = V3Dot(ap, ab); const FloatV denom = V3Dot(ab, ab); const FloatV tValue = FClamp(FDiv(nom, denom), zero, one); const FloatV t = FSel(FIsEq(denom, zero), zero, tValue); const Vec3V v = V3NegScaleSub(ab, t, ap); return V3Dot(v, v); } /* This local function is to avoid DLL call */ static Ps::aos::FloatV distancePointTriangleSquaredLocal( const Ps::aos::Vec3VArg p, const Ps::aos::Vec3VArg a, const Ps::aos::Vec3VArg b, const Ps::aos::Vec3VArg c) { using namespace Ps::aos; const FloatV zero = FZero(); //const Vec3V zero = V3Zero(); const Vec3V ab = V3Sub(b, a); const Vec3V ac = V3Sub(c, a); const Vec3V bc = V3Sub(c, b); const Vec3V ap = V3Sub(p, a); const Vec3V bp = V3Sub(p, b); const Vec3V cp = V3Sub(p, c); const FloatV d1 = V3Dot(ab, ap); // snom const FloatV d2 = V3Dot(ac, ap); // tnom const FloatV d3 = V3Dot(ab, bp); // -sdenom const FloatV d4 = V3Dot(ac, bp); // unom = d4 - d3 const FloatV d5 = V3Dot(ab, cp); // udenom = d5 - d6 const FloatV d6 = V3Dot(ac, cp); // -tdenom const FloatV unom = FSub(d4, d3); const FloatV udenom = FSub(d5, d6); //check if p in vertex region outside a const BoolV con00 = FIsGrtr(zero, d1); // snom <= 0 const BoolV con01 = FIsGrtr(zero, d2); // tnom <= 0 const BoolV con0 = BAnd(con00, con01); // vertex region a if(BAllEqTTTT(con0)) { const Vec3V vv = V3Sub(p, a); return V3Dot(vv, vv); } //check if p in vertex region outside b const BoolV con10 = FIsGrtrOrEq(d3, zero); const BoolV con11 = FIsGrtrOrEq(d3, d4); const BoolV con1 = BAnd(con10, con11); // vertex region b if(BAllEqTTTT(con1)) { const Vec3V vv = V3Sub(p, b); return V3Dot(vv, vv); } //check if p in vertex region outside c const BoolV con20 = FIsGrtrOrEq(d6, zero); const BoolV con21 = FIsGrtrOrEq(d6, d5); const BoolV con2 = BAnd(con20, con21); // vertex region c if(BAllEqTTTT(con2)) { const Vec3V vv = V3Sub(p, c); return V3Dot(vv, vv); } //check if p in edge region of AB const FloatV vc = FSub(FMul(d1, d4), FMul(d3, d2)); const BoolV con30 = FIsGrtr(zero, vc); const BoolV con31 = FIsGrtrOrEq(d1, zero); const BoolV con32 = FIsGrtr(zero, d3); const BoolV con3 = BAnd(con30, BAnd(con31, con32)); if(BAllEqTTTT(con3)) { const FloatV sScale = FDiv(d1, FSub(d1, d3)); const Vec3V closest3 = V3ScaleAdd(ab, sScale, a);//V3Add(a, V3Scale(ab, sScale)); const Vec3V vv = V3Sub(p, closest3); return V3Dot(vv, vv); } //check if p in edge region of BC const FloatV va = FSub(FMul(d3, d6),FMul(d5, d4)); const BoolV con40 = FIsGrtr(zero, va); const BoolV con41 = FIsGrtrOrEq(d4, d3); const BoolV con42 = FIsGrtrOrEq(d5, d6); const BoolV con4 = BAnd(con40, BAnd(con41, con42)); if(BAllEqTTTT(con4)) { const FloatV uScale = FDiv(unom, FAdd(unom, udenom)); const Vec3V closest4 = V3ScaleAdd(bc, uScale, b);//V3Add(b, V3Scale(bc, uScale)); const Vec3V vv = V3Sub(p, closest4); return V3Dot(vv, vv); } //check if p in edge region of AC const FloatV vb = FSub(FMul(d5, d2), FMul(d1, d6)); const BoolV con50 = FIsGrtr(zero, vb); const BoolV con51 = FIsGrtrOrEq(d2, zero); const BoolV con52 = FIsGrtr(zero, d6); const BoolV con5 = BAnd(con50, BAnd(con51, con52)); if(BAllEqTTTT(con5)) { const FloatV tScale = FDiv(d2, FSub(d2, d6)); const Vec3V closest5 = V3ScaleAdd(ac, tScale, a);//V3Add(a, V3Scale(ac, tScale)); const Vec3V vv = V3Sub(p, closest5); return V3Dot(vv, vv); } //P must project inside face region. Compute Q using Barycentric coordinates const Vec3V n = V3Cross(ab, ac); const FloatV nn = V3Dot(n,n); const FloatV t = FSel(FIsGrtr(nn, zero),FDiv(V3Dot(n, V3Sub(a, p)), nn), zero); const Vec3V closest6 = V3Add(p, V3Scale(n, t)); const Vec3V vv = V3Sub(p, closest6); return V3Dot(vv, vv); } //This is the translational threshold used in invalidate_BoxConvexHull. 0.5 is 50% of the object margin. we use different threshold between //0 and 4 points. This threashold is a scale that is multiplied by the objects' margins. const PxF32 invalidateThresholds[5] = { 0.5f, 0.125f, 0.25f, 0.375f, 0.375f }; //This is the translational threshold used in invalidate_SphereCapsule. 0.5 is 50% of the object margin, we use different threshold between //0 and 2 points. This threshold is a scale that is multiplied by the objects' margin const PxF32 invalidateThresholds2[3] = { 0.5f, 0.1f, 0.75f }; //This is the rotational threshold used in invalidate_BoxConvexHull. 0.9998 is a threshold for quat difference //between previous and current frame const PxF32 invalidateQuatThresholds[5] = { 0.9998f, 0.9999f, 0.9999f, 0.9999f, 0.9999f }; //This is the rotational threshold used in invalidate_SphereCapsule. 0.9995f is a threshold for quat difference //between previous and current frame const PxF32 invalidateQuatThresholds2[3] = { 0.9995f, 0.9999f, 0.9997f }; } } #if VISUALIZE_PERSISTENT_CONTACT #include "CmRenderOutput.h" static void drawManifoldPoint(const Gu::PersistentContact& manifold, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB, Cm::RenderOutput& out, PxU32 color=0xffffff) { PX_UNUSED(color); using namespace Ps::aos; const Vec3V worldA = trA.transform(manifold.mLocalPointA); const Vec3V worldB = trB.transform(manifold.mLocalPointB); const Vec3V localNormal = Vec3V_From_Vec4V(manifold.mLocalNormalPen); const FloatV pen = V4GetW(manifold.mLocalNormalPen); const Vec3V worldNormal = trB.rotate(localNormal); PxVec3 a, b, v; V3StoreU(worldA, a); V3StoreU(worldB, b); V3StoreU(worldNormal, v); PxF32 dist; FStore(pen, &dist); PxVec3 e = a - v*dist; PxF32 size = 0.05f; const PxVec3 up(0.f, size, 0.f); const PxVec3 right(size, 0.f, 0.f); const PxVec3 forwards(0.f, 0.f, size); PxF32 size2 = 0.1f; const PxVec3 up2(0.f, size2, 0.f); const PxVec3 right2(size2, 0.f, 0.f); const PxVec3 forwards2(0.f, 0.f, size2); PxMat44 m = PxMat44(PxIdentity); out << 0xffff00ff << m << Cm::RenderOutput::LINES << a << e; out << 0xff00ffff << m << Cm::RenderOutput::LINES << a + up << a - up; out << 0xff00ffff << m << Cm::RenderOutput::LINES << a + right << a - right; out << 0xff00ffff << m << Cm::RenderOutput::LINES << a + forwards << a - forwards; out << 0xffff0000 << m << Cm::RenderOutput::LINES << b + up2 << b - up2; out << 0xffff0000 << m << Cm::RenderOutput::LINES << b + right2 << b - right2; out << 0xffff0000 << m << Cm::RenderOutput::LINES << b + forwards2 << b - forwards2; out << 0xffff0000 << m << Cm::RenderOutput::LINES << a << b; } static void drawManifoldPoint(const Gu::PersistentContact& manifold, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB, const Ps::aos::FloatVArg radius, Cm::RenderOutput& out, PxU32 color=0xffffff) { PX_UNUSED(color); using namespace Ps::aos; const Vec3V localNormal = Vec3V_From_Vec4V(manifold.mLocalNormalPen); const Vec3V worldNormal = trB.rotate(localNormal); const Vec3V worldA = V3NegScaleSub(worldNormal, radius, trA.transform(manifold.mLocalPointA)); const Vec3V worldB = trB.transform(manifold.mLocalPointB); const FloatV pen = FSub(V4GetW(manifold.mLocalNormalPen), radius); PxVec3 a, b, v; V3StoreU(worldA, a); V3StoreU(worldB, b); V3StoreU(worldNormal, v); PxF32 dist; FStore(pen, &dist); PxVec3 e = a - v*dist; PxF32 size = 0.05f; const PxVec3 up(0.f, size, 0.f); const PxVec3 right(size, 0.f, 0.f); const PxVec3 forwards(0.f, 0.f, size); PxF32 size2 = 0.1f; const PxVec3 up2(0.f, size2, 0.f); const PxVec3 right2(size2, 0.f, 0.f); const PxVec3 forwards2(0.f, 0.f, size2); PxMat44 m = PxMat44(PxIdentity); out << 0xffff00ff << m << Cm::RenderOutput::LINES << a << e; out << 0xff00ffff << m << Cm::RenderOutput::LINES << a + up << a - up; out << 0xff00ffff << m << Cm::RenderOutput::LINES << a + right << a - right; out << 0xff00ffff << m << Cm::RenderOutput::LINES << a + forwards << a - forwards; out << 0xffff0000 << m << Cm::RenderOutput::LINES << b + up2 << b - up2; out << 0xffff0000 << m << Cm::RenderOutput::LINES << b + right2 << b - right2; out << 0xffff0000 << m << Cm::RenderOutput::LINES << b + forwards2 << b - forwards2; out << 0xffff0000 << m << Cm::RenderOutput::LINES << a << b; } static PxU32 gColors[8] = { 0xff0000ff, 0xff00ff00, 0xffff0000, 0xff00ffff, 0xffff00ff, 0xffffff00, 0xff000080, 0xff008000}; #endif /* SIMD version */ Ps::aos::Mat33V Gu::findRotationMatrixFromZAxis(const Ps::aos::Vec3VArg to) { using namespace Ps::aos; const FloatV one = FOne(); const FloatV threshold = FLoad(0.9999f); const FloatV e = V3GetZ(to); const FloatV f = FAbs(e); if(FAllGrtr(threshold, f)) { const FloatV vx = FNeg(V3GetY(to)); const FloatV vy = V3GetX(to); const FloatV h = FRecip(FAdd(one, e)); const FloatV hvx = FMul(h,vx); const FloatV hvxy = FMul(hvx, vy); const Vec3V col0 = V3Merge(FScaleAdd(hvx, vx, e), hvxy, vy); const Vec3V col1 = V3Merge(hvxy, FScaleAdd(h, FMul(vy, vy), e), FNeg(vx)); const Vec3V col2 = V3Merge(FNeg(vy), vx, e); return Mat33V(col0, col1, col2); } else { const FloatV two = FLoad(2.f); const Vec3V from = V3UnitZ(); const Vec3V absFrom = V3UnitY(); const Vec3V u = V3Sub(absFrom, from); const Vec3V v = V3Sub(absFrom, to); const FloatV dotU = V3Dot(u, u); const FloatV dotV = V3Dot(v, v); const FloatV dotUV = V3Dot(u, v); const FloatV c1 = FNeg(FDiv(two, dotU)); const FloatV c2 = FNeg(FDiv(two, dotV)); const FloatV c3 = FMul(c1, FMul(c2, dotUV)); const Vec3V c1u = V3Scale(u, c1); const Vec3V c2v = V3Scale(v, c2); const Vec3V c3v = V3Scale(v, c3); FloatV temp0 = V3GetX(c1u); FloatV temp1 = V3GetX(c2v); FloatV temp2 = V3GetX(c3v); Vec3V col0 = V3ScaleAdd(u, temp0, V3ScaleAdd(v, temp1, V3Scale(u, temp2))); col0 = V3SetX(col0, FAdd(V3GetX(col0), one)); temp0 = V3GetY(c1u); temp1 = V3GetY(c2v); temp2 = V3GetY(c3v); Vec3V col1 = V3ScaleAdd(u, temp0, V3ScaleAdd(v, temp1, V3Scale(u, temp2))); col1 = V3SetY(col1, FAdd(V3GetY(col1), one)); temp0 = V3GetZ(c1u); temp1 = V3GetZ(c2v); temp2 = V3GetZ(c3v); Vec3V col2 = V3ScaleAdd(u, temp0, V3ScaleAdd(v, temp1, V3Scale(u, temp2))); col2 = V3SetZ(col2, FAdd(V3GetZ(col2), one)); return Mat33V(col0, col1, col2); } } void Gu::PersistentContactManifold::drawManifold( Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT PxVec3 a, b; V3StoreU(trA.p, a); V3StoreU(trB.p, b); for(PxU32 i = 0; i< mNumContacts; ++i) { Gu::PersistentContact& m = mContactPoints[i]; drawManifoldPoint(m, trA, trB, out, gColors[i]); } #else PX_UNUSED(out); PX_UNUSED(trA); PX_UNUSED(trB); #endif } void Gu::PersistentContactManifold::drawManifold( Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB, const Ps::aos::FloatVArg radius) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT PxVec3 a, b; V3StoreU(trA.p, a); V3StoreU(trB.p, b); for(PxU32 i = 0; i< mNumContacts; ++i) { Gu::PersistentContact& m = mContactPoints[i]; drawManifoldPoint(m, trA, trB, radius, out, gColors[i]); } #else PX_UNUSED(out); PX_UNUSED(trA); PX_UNUSED(trB); PX_UNUSED(radius); #endif } void Gu::PersistentContactManifold::drawManifold(const Gu::PersistentContact& m, Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB) { #if VISUALIZE_PERSISTENT_CONTACT drawManifoldPoint(m, trA, trB, out, gColors[0]); #else PX_UNUSED(out); PX_UNUSED(trA); PX_UNUSED(trB); PX_UNUSED(m); #endif } void Gu::PersistentContactManifold::drawPoint(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p, const PxF32 size, const PxU32 color) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT const PxVec3 up(0.f, size, 0.f); const PxVec3 right(size, 0.f, 0.f); const PxVec3 forwards(0.f, 0.f, size); PxVec3 a; V3StoreU(p, a); PxMat44 m = PxMat44(PxIdentity); out << color << m << Cm::RenderOutput::LINES << a + up << a - up; out << color << m << Cm::RenderOutput::LINES << a + right << a - right; out << color << m << Cm::RenderOutput::LINES << a + forwards << a - forwards; #else PX_UNUSED(out); PX_UNUSED(p); PX_UNUSED(size); PX_UNUSED(color); #endif } void Gu::PersistentContactManifold::drawLine(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p0, const Ps::aos::Vec3VArg p1, const PxU32 color) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT PxVec3 a, b; V3StoreU(p0, a); V3StoreU(p1, b); PxMat44 m = PxMat44(PxIdentity); out << color << m << Cm::RenderOutput::LINES << a << b; #else PX_UNUSED(out); PX_UNUSED(p0); PX_UNUSED(p1); PX_UNUSED(color); #endif } void Gu::PersistentContactManifold::drawTriangle(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p0, const Ps::aos::Vec3VArg p1, const Ps::aos::Vec3VArg p2, const PxU32 color) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT PxVec3 a, b, c; V3StoreU(p0, a); V3StoreU(p1, b); V3StoreU(p2, c); PxMat44 m = PxMat44(PxIdentity); out << color << m << Cm::RenderOutput::TRIANGLES << a << b << c; #else PX_UNUSED(out); PX_UNUSED(p0); PX_UNUSED(p1); PX_UNUSED(p2); PX_UNUSED(color); #endif } void Gu::PersistentContactManifold::drawPolygon( Cm::RenderOutput& out, const Ps::aos::PsTransformV& transform, Ps::aos::Vec3V* points, const PxU32 numVerts, const PxU32 color) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT for(PxU32 i=0; i(&contact.normal.x)); V4StoreA(Vec4V_From_Vec3V(worldP), reinterpret_cast(&contact.point.x)); FStore(dist, &contact.separation); PX_ASSERT(contact.point.isFinite()); PX_ASSERT(contact.normal.isFinite()); PX_ASSERT(PxIsFinite(contact.separation)); contact.internalFaceIndex1 = PXC_CONTACT_NO_FACE_INDEX; } } contactBuffer.count = contactCount; } /* This function is for direct implementation for box vs box. We don't need to discard the contacts based on whether the contact offset is larger than penetration/dist because the direct implementation will guarantee the penetration/dist won't be larger than the contact offset. Also, we won't have points from the cache if the direct implementation of box vs box is called. */ void Gu::PersistentContactManifold::addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::Vec3VArg normal, const Ps::aos::PsMatTransformV& transf1) { using namespace Ps::aos; //add the manifold contacts; PxU32 contactCount = 0;//contactBuffer.count; for(PxU32 i=0; (i< mNumContacts) & (contactCount < Gu::ContactBuffer::MAX_CONTACTS); ++i) { PersistentContact& p = getContactPoint(i); const Vec3V worldP =transf1.transform(p.mLocalPointB); const FloatV dist = V4GetW(p.mLocalNormalPen); Gu::ContactPoint& contact = contactBuffer.contacts[contactCount++]; //Fast allign store V4StoreA(Vec4V_From_Vec3V(normal), reinterpret_cast(&contact.normal.x)); V4StoreA(Vec4V_From_Vec3V(worldP), reinterpret_cast(&contact.point.x)); FStore(dist, &contact.separation); PX_ASSERT(PxIsFinite(contact.point.x)); PX_ASSERT(PxIsFinite(contact.point.y)); PX_ASSERT(PxIsFinite(contact.point.z)); //PX_ASSERT(contact.separation > -0.2f); contact.internalFaceIndex1 = PXC_CONTACT_NO_FACE_INDEX; } contactBuffer.count = contactCount; } /* This function is for sphere/capsule vs other primitives. We treat sphere as a point and capsule as a segment in the contact gen and store the sphere center or a point in the segment for capsule in the manifold. */ void Gu::PersistentContactManifold::addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::Vec3VArg normal, const Ps::aos::Vec3VArg projectionNormal, const Ps::aos::PsTransformV& transf0, const Ps::aos::FloatVArg radius, const Ps::aos::FloatVArg contactOffset) { using namespace Ps::aos; //add the manifold contacts; PxU32 contactCount = 0;//contactBuffer.count; for(PxU32 i=0; (i< mNumContacts) & (contactCount < Gu::ContactBuffer::MAX_CONTACTS); ++i) { PersistentContact& p = getContactPoint(i); const FloatV dist = FSub(V4GetW(p.mLocalNormalPen), radius); //The newly created points should have a dist < contactOffset. However, points might come from the PCM contact cache so we might still have points which are //larger than contactOffset. The reason why we don't want to discard the contacts in the contact cache whose dist > contactOffset is because the contacts may //only temporarily become separated. The points still project onto roughly the same spot but so, if the bodies move together again, the contacts may be valid again. //This is important when simulating at large time-steps because GJK can only generate 1 point of contact and missing contacts for just a single frame with large time-steps //may introduce noticeable instability. if(FAllGrtrOrEq(contactOffset, dist)) { const Vec3V worldP =V3NegScaleSub(projectionNormal, radius, transf0.transform(p.mLocalPointA)); Gu::ContactPoint& contact = contactBuffer.contacts[contactCount++]; //Fast allign store V4StoreA(Vec4V_From_Vec3V(normal), reinterpret_cast(&contact.normal.x)); V4StoreA(Vec4V_From_Vec3V(worldP), reinterpret_cast(&contact.point.x)); FStore(dist, &contact.separation); //PX_ASSERT(PxAbs(contact.separation) < 2.f); contact.internalFaceIndex1 = PXC_CONTACT_NO_FACE_INDEX; } } contactBuffer.count = contactCount; } /* This function is used in the box/convexhull full manifold contact genenation. We will pass in a list of manifold contacts. If the number of contacts are more than GU_MANIFOLD_CACHE_SIZE, we will need to do contact reduction while we are storing the chosen manifold contacts from the manifold contact list to the manifold contact buffer. */ void Gu::PersistentContactManifold::addBatchManifoldContacts(const PersistentContact* manifoldContacts, const PxU32 numPoints, const PxReal toleranceLength) { if(numPoints <= GU_MANIFOLD_CACHE_SIZE) { for(PxU32 i=0; i 4, we will reduce the contact points to 4 */ void Gu::PersistentContactManifold::reduceBatchContacts(const PersistentContact* manifoldPoints, const PxU32 numPoints, const PxReal tolereanceLength) { using namespace Ps::aos; PxU8 chosenIndices[4]; PxU8 candidates[64]; const FloatV zero = FZero(); const FloatV max = FMax(); const FloatV nmax = FNeg(max); FloatV maxPen = V4GetW(manifoldPoints[0].mLocalNormalPen); FloatV minPen = nmax; PxU32 index = 0; candidates[0] = 0; PxU32 candidateIndex = 0; PxU32 nbCandiates = numPoints; //keep the deepest point, candidateIndex will be the same as index for (PxU32 i = 1; i 2, we will reduce the contact points to 2 */ void Gu::PersistentContactManifold::reduceBatchContacts2(const PersistentContact* manifoldPoints, const PxU32 numPoints) { using namespace Ps::aos; PX_ASSERT(numPoints < 64); bool chosen[64]; physx::PxMemZero(chosen, sizeof(bool)*numPoints); FloatV maxDis = V4GetW(manifoldPoints[0].mLocalNormalPen); PxI32 index = 0; //keep the deepest point for(PxU32 i=1; imStartIndex; jmEndIndex; ++j) { mContactPoints[tempNumContacts++] = manifoldContact[j]; } currentPatch = currentPatch->mNextPatch; } mNumContacts = tempNumContacts; return patch.mPatchMaxPen; } else { //contact reduction const FloatV maxPen = reduceBatchContactsConvex(manifoldContact, numContactExt, patch); mNumContacts = GU_SINGLE_MANIFOLD_CACHE_SIZE; return maxPen; } } Ps::aos::FloatV Gu::SinglePersistentContactManifold::addBatchManifoldContactsSphere(const MeshPersistentContact* manifoldContact, const PxU32 numContactExt, PCMContactPatch& patch, const Ps::aos::FloatVArg replaceBreakingThreshold) { PX_UNUSED(replaceBreakingThreshold); using namespace Ps::aos; const FloatV maxPen = reduceBatchContactsSphere(manifoldContact, numContactExt, patch); mNumContacts = 1; return maxPen; } Ps::aos::FloatV Gu::SinglePersistentContactManifold::addBatchManifoldContactsCapsule(const MeshPersistentContact* manifoldContact, const PxU32 numContactExt, PCMContactPatch& patch, const Ps::aos::FloatVArg replaceBreakingThreshold) { PX_UNUSED(replaceBreakingThreshold); using namespace Ps::aos; if(patch.mTotalSize <=GU_CAPSULE_MANIFOLD_CACHE_SIZE) { PCMContactPatch* currentPatch = &patch; //this is because we already add the manifold contacts into manifoldContact array PxU32 tempNumContacts = 0; while(currentPatch) { for(PxU32 j=currentPatch->mStartIndex; jmEndIndex; ++j) { mContactPoints[tempNumContacts++] = manifoldContact[j]; } currentPatch = currentPatch->mNextPatch; } mNumContacts = tempNumContacts; return patch.mPatchMaxPen; } else { const FloatV maxPen = reduceBatchContactsCapsule(manifoldContact, numContactExt, patch); mNumContacts = GU_CAPSULE_MANIFOLD_CACHE_SIZE; return maxPen; } } Ps::aos::FloatV Gu::SinglePersistentContactManifold::reduceBatchContactsSphere(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch) { PX_UNUSED(numContacts); using namespace Ps::aos; FloatV max = FMax(); FloatV maxDist = max; PxI32 index = -1; PCMContactPatch* currentPatch = &patch; while(currentPatch) { for(PxU32 i=currentPatch->mStartIndex; imEndIndex; ++i) { const FloatV pen = V4GetW(manifoldContactExt[i].mLocalNormalPen); if(FAllGrtr(maxDist, pen)) { maxDist = pen; index = PxI32(i); } } currentPatch = currentPatch->mNextPatch; } PX_ASSERT(index!=-1); mContactPoints[0] = manifoldContactExt[index]; return maxDist; } Ps::aos::FloatV Gu::SinglePersistentContactManifold::reduceBatchContactsCapsule(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch) { using namespace Ps::aos; bool* chosen = reinterpret_cast(PxAlloca(sizeof(bool)*numContacts)); physx::PxMemZero(chosen, sizeof(bool)*numContacts); const FloatV max = FMax(); FloatV maxDis = max; PxI32 index = -1; FloatV maxPen = max; PCMContactPatch* currentPatch = &patch; while(currentPatch) { for(PxU32 i=currentPatch->mStartIndex; imEndIndex; ++i) { const FloatV pen = V4GetW(manifoldContactExt[i].mLocalNormalPen); if(FAllGrtr(maxDis, pen)) { maxDis = pen; index = PxI32(i); } } currentPatch = currentPatch->mNextPatch; } chosen[index] = true; mContactPoints[0] = manifoldContactExt[index]; maxPen = FMin(maxPen, V4GetW(manifoldContactExt[index].mLocalNormalPen)); //calculate the furthest away points Vec3V v = V3Sub(manifoldContactExt[patch.mStartIndex].mLocalPointB, mContactPoints[0].mLocalPointB); maxDis = V3Dot(v, v); index = PxI32(patch.mStartIndex); currentPatch = &patch; while(currentPatch) { for(PxU32 i=currentPatch->mStartIndex; imEndIndex; ++i) { v = V3Sub(manifoldContactExt[i].mLocalPointB, mContactPoints[0].mLocalPointB); const FloatV d = V3Dot(v, v); if(FAllGrtr(d, maxDis)) { maxDis = d; index = PxI32(i); } } currentPatch = currentPatch->mNextPatch; } //PX_ASSERT(chosen[index] == false); chosen[index] = true; mContactPoints[1] = manifoldContactExt[index]; maxPen = FMin(maxPen, V4GetW(manifoldContactExt[index].mLocalNormalPen)); //keep the second deepest point maxDis = max; currentPatch = &patch; while(currentPatch) { for(PxU32 i=currentPatch->mStartIndex; imEndIndex; ++i) { if(!chosen[i]) { const FloatV pen = V4GetW(manifoldContactExt[i].mLocalNormalPen); //const FloatV v = V3Dot(manifoldContactExt[i].mLocalPointB, manifoldContactExt[i].mLocalPointB); if(FAllGrtr(maxDis, pen)) { maxDis = pen; index = PxI32(i); } } } currentPatch = currentPatch->mNextPatch; } //PX_ASSERT(chosen[index] == false); chosen[index] = true; mContactPoints[2] = manifoldContactExt[index]; maxPen = FMin(maxPen, V4GetW(manifoldContactExt[index].mLocalNormalPen)); return maxPen; } Ps::aos::FloatV Gu::SinglePersistentContactManifold::reduceBatchContactsConvex(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch) { using namespace Ps::aos; bool* chosen = reinterpret_cast(PxAlloca(sizeof(bool)*numContacts)); physx::PxMemZero(chosen, sizeof(bool)*numContacts); const FloatV max = FMax(); const FloatV nmax = FNeg(max); FloatV maxDis = nmax; PxU32 index = GU_MANIFOLD_INVALID_INDEX; PCMContactPatch* currentPatch = &patch; while(currentPatch) { for(PxU32 i=currentPatch->mStartIndex; imEndIndex; ++i) { //const FloatV pen = V4GetW(manifoldContactExt[i].localNormalPen); const FloatV v = V3Dot(manifoldContactExt[i].mLocalPointB, manifoldContactExt[i].mLocalPointB); if(FAllGrtr(v, maxDis)) { maxDis = v; index = i; } } currentPatch = currentPatch->mNextPatch; } chosen[index] = true; const Vec3V contact0 = manifoldContactExt[index].mLocalPointB; mContactPoints[0] = manifoldContactExt[index]; FloatV maxPen = V4GetW(manifoldContactExt[index].mLocalNormalPen); //calculate the furthest away points Vec3V v = V3Sub(manifoldContactExt[patch.mStartIndex].mLocalPointB, contact0); maxDis = V3Dot(v, v); index = patch.mStartIndex; currentPatch = &patch; while(currentPatch) { for(PxU32 i=currentPatch->mStartIndex; imEndIndex; ++i) { v = V3Sub(manifoldContactExt[i].mLocalPointB, contact0); const FloatV d = V3Dot(v, v); if(FAllGrtr(d, maxDis)) { maxDis = d; index = i; } } currentPatch = currentPatch->mNextPatch; } //PX_ASSERT(chosen[index] == false); chosen[index] = true; const Vec3V contact1 = manifoldContactExt[index].mLocalPointB; mContactPoints[1] = manifoldContactExt[index]; maxPen = FMin(maxPen, V4GetW(manifoldContactExt[index].mLocalNormalPen)); maxDis = nmax; index = GU_MANIFOLD_INVALID_INDEX; v = V3Sub(contact1, contact0); const Vec3V cn0 = Vec3V_From_Vec4V(mContactPoints[0].mLocalNormalPen); Vec3V norm = V3Cross(v, cn0); const FloatV sqLen = V3Dot(norm, norm); norm = V3Sel(FIsGrtr(sqLen, FZero()), V3ScaleInv(norm, FSqrt(sqLen)), cn0); FloatV minDis = max; PxU32 index1 = GU_MANIFOLD_INVALID_INDEX; //calculate the point furthest way to the segment currentPatch = &patch; while(currentPatch) { for(PxU32 i=currentPatch->mStartIndex; imEndIndex; ++i) { if(!chosen[i]) { v = V3Sub(manifoldContactExt[i].mLocalPointB, contact0); const FloatV d = V3Dot(v, norm); if(FAllGrtr(d, maxDis)) { maxDis = d; index = i; } if(FAllGrtr(minDis, d)) { minDis = d; index1 = i; } } } currentPatch = currentPatch->mNextPatch; } //PX_ASSERT(chosen[index] == false); chosen[index] = true; mContactPoints[2] = manifoldContactExt[index]; maxPen = FMin(maxPen, V4GetW(manifoldContactExt[index].mLocalNormalPen)); //if min and max in the same side, choose again const FloatV temp = FMul(minDis, maxDis); if(FAllGrtr(temp, FZero())) { //choose again maxDis = nmax; //calculate the point furthest way to the segment currentPatch = &patch; while(currentPatch) { for(PxU32 i=currentPatch->mStartIndex; imEndIndex; ++i) { if(!chosen[i]) { v = V3Sub(manifoldContactExt[i].mLocalPointB, contact0); const FloatV d = V3Dot(v, norm); if(FAllGrtr(d, maxDis)) { maxDis = d; index1 = i; } } } currentPatch = currentPatch->mNextPatch; } } //PX_ASSERT(chosen[index1] == false); chosen[index1] = true; mContactPoints[3] = manifoldContactExt[index1]; maxPen = FMin(maxPen, V4GetW(manifoldContactExt[index1].mLocalNormalPen)); const PxU32 NB_TO_ADD = GU_SINGLE_MANIFOLD_CACHE_SIZE - 4; FloatV pens[NB_TO_ADD]; PxU32 inds[NB_TO_ADD]; for (PxU32 a = 0; a < NB_TO_ADD; ++a) { pens[a] = FMax(); inds[a] = 0; } { currentPatch = &patch; while (currentPatch) { for (PxU32 i = currentPatch->mStartIndex; i < currentPatch->mEndIndex; ++i) { if (!chosen[i]) { const FloatV pen = V4GetW(manifoldContactExt[i].mLocalNormalPen); for (PxU32 a = 0; a < NB_TO_ADD; ++a) { if (FAllGrtr(pens[a], pen)) { for (PxU32 b = a + 1; b < NB_TO_ADD; ++b) { pens[b] = pens[b - 1]; inds[b] = inds[b - 1]; } pens[a] = pen; inds[a] = i; break; } } } } currentPatch = currentPatch->mNextPatch; } for (PxU32 i = 0; i < NB_TO_ADD; ++i) { mContactPoints[i + 4] = manifoldContactExt[inds[i]]; maxPen = FMin(maxPen, pens[i]); } } return maxPen; } PxU32 Gu::SinglePersistentContactManifold::reduceContacts(MeshPersistentContact* manifoldPoints, PxU32 numPoints) { using namespace Ps::aos; PxU8 chosenIndices[GU_SINGLE_MANIFOLD_SINGLE_POLYGONE_CACHE_SIZE]; PxU8* candidates = reinterpret_cast(PxAlloca(sizeof(PxU8) * numPoints)); const FloatV max = FMax(); const FloatV nmax = FNeg(max); const FloatV zero = FZero(); FloatV maxPen = V4GetW(manifoldPoints[0].mLocalNormalPen); PxU32 index = 0; candidates[0] = 0; PxU32 candidateIndex = 0; PxU32 nbCandiates = numPoints; MeshPersistentContact newManifold[GU_SINGLE_MANIFOLD_SINGLE_POLYGONE_CACHE_SIZE]; //keep the deepest point for(PxU32 i=1; i 0; --i) { MeshPersistentContact& manifoldPoint = mContactPoints[i-1]; const Vec3V localAInB = aToB.transform( manifoldPoint.mLocalPointA ); // from a to b const Vec3V localBInB = manifoldPoint.mLocalPointB; const Vec3V v = V3Sub(localAInB, localBInB); const Vec3V localNormal = Vec3V_From_Vec4V(manifoldPoint.mLocalNormalPen); // normal in b space const FloatV dist= V3Dot(v, localNormal); const Vec3V projectedPoint = V3NegScaleSub(localNormal, dist, localAInB);//manifoldPoint.worldPointA - manifoldPoint.worldPointB * manifoldPoint.m_distance1; const Vec3V projectedDifference = V3Sub(localBInB, projectedPoint); const FloatV distance2d = V3Dot(projectedDifference, projectedDifference); //const BoolV con = BOr(FIsGrtr(dist, contactOffset), FIsGrtr(distance2d, sqProjectBreakingThreshold)); const BoolV con = FIsGrtr(distance2d, sqProjectBreakingThreshold); if(BAllEqTTTT(con)) { removeContactPoint(i-1); } else { manifoldPoint.mLocalNormalPen = V4SetW(Vec4V_From_Vec3V(localNormal), dist); maxPen = FMin(maxPen, dist); } } return maxPen; } void Gu::SinglePersistentContactManifold::drawManifold( Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT PxVec3 a, b; V3StoreU(trA.p, a); V3StoreU(trB.p, b); for(PxU32 i = 0; i< mNumContacts; ++i) { Gu::MeshPersistentContact& m = mContactPoints[i]; drawManifoldPoint(m, trA, trB, out, gColors[i]); } #else PX_UNUSED(out); PX_UNUSED(trA); PX_UNUSED(trB); #endif } void Gu::MultiplePersistentContactManifold::drawManifold( Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB) { for(PxU32 i=0; idrawManifold(out, trA, trB); } } void Gu::MultiplePersistentContactManifold::drawLine(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p0, const Ps::aos::Vec3VArg p1, const PxU32 color) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT PxVec3 a, b; V3StoreU(p0, a); V3StoreU(p1, b); PxMat44 m = PxMat44(PxIdentity); out << color << m << Cm::RenderOutput::LINES << a << b; #else PX_UNUSED(out); PX_UNUSED(p0); PX_UNUSED(p1); PX_UNUSED(color); #endif } void Gu::MultiplePersistentContactManifold::drawLine(Cm::RenderOutput& out, const PxVec3 p0, const PxVec3 p1, const PxU32 color) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT PxMat44 m = PxMat44(PxIdentity); out << color << m << Cm::RenderOutput::LINES << p0 << p1; #else PX_UNUSED(out); PX_UNUSED(p0); PX_UNUSED(p1); PX_UNUSED(color); #endif } void Gu::MultiplePersistentContactManifold::drawPoint(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p, const PxF32 size, const PxU32 color) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT const PxVec3 up(0.f, size, 0.f); const PxVec3 right(size, 0.f, 0.f); const PxVec3 forwards(0.f, 0.f, size); PxVec3 a; V3StoreU(p, a); PxMat44 m = PxMat44(PxIdentity); out << color << m << Cm::RenderOutput::LINES << a + up << a - up; out << color << m << Cm::RenderOutput::LINES << a + right << a - right; out << color << m << Cm::RenderOutput::LINES << a + forwards << a - forwards; #else PX_UNUSED(out); PX_UNUSED(p); PX_UNUSED(size); PX_UNUSED(color); #endif } void Gu::MultiplePersistentContactManifold::drawPolygon( Cm::RenderOutput& out, const Ps::aos::PsTransformV& transform, Ps::aos::Vec3V* points, const PxU32 numVerts, const PxU32 color) { using namespace Ps::aos; #if VISUALIZE_PERSISTENT_CONTACT for(PxU32 i=0; iaddBatchManifoldContactsSphere(manifoldContact, numManifoldContacts, *patch, sqReplaceBreakingThreshold); case GU_CAPSULE_MANIFOLD_CACHE_SIZE://capsule, need to implement keep two deepest return manifold->addBatchManifoldContactsCapsule(manifoldContact, numManifoldContacts, *patch, sqReplaceBreakingThreshold); default://cache size GU_SINGLE_MANIFOLD_CACHE_SIZE return manifold->addBatchManifoldContactsConvex(manifoldContact, numManifoldContacts, *patch, sqReplaceBreakingThreshold); }; } /* This function adds the manifold contacts with different patches into the corresponding single persistent contact manifold */ void Gu::MultiplePersistentContactManifold::addManifoldContactPoints(MeshPersistentContact* manifoldContact, PxU32 numManifoldContacts, PCMContactPatch** contactPatch, const PxU32 numPatch, const Ps::aos::FloatVArg sqReplaceBreakingThreshold, const Ps::aos::FloatVArg acceptanceEpsilon, PxU8 maxContactsPerManifold) { using namespace Ps::aos; if(mNumManifolds == 0) { for(PxU32 i=0; imRoot == patch) { SinglePersistentContactManifold* manifold = getEmptyManifold(); if(manifold) { const FloatV _maxPen = addBatchManifoldContactsToSingleManifold(manifold, manifoldContact, numManifoldContacts, patch, sqReplaceBreakingThreshold, maxContactsPerManifold); FStore(_maxPen, &mMaxPen[mManifoldIndices[mNumManifolds]]); mNumManifolds++; } else { //We already pre-sorted the patches so we know we can return here return; } } } } else { //we do processContacts() when the number of contacts are more than 16, such that, we might call processContacts() multiple times when we have very detailed mesh //or very large contact offset/objects. In this case, the mNumManifolds will be large than 0. PCMContactPatch tempPatch; for(PxU32 i=0; imRoot == patch) { PX_ASSERT(mNumManifolds <= GU_MAX_MANIFOLD_SIZE); for(PxU32 j=0; jmPatchNormal, pNor); if(FAllGrtrOrEq(d, acceptanceEpsilon)) { //appending the existing contacts to the manifold contact stream for(PxU32 k=0; k< manifold.mNumContacts; ++k) { PxU32 index = k + numManifoldContacts; //not duplicate point PX_ASSERT(index < 64); manifoldContact[index] = manifold.mContactPoints[k]; } //create a new patch for the exiting manifold tempPatch.mStartIndex = numManifoldContacts; tempPatch.mEndIndex = numManifoldContacts + manifold.mNumContacts; tempPatch.mPatchNormal = pNor;//manifold.getLocalNormal(); tempPatch.mRoot = patch; tempPatch.mNextPatch = NULL; patch->mEndPatch->mNextPatch = &tempPatch; //numManifoldContacts += manifold.numContacts; patch->mTotalSize += manifold.mNumContacts; patch->mPatchMaxPen = FMin(patch->mPatchMaxPen, FLoad(mMaxPen[mManifoldIndices[j]])); //manifold.numContacts = 0; PX_ASSERT((numManifoldContacts+manifold.mNumContacts) <= 64); const FloatV _maxPen = addBatchManifoldContactsToSingleManifold(&manifold, manifoldContact, numManifoldContacts+manifold.mNumContacts, patch, sqReplaceBreakingThreshold, maxContactsPerManifold); FStore(_maxPen, &mMaxPen[mManifoldIndices[j]]); found = true; break; } } if(!found)// && numManifolds < 4) { SinglePersistentContactManifold* manifold = getEmptyManifold(); //we still have slot to create a new manifold if(manifold) { const FloatV _maxPen = addBatchManifoldContactsToSingleManifold(manifold, manifoldContact, numManifoldContacts, patch, sqReplaceBreakingThreshold, maxContactsPerManifold); FStore(_maxPen, &mMaxPen[mManifoldIndices[mNumManifolds]]); mNumManifolds++; } else { //we can't allocate a new manifold and no existing manifold has the same normal as this patch, we need to find the shallowest penetration manifold. If this manifold is shallower than //the current patch, replace the manifold with the current patch PxU32 index = 0; for(PxU32 j=1; j mMaxPen[mManifoldIndices[index]]) { index = j; } } if(FAllGrtr(FLoad(mMaxPen[mManifoldIndices[index]]), patch->mPatchMaxPen)) { manifold = getManifold(index); manifold->mNumContacts = 0; const FloatV _maxPen = addBatchManifoldContactsToSingleManifold(manifold, manifoldContact, numManifoldContacts, patch, sqReplaceBreakingThreshold, maxContactsPerManifold); FStore(_maxPen, &mMaxPen[mManifoldIndices[index]]); } return; } } } } } } //This function adds the multi manifold contacts to the contact buffer for box/convexhull bool Gu::MultiplePersistentContactManifold::addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::PsTransformV& meshTransform) { using namespace Ps::aos; PxU32 contactCount = 0;//contactBuffer.count; PxU32 numContacts = 0; mNumTotalContacts = 0; //drawManifold(*gRenderOutPut, convexTransform, meshTransform); for(PxU32 i=0; i < mNumManifolds; ++i) { Gu::SinglePersistentContactManifold& manifold = *getManifold(i); numContacts = manifold.getNumContacts(); PX_ASSERT(mNumTotalContacts + numContacts <= 0xFF); mNumTotalContacts += Ps::to8(numContacts); const Vec3V normal = manifold.getWorldNormal(meshTransform); for(PxU32 j=0; (j< numContacts) & (contactCount < ContactBuffer::MAX_CONTACTS); ++j) { Gu::MeshPersistentContact& p = manifold.getContactPoint(j); const Vec3V worldP =meshTransform.transform(p.mLocalPointB); const FloatV dist = V4GetW(p.mLocalNormalPen); Gu::ContactPoint& contact = contactBuffer.contacts[contactCount++]; //Fast allign store V4StoreA(Vec4V_From_Vec3V(normal), reinterpret_cast(&contact.normal.x)); V4StoreA(Vec4V_From_Vec3V(worldP), reinterpret_cast(&contact.point.x)); FStore(dist, &contact.separation); contact.internalFaceIndex1 = p.mFaceIndex; } } PX_ASSERT(contactCount <= 64); contactBuffer.count = contactCount; return contactCount > 0; } //This function adds the multi manifold contacts to the contact buffer for sphere and capsule, radius is corresponding to the sphere radius/capsule radius bool Gu::MultiplePersistentContactManifold::addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB, const Ps::aos::FloatVArg radius) { using namespace Ps::aos; PxU32 contactCount = 0; PxU32 numContacts = 0; mNumTotalContacts = 0; for(PxU32 i=0; i < mNumManifolds; ++i) { //get a single manifold Gu::SinglePersistentContactManifold& manifold = *getManifold(i); numContacts = manifold.getNumContacts(); PX_ASSERT(mNumTotalContacts + numContacts <= 0xFF); mNumTotalContacts += Ps::to8(numContacts); const Vec3V normal = manifold.getWorldNormal(trB); //iterate all the contacts in this single manifold and add contacts to the contact buffer //each manifold contact point store two points which are in each other's local space. In this //case, mLocalPointA is stored as the center of sphere/a point in the segment for capsule for(PxU32 j=0; (j< numContacts) & (contactCount < ContactBuffer::MAX_CONTACTS); ++j) { Gu::MeshPersistentContact& p = manifold.getContactPoint(j); const Vec3V worldP =V3NegScaleSub(normal, radius, trA.transform(p.mLocalPointA)); const FloatV dist = FSub(V4GetW(p.mLocalNormalPen), radius); Gu::ContactPoint& contact = contactBuffer.contacts[contactCount++]; //Fast allign store V4StoreA(Vec4V_From_Vec3V(normal), reinterpret_cast(&contact.normal.x)); V4StoreA(Vec4V_From_Vec3V(worldP), reinterpret_cast(&contact.point.x)); FStore(dist, &contact.separation); contact.internalFaceIndex1 = p.mFaceIndex; } } PX_ASSERT(contactCount <= 64); contactBuffer.count = contactCount; return contactCount > 0; } /* This function copies the mesh persistent contact from compress buffer(NpCacheStreamPair in the PxcNpThreadContext) to the multiple manifold */ // PT: function moved to cpp to go around a compiler bug on PS4 void physx::Gu::MultiplePersistentContactManifold::fromBuffer(PxU8* PX_RESTRICT buffer) { using namespace Ps::aos; PxU32 numManifolds = 0; if(buffer != NULL) { PX_ASSERT(((uintptr_t(buffer)) & 0xF) == 0); PxU8* PX_RESTRICT buff = buffer; MultiPersistentManifoldHeader* PX_RESTRICT header = reinterpret_cast(buff); buff += sizeof(MultiPersistentManifoldHeader); numManifolds = header->mNumManifolds; PX_ASSERT(numManifolds <= GU_MAX_MANIFOLD_SIZE); mRelativeTransform = header->mRelativeTransform; for(PxU32 a = 0; a < numManifolds; ++a) { mManifoldIndices[a] = PxU8(a); SingleManifoldHeader* PX_RESTRICT manHeader = reinterpret_cast(buff); buff += sizeof(SingleManifoldHeader); PxU32 numContacts = manHeader->mNumContacts; PX_ASSERT(numContacts <= GU_SINGLE_MANIFOLD_CACHE_SIZE); SinglePersistentContactManifold& manifold = mManifolds[a]; manifold.mNumContacts = numContacts; PX_ASSERT((uintptr_t(buff) & 0xf) == 0); CachedMeshPersistentContact* contacts = reinterpret_cast(buff); for(PxU32 b=0; b