aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/GuSweepMTD.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/GeomUtils/src/GuSweepMTD.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/GeomUtils/src/GuSweepMTD.cpp')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/GuSweepMTD.cpp1183
1 files changed, 1183 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/GuSweepMTD.cpp b/PhysX_3.4/Source/GeomUtils/src/GuSweepMTD.cpp
new file mode 100644
index 00000000..d94198b3
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/GuSweepMTD.cpp
@@ -0,0 +1,1183 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 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 "GuHeightFieldUtil.h"
+#include "GuEntityReport.h"
+#include "PxConvexMeshGeometry.h"
+#include "GuConvexMesh.h"
+#include "GuSweepSharedTests.h"
+#include "GuConvexUtilsInternal.h"
+#include "GuTriangleMesh.h"
+#include "GuVecBox.h"
+#include "GuVecTriangle.h"
+#include "GuVecConvexHullNoScale.h"
+#include "GuMidphaseInterface.h"
+#include "GuPCMContactConvexCommon.h"
+#include "GuSweepMTD.h"
+#include "GuPCMShapeConvex.h"
+#include "GuDistanceSegmentSegment.h"
+#include "GuDistancePointSegment.h"
+#include "GuInternal.h"
+#include "GuConvexEdgeFlags.h"
+
+using namespace physx;
+using namespace Gu;
+
+static PX_FORCE_INLINE void getScaledTriangle(const PxTriangleMeshGeometry& triGeom, const Cm::Matrix34& vertex2worldSkew, bool flipsNormal, PxTriangle& triangle, PxTriangleID triangleIndex)
+{
+ TriangleMesh* tm = static_cast<TriangleMesh*>(triGeom.triangleMesh);
+ tm->computeWorldTriangle(triangle, triangleIndex, vertex2worldSkew, flipsNormal);
+}
+
+#define BATCH_TRIANGLE_NUMBER 32u
+
+struct MTDTriangle : public PxTriangle
+{
+public:
+ PxU8 extraTriData;//active edge flag data
+};
+
+struct MeshMTDGenerationCallback : MeshHitCallback<PxRaycastHit>
+{
+public:
+
+ Ps::Array<PxU32>& container;
+
+ MeshMTDGenerationCallback(Ps::Array<PxU32>& tempContainer)
+ : MeshHitCallback<PxRaycastHit>(CallbackMode::eMULTIPLE), container(tempContainer)
+ {
+ }
+
+ virtual PxAgain processHit(
+ const PxRaycastHit& hit, const PxVec3&, const PxVec3&, const PxVec3&, PxReal&, const PxU32*)
+ {
+ container.pushBack(hit.faceIndex);
+
+ return true;
+ }
+
+ void operator=(const MeshMTDGenerationCallback&) {}
+};
+
+static bool getMTDPerTriangle(const MeshPersistentContact* manifoldContacts, const PxU32 numContacts, const PxU32 triangleIndex, Ps::aos::Vec3V& normal, Ps::aos::Vec3V& closestA, Ps::aos::Vec3V& closestB, PxU32& faceIndex, Ps::aos::FloatV& deepestPen)
+{
+ using namespace Ps::aos;
+
+ FloatV deepest = V4GetW(manifoldContacts[0].mLocalNormalPen);
+ PxU32 index = 0;
+ for(PxU32 k=1; k<numContacts; ++k)
+ {
+ const FloatV pen = V4GetW(manifoldContacts[k].mLocalNormalPen);
+ if(FAllGrtr(deepest, pen))
+ {
+ deepest = pen;
+ index = k;
+ }
+ }
+
+ if(FAllGrtr(deepestPen, deepest))
+ {
+ PX_ASSERT(triangleIndex == manifoldContacts[index].mFaceIndex);
+ faceIndex = triangleIndex;
+ deepestPen = deepest;
+ normal = Vec3V_From_Vec4V(manifoldContacts[index].mLocalNormalPen);
+ closestA = manifoldContacts[index].mLocalPointB;
+ closestB = manifoldContacts[index].mLocalPointA;
+ return true;
+ }
+
+ return false;
+}
+static void midPhaseQuery(const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose, const Box& bound, Ps::Array<PxU32>& tempContainer)
+{
+ TriangleMesh* meshData = static_cast<TriangleMesh*>(meshGeom.triangleMesh);
+
+ Box vertexSpaceBox;
+ computeVertexSpaceOBB(vertexSpaceBox, bound, pose, meshGeom.scale);
+
+ MeshMTDGenerationCallback callback(tempContainer);
+ Midphase::intersectOBB(meshData, vertexSpaceBox, callback, true);
+}
+
+// PT: TODO: refactor with EntityReportContainerCallback
+struct MidPhaseQueryLocalReport : EntityReport<PxU32>
+{
+ MidPhaseQueryLocalReport(Ps::Array<PxU32>& _container) : container(_container)
+ {
+
+ }
+ virtual bool onEvent(PxU32 nb, PxU32* indices)
+ {
+ for(PxU32 i=0; i<nb; i++)
+ container.pushBack(indices[i]);
+ return true;
+ }
+
+ Ps::Array<PxU32>& container;
+
+private:
+ MidPhaseQueryLocalReport operator=(MidPhaseQueryLocalReport& report);
+} ;
+
+static void midPhaseQuery(const HeightFieldUtil& hfUtil, const PxTransform& pose, const PxBounds3& bounds, Ps::Array<PxU32>& tempContainer, PxU32 flags)
+{
+ MidPhaseQueryLocalReport localReport(tempContainer);
+ hfUtil.overlapAABBTriangles(pose, bounds, flags, &localReport);
+}
+
+static bool calculateMTD( const CapsuleV& capsuleV, const Ps::aos::FloatVArg inflatedRadiusV, const bool isDoubleSide, const MTDTriangle* triangles, const PxU32 nbTriangles, const PxU32 startIndex, MeshPersistentContact* manifoldContacts,
+ PxU32& numContacts, Ps::aos::Vec3V& normal, Ps::aos::Vec3V& closestA, Ps::aos::Vec3V& closestB, PxU32& faceIndex, Ps::aos::FloatV& mtd)
+{
+ using namespace Ps::aos;
+ const FloatV zero = FZero();
+ bool hadContacts = false;
+ FloatV deepestPen = mtd;
+
+ for(PxU32 j=0; j<nbTriangles; ++j)
+ {
+ numContacts = 0;
+
+ const MTDTriangle& curTri = triangles[j];
+ TriangleV triangleV;
+ triangleV.verts[0] = V3LoadU(curTri.verts[0]);
+ triangleV.verts[1] = V3LoadU(curTri.verts[1]);
+ triangleV.verts[2] = V3LoadU(curTri.verts[2]);
+ const PxU8 triFlag = curTri.extraTriData;
+
+ const Vec3V triangleNormal = triangleV.normal();
+ const Vec3V v = V3Sub(capsuleV.getCenter(), triangleV.verts[0]);
+ const FloatV dotV = V3Dot(triangleNormal, v);
+
+ // Backface culling
+ const bool culled = !isDoubleSide && (FAllGrtr(zero, dotV));
+ if(culled)
+ continue;
+
+ PCMCapsuleVsMeshContactGeneration::processTriangle(triangleV, j+startIndex, capsuleV, inflatedRadiusV, triFlag, manifoldContacts, numContacts);
+
+ if(numContacts ==0)
+ continue;
+
+ hadContacts = true;
+
+ getMTDPerTriangle(manifoldContacts, numContacts, j + startIndex, normal, closestA, closestB, faceIndex, deepestPen);
+ }
+
+ mtd = deepestPen;
+ return hadContacts;
+}
+
+bool physx::Gu::computeCapsule_TriangleMeshMTD( const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose, CapsuleV& capsuleV, PxReal inflatedRadius,
+ bool isDoubleSided, PxSweepHit& hit)
+{
+ using namespace Ps::aos;
+
+ const Vec3V zeroV = V3Zero();
+
+ TriangleMesh* triMesh = static_cast<TriangleMesh*>(triMeshGeom.triangleMesh);
+ const PxU8* extraTrigData = triMesh->getExtraTrigData();
+ const bool flipsNormal = triMeshGeom.scale.hasNegativeDeterminant();
+
+ MeshPersistentContact manifoldContacts[64];
+ PxU32 numContacts = 0;
+ //inflated the capsule by 15% in case of some disagreement between sweep and mtd calculation. If sweep said initial overlap, but mtd has a positive separation,
+ //we are still be able to return a valid normal but we should zero the distance.
+ const FloatV inflatedRadiusV = FLoad(inflatedRadius*1.15f);
+
+ bool foundInitial = false;
+ const PxU32 iterations = 4;
+
+ const Cm::Matrix34 vertexToWorldSkew = pose * triMeshGeom.scale;
+
+ Ps::Array<PxU32> tempContainer;
+ tempContainer.reserve(128);
+
+ Vec3V closestA = zeroV, closestB = zeroV, normal = zeroV;
+ PxU32 triangleIndex = 0xfffffff;
+
+ Vec3V translation = zeroV;
+ FloatV mtd;
+ FloatV distV;
+ for(PxU32 i=0; i<iterations; ++i)
+ {
+ tempContainer.forceSize_Unsafe(0);
+ Capsule inflatedCapsule;
+ V3StoreU(capsuleV.p0, inflatedCapsule.p0);
+ V3StoreU(capsuleV.p1, inflatedCapsule.p1);
+ inflatedCapsule.radius = inflatedRadius;
+
+ Box capsuleBox;
+ computeBoxAroundCapsule(inflatedCapsule, capsuleBox);
+ midPhaseQuery(triMeshGeom, pose, capsuleBox, tempContainer);
+
+ // Get results
+ const PxU32 nbTriangles = tempContainer.size();
+ if(!nbTriangles)
+ break;
+
+ const PxU32* indices = tempContainer.begin();
+
+ bool hadContacts = false;
+
+ const PxU32 nbBatches = (nbTriangles + BATCH_TRIANGLE_NUMBER - 1)/BATCH_TRIANGLE_NUMBER;
+ mtd = FMax();
+ MTDTriangle triangles[BATCH_TRIANGLE_NUMBER];
+ for(PxU32 a = 0; a < nbBatches; ++a)
+ {
+ const PxU32 startIndex = a * BATCH_TRIANGLE_NUMBER;
+ const PxU32 nbTrigs = PxMin(nbTriangles - startIndex, BATCH_TRIANGLE_NUMBER);
+ for(PxU32 k=0; k<nbTrigs; k++)
+ {
+ //triangle world space
+ const PxU32 triangleIndex1 = indices[startIndex+k];
+ ::getScaledTriangle(triMeshGeom, vertexToWorldSkew, flipsNormal, triangles[k], triangleIndex1);
+ triangles[k].extraTriData = getConvexEdgeFlags(extraTrigData, triangleIndex1);
+ }
+
+ //ML: mtd has back face culling, so if the capsule's center is below the triangle, we won't generate any contacts
+ hadContacts = calculateMTD(capsuleV, inflatedRadiusV, isDoubleSided, triangles, nbTrigs, startIndex, manifoldContacts, numContacts, normal, closestA, closestB, triangleIndex, mtd) || hadContacts;
+ }
+
+ if(!hadContacts)
+ break;
+
+ triangleIndex = indices[triangleIndex];
+
+ foundInitial = true;
+
+ //move the capsule to depenetrate it
+
+ distV = FSub(mtd, capsuleV.radius);
+ if(FAllGrtrOrEq(FZero(), distV))
+ {
+ Vec3V center = capsuleV.getCenter();
+ const Vec3V t = V3Scale(normal, distV);
+ translation = V3Sub(translation, t);
+ center = V3Sub(center, t);
+ capsuleV.setCenter(center);
+ }
+ else
+ {
+ if(i == 0)
+ {
+ //First iteration so keep this normal
+ hit.distance = 0.f;
+ V3StoreU(closestA, hit.position);
+ V3StoreU(normal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ return true;
+ }
+ break;
+ }
+ }
+
+ normal = V3Normalize(translation);
+ distV = FNeg(V3Length(translation));
+
+ if(foundInitial)
+ {
+ FStore(distV, &hit.distance);
+ V3StoreU(closestA, hit.position);
+ V3StoreU(normal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ }
+ return foundInitial;
+}
+
+
+bool physx::Gu::computeCapsule_HeightFieldMTD(const PxHeightFieldGeometry& heightFieldGeom, const PxTransform& pose, CapsuleV& capsuleV, PxReal inflatedRadius, bool isDoubleSided, const PxU32 flags, PxSweepHit& hit)
+{
+ using namespace Ps::aos;
+
+ const Vec3V zeroV = V3Zero();
+
+ MeshPersistentContact manifoldContacts[64];
+ PxU32 numContacts = 0;
+ //inflated the capsule by 1% in case of some disagreement between sweep and mtd calculation.If sweep said initial overlap, but mtd has a positive separation,
+ //we are still be able to return a valid normal but we should zero the distance.
+ const FloatV inflatedRadiusV = FLoad(inflatedRadius*1.01f);
+
+ bool foundInitial = false;
+ const PxU32 iterations = 4;
+
+ Ps::Array<PxU32> tempContainer;
+ tempContainer.reserve(128);
+
+ const HeightFieldUtil hfUtil(heightFieldGeom);
+
+ Vec3V closestA = zeroV, closestB = zeroV, normal = zeroV;
+ PxU32 triangleIndex = 0xfffffff;
+
+ Vec3V translation = zeroV;
+ FloatV mtd;
+ FloatV distV;
+ for(PxU32 i=0; i<iterations; ++i)
+ {
+ tempContainer.empty();
+ Capsule inflatedCapsule;
+ V3StoreU(capsuleV.p0, inflatedCapsule.p0);
+ V3StoreU(capsuleV.p1, inflatedCapsule.p1);
+ inflatedCapsule.radius = inflatedRadius;
+
+ Box capsuleBox;
+ computeBoxAroundCapsule(inflatedCapsule, capsuleBox);
+ const PxTransform capsuleBoxTransform = capsuleBox.getTransform();
+ const PxBounds3 bounds = PxBounds3::poseExtent(capsuleBoxTransform, capsuleBox.extents);
+ midPhaseQuery(hfUtil, pose, bounds, tempContainer, flags);
+
+ // Get results
+ const PxU32 nbTriangles = tempContainer.size();
+ if(!nbTriangles)
+ break;
+
+ bool hadContacts = false;
+
+ const PxU32 nbBatches = (nbTriangles + BATCH_TRIANGLE_NUMBER - 1)/BATCH_TRIANGLE_NUMBER;
+ mtd = FMax();
+ MTDTriangle triangles[BATCH_TRIANGLE_NUMBER];
+ for(PxU32 a = 0; a < nbBatches; ++a)
+ {
+ const PxU32 startIndex = a * BATCH_TRIANGLE_NUMBER;
+ const PxU32 nbTrigs = PxMin(nbTriangles - startIndex, BATCH_TRIANGLE_NUMBER);
+ for(PxU32 k=0; k<nbTrigs; k++)
+ {
+ //triangle vertex space
+ const PxU32 triangleIndex1 = tempContainer[startIndex+k];
+ hfUtil.getTriangle(pose, triangles[k], NULL, NULL, triangleIndex1, true);
+ triangles[k].extraTriData = ETD_CONVEX_EDGE_ALL;
+ }
+
+ //ML: mtd has back face culling, so if the capsule's center is below the triangle, we won't generate any contacts
+ hadContacts = calculateMTD(capsuleV, inflatedRadiusV, isDoubleSided, triangles, nbTrigs, startIndex, manifoldContacts, numContacts, normal, closestA, closestB, triangleIndex, mtd) || hadContacts;
+ }
+
+ if(!hadContacts)
+ break;
+
+ triangleIndex = tempContainer[triangleIndex];
+
+ foundInitial = true;
+
+ distV = FSub(mtd, capsuleV.radius);
+ if(FAllGrtrOrEq(FZero(), distV))
+ {
+ //move the capsule to depenetrate it
+ Vec3V center = capsuleV.getCenter();
+ const Vec3V t = V3Scale(normal, distV);
+ translation = V3Sub(translation, t);
+ center = V3Sub(center, t);
+ capsuleV.setCenter(center);
+ }
+ else
+ {
+ if(i == 0)
+ {
+ //First iteration so keep this normal
+ hit.distance = 0.f;
+ V3StoreU(closestA, hit.position);
+ V3StoreU(normal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ return true;
+ }
+ break;
+ }
+ }
+
+ normal = V3Normalize(translation);
+ distV = FNeg(V3Length(translation));
+ if(foundInitial)
+ {
+ FStore(distV, &hit.distance);
+ V3StoreU(closestA, hit.position);
+ V3StoreU(normal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ }
+ return foundInitial;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static bool calculateMTD( const PolygonalData& polyData, SupportLocal* polyMap, Ps::aos::PsTransformV& convexTransform, const Ps::aos::PsMatTransformV& meshToConvex, bool isDoubleSided, const Ps::aos::FloatVArg inflation, const MTDTriangle* triangles, const PxU32 nbTriangles, const PxU32 startIndex,
+ MeshPersistentContact* manifoldContacts, PxU32& numContacts, Ps::aos::Vec3V& normal, Ps::aos::Vec3V& closestA, Ps::aos::Vec3V& closestB, PxU32& faceIndex, Ps::aos::FloatV& mtd)
+{
+ using namespace Ps::aos;
+
+ bool hadContacts = false;
+ FloatV deepestPen = mtd;
+
+ for(PxU32 j=0; j<nbTriangles; ++j)
+ {
+ numContacts = 0;
+ const MTDTriangle& curTri = triangles[j];
+ const PxU8 triFlag = curTri.extraTriData;
+
+ PCMConvexVsMeshContactGeneration::processTriangle(polyData, polyMap, curTri.verts, j+startIndex, triFlag, inflation, isDoubleSided, convexTransform, meshToConvex, manifoldContacts, numContacts);
+
+ if(numContacts ==0)
+ continue;
+
+ hadContacts = true;
+ getMTDPerTriangle(manifoldContacts, numContacts, j+startIndex, normal, closestA, closestB, faceIndex, deepestPen);
+ }
+
+ mtd = deepestPen;
+
+ return hadContacts;
+}
+
+bool physx::Gu::computeBox_TriangleMeshMTD(const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose, const Box& _box, const PxTransform& boxTransform, PxReal inflation, bool isDoubleSided, PxSweepHit& hit)
+{
+ using namespace Ps::aos;
+
+ TriangleMesh* triMesh = static_cast<TriangleMesh*>(triMeshGeom.triangleMesh);
+ const PxU8* extraTrigData = triMesh->getExtraTrigData();
+
+ const Vec3V zeroV = V3Zero();
+
+ MeshPersistentContact manifoldContacts[64];
+ PxU32 numContacts = 0;
+
+ bool foundInitial = false;
+ const PxU32 iterations = 4;
+
+ Ps::Array<PxU32> tempContainer;
+ tempContainer.reserve(128);
+
+ Vec3V closestA = zeroV, closestB = zeroV, normal = zeroV;
+ Vec3V worldNormal = zeroV, worldContactA = zeroV;//, worldContactB = zeroV;
+ PxU32 triangleIndex = 0xfffffff;
+
+ Vec3V translation = zeroV;
+
+ Box box = _box;
+
+ const QuatV q0 = QuatVLoadU(&boxTransform.q.x);
+ const Vec3V p0 = V3LoadU(&boxTransform.p.x);
+
+ const Vec3V boxExtents = V3LoadU(box.extents);
+ const FloatV minMargin = CalculatePCMBoxMargin(boxExtents);
+ const FloatV inflationV = FAdd(FLoad(inflation), minMargin);
+ PxReal boundInflation;
+ FStore(inflationV, &boundInflation);
+
+ box.extents += PxVec3(boundInflation);
+ const BoxV boxV(zeroV, boxExtents);
+
+ Vec3V boxCenter = V3LoadU(box.center);
+
+ //create the polyData based on the original data
+ PolygonalData polyData;
+ const PCMPolygonalBox polyBox(_box.extents);
+ polyBox.getPolygonalData(&polyData);
+
+ const Mat33V identity = M33Identity();
+
+ const Cm::Matrix34 meshToWorldSkew = pose * triMeshGeom.scale;
+
+ PsTransformV boxTransformV(p0, q0);//box
+
+ FloatV mtd;
+ FloatV distV;
+ for(PxU32 i=0; i<iterations; ++i)
+ {
+ tempContainer.forceSize_Unsafe(0);
+
+ midPhaseQuery(triMeshGeom, pose, box, tempContainer);
+
+ // Get results
+ const PxU32 nbTriangles = tempContainer.size();
+ if(!nbTriangles)
+ break;
+
+ boxTransformV.p = boxCenter;
+ SupportLocalImpl<BoxV> boxMap(boxV, boxTransformV, identity, identity, true);
+
+ boxMap.setShapeSpaceCenterofMass(zeroV);
+ // Move to AABB space
+ Cm::Matrix34 WorldToBox;
+ computeWorldToBoxMatrix(WorldToBox, box);
+ const Cm::Matrix34 meshToBox = WorldToBox*meshToWorldSkew;
+
+ const Ps::aos::Mat33V rot(V3LoadU(meshToBox.m.column0), V3LoadU(meshToBox.m.column1), V3LoadU(meshToBox.m.column2));
+ const Ps::aos::PsMatTransformV meshToConvex(V3LoadU(meshToBox.p), rot);
+
+ bool hadContacts = false;
+
+ const PxU32 nbBatches = (nbTriangles + BATCH_TRIANGLE_NUMBER - 1)/BATCH_TRIANGLE_NUMBER;
+ mtd = FMax();
+ MTDTriangle triangles[BATCH_TRIANGLE_NUMBER];
+ for(PxU32 a = 0; a < nbBatches; ++a)
+ {
+ const PxU32 startIndex = a * BATCH_TRIANGLE_NUMBER;
+ const PxU32 nbTrigs = PxMin(nbTriangles - startIndex, BATCH_TRIANGLE_NUMBER);
+ for(PxU32 k=0; k<nbTrigs; k++)
+ {
+ //triangle vertex space
+ const PxU32 triangleIndex1 = tempContainer[startIndex+k];
+ triMesh->getLocalTriangle(triangles[k], triangleIndex1, triMeshGeom.scale.hasNegativeDeterminant());
+ triangles[k].extraTriData = getConvexEdgeFlags(extraTrigData, triangleIndex1);
+ }
+
+ //ML: mtd has back face culling, so if the capsule's center is below the triangle, we won't generate any contacts
+ hadContacts = calculateMTD(polyData, &boxMap, boxTransformV, meshToConvex, isDoubleSided, inflationV, triangles, nbTrigs, startIndex, manifoldContacts, numContacts, normal, closestA, closestB, triangleIndex, mtd) || hadContacts;
+ }
+
+ if(!hadContacts)
+ break;
+
+ triangleIndex = tempContainer[triangleIndex];
+
+ foundInitial = true;
+
+ distV = mtd;
+ worldNormal = boxTransformV.rotate(normal);
+ worldContactA = boxTransformV.transform(closestA);
+ if(FAllGrtrOrEq(FZero(), distV))
+ {
+ const Vec3V t = V3Scale(worldNormal, mtd);
+ translation = V3Sub(translation, t);
+ boxCenter = V3Sub(boxCenter, t);
+ V3StoreU(boxCenter, box.center);
+ }
+ else
+ {
+ if(i == 0)
+ {
+ //First iteration so keep this normal
+ hit.distance = 0.f;
+ V3StoreU(worldContactA, hit.position);
+ V3StoreU(worldNormal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ return true;
+ }
+ break;
+ }
+ }
+
+ worldNormal = V3Normalize(translation);
+ distV = FNeg(V3Length(translation));
+ if(foundInitial)
+ {
+ //transform closestA to world space
+ FStore(distV, &hit.distance);
+ V3StoreU(worldContactA, hit.position);
+ V3StoreU(worldNormal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ }
+ return foundInitial;
+}
+
+bool physx::Gu::computeBox_HeightFieldMTD( const PxHeightFieldGeometry& heightFieldGeom, const PxTransform& pose, const Box& _box, const PxTransform& boxTransform, PxReal inflation,
+ bool isDoubleSided, const PxU32 flags, PxSweepHit& hit)
+{
+ using namespace Ps::aos;
+
+ const Vec3V zeroV = V3Zero();
+ MeshPersistentContact manifoldContacts[64];
+ PxU32 numContacts = 0;
+ bool foundInitial = false;
+ const PxU32 iterations = 4;
+
+ Ps::Array<PxU32> tempContainer;
+ tempContainer.reserve(128);
+ const HeightFieldUtil hfUtil(heightFieldGeom);
+
+ Vec3V closestA = zeroV, closestB = zeroV, normal = zeroV;
+ Vec3V worldNormal = zeroV, worldContactA = zeroV;//, worldContactB = zeroV;
+ PxU32 triangleIndex = 0xfffffff;
+
+ Vec3V translation = zeroV;
+
+ Box box = _box;
+
+ const QuatV q0 = QuatVLoadU(&boxTransform.q.x);
+ const Vec3V p0 = V3LoadU(&boxTransform.p.x);
+
+ const Vec3V boxExtents = V3LoadU(box.extents);
+ const FloatV minMargin = CalculatePCMBoxMargin(boxExtents);
+ const FloatV inflationV = FAdd(FLoad(inflation), minMargin);
+ //const FloatV inflationV = FLoad(inflation);
+
+ PxReal boundInflation;
+ FStore(inflationV, &boundInflation);
+ box.extents += PxVec3(boundInflation);
+
+ const BoxV boxV(zeroV, boxExtents);
+
+ Vec3V boxCenter = V3LoadU(box.center);
+
+ //create the polyData based on the original box
+ PolygonalData polyData;
+ const PCMPolygonalBox polyBox(_box.extents);
+ polyBox.getPolygonalData(&polyData);
+
+ const Mat33V identity = M33Identity();
+
+ const Cm::Matrix34 meshToWorldSkew(pose);
+
+ PsTransformV boxTransformV(p0, q0);//box
+
+ FloatV mtd;
+ FloatV distV;
+ for(PxU32 i=0; i<iterations; ++i)
+ {
+ tempContainer.forceSize_Unsafe(0);
+
+ const PxBounds3 bounds = PxBounds3::poseExtent(box.getTransform(), box.extents);
+ midPhaseQuery(hfUtil, pose, bounds, tempContainer, flags);
+
+ // Get results
+ const PxU32 nbTriangles = tempContainer.size();
+ if(!nbTriangles)
+ break;
+
+ boxTransformV.p = boxCenter;
+ SupportLocalImpl<BoxV> boxMap(boxV, boxTransformV, identity, identity, true);
+ boxMap.setShapeSpaceCenterofMass(zeroV);
+ // Move to AABB space
+ Cm::Matrix34 WorldToBox;
+ computeWorldToBoxMatrix(WorldToBox, box);
+ const Cm::Matrix34 meshToBox = WorldToBox*meshToWorldSkew;
+
+ const Ps::aos::Mat33V rot(V3LoadU(meshToBox.m.column0), V3LoadU(meshToBox.m.column1), V3LoadU(meshToBox.m.column2));
+ const Ps::aos::PsMatTransformV meshToConvex(V3LoadU(meshToBox.p), rot);
+
+ bool hadContacts = false;
+
+ const PxU32 nbBatches = (nbTriangles + BATCH_TRIANGLE_NUMBER-1)/BATCH_TRIANGLE_NUMBER;
+ mtd = FMax();
+ MTDTriangle triangles[BATCH_TRIANGLE_NUMBER];
+ for(PxU32 a = 0; a < nbBatches; ++a)
+ {
+ const PxU32 startIndex = a * BATCH_TRIANGLE_NUMBER;
+ const PxU32 nbTrigs = PxMin(nbTriangles - startIndex, BATCH_TRIANGLE_NUMBER);
+ for(PxU32 k=0; k<nbTrigs; k++)
+ {
+ //triangle vertex space
+ const PxU32 triangleIndex1 = tempContainer[startIndex+k];
+ hfUtil.getTriangle(pose, triangles[k], NULL, NULL, triangleIndex1, false, false);
+ triangles[k].extraTriData = ETD_CONVEX_EDGE_ALL;
+ }
+
+ //ML: mtd has back face culling, so if the box's center is below the triangle, we won't generate any contacts
+ hadContacts = calculateMTD(polyData, &boxMap, boxTransformV, meshToConvex, isDoubleSided, inflationV, triangles, nbTrigs, startIndex, manifoldContacts, numContacts, normal, closestA, closestB, triangleIndex, mtd) || hadContacts;
+ }
+
+ if(!hadContacts)
+ break;
+
+ triangleIndex = tempContainer[triangleIndex];
+
+ foundInitial = true;
+
+ distV = mtd;
+ worldNormal = boxTransformV.rotate(normal);
+ worldContactA = boxTransformV.transform(closestA);
+ if(FAllGrtrOrEq(FZero(), distV))
+ {
+ //worldContactB = boxTransformV.transform(closestB);
+ const Vec3V t = V3Scale(worldNormal, mtd);
+ translation = V3Sub(translation, t);
+ boxCenter = V3Sub(boxCenter, t);
+ V3StoreU(boxCenter, box.center);
+ }
+ else
+ {
+ if(i == 0)
+ {
+ //First iteration so keep this normal
+ hit.distance = 0.f;
+ V3StoreU(worldContactA, hit.position);
+ V3StoreU(worldNormal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ return true;
+ }
+ break;
+ }
+ }
+
+ worldNormal = V3Normalize(translation);
+ distV = FNeg(V3Length(translation));
+
+ if(foundInitial)
+ {
+ FStore(distV, &hit.distance);
+ V3StoreU(worldContactA, hit.position);
+ V3StoreU(worldNormal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ }
+ return foundInitial;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool physx::Gu::computeConvex_TriangleMeshMTD( const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose, PxReal inflation,
+ bool isDoubleSided, PxSweepHit& hit)
+{
+ using namespace Ps::aos;
+
+ const Vec3V zeroV = V3Zero();
+
+ TriangleMesh* triMesh = static_cast<TriangleMesh*>(triMeshGeom.triangleMesh);
+ ConvexMesh* cm = static_cast<ConvexMesh*>(convexGeom.convexMesh);
+ const PxU8* extraTrigData = triMesh->getExtraTrigData();
+
+ MeshPersistentContact manifoldContacts[64];
+ PxU32 numContacts = 0;
+
+ bool foundInitial = false;
+ const PxU32 iterations = 2;
+
+ ConvexHullData* hullData = &cm->getHull();
+
+ const bool idtScaleConvex = convexGeom.scale.isIdentity();
+
+ Cm::FastVertex2ShapeScaling convexScaling;
+ if(!idtScaleConvex)
+ convexScaling.init(convexGeom.scale);
+
+ const PxVec3 _shapeSpaceCenterOfMass = convexScaling * hullData->mCenterOfMass;
+ const Vec3V shapeSpaceCenterOfMass = V3LoadU(_shapeSpaceCenterOfMass);
+
+ const QuatV q0 = QuatVLoadU(&convexPose.q.x);
+ const Vec3V p0 = V3LoadU(&convexPose.p.x);
+ PsTransformV convexTransformV(p0, q0);
+
+ const Vec3V vScale = V3LoadU_SafeReadW(convexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
+ const QuatV vQuat = QuatVLoadU(&convexGeom.scale.rotation.x);
+ ConvexHullV convexHull(hullData, V3Zero(), vScale, vQuat, idtScaleConvex);
+ PX_ALIGN(16, PxU8 convexBuff[sizeof(SupportLocalImpl<ConvexHullV>)]);
+
+ const FloatV convexMargin = CalculatePCMConvexMargin(hullData, vScale);
+ const FloatV inflationV = FAdd(FLoad(inflation), convexMargin);
+ PxReal boundInflation;
+ FStore(inflationV, &boundInflation);
+
+ Ps::Array<PxU32> tempContainer;
+ tempContainer.reserve(128);
+
+ Vec3V closestA = zeroV, closestB = zeroV, normal = zeroV;
+ PxU32 triangleIndex = 0xfffffff;
+
+ Vec3V translation = zeroV;
+
+ const Cm::Matrix34 meshToWorldSkew = pose * triMeshGeom.scale;
+
+ PolygonalData polyData;
+ getPCMConvexData(convexHull, idtScaleConvex, polyData);
+
+ FloatV mtd;
+ FloatV distV;
+ Vec3V center = p0;
+ PxTransform tempConvexPose = convexPose;
+ Vec3V worldNormal = zeroV, worldContactA = zeroV;//, worldContactB = zeroV;
+
+ for(PxU32 i=0; i<iterations; ++i)
+ {
+ tempContainer.forceSize_Unsafe(0);
+
+ //ML:: construct convex hull data
+ V3StoreU(center, tempConvexPose.p);
+ convexTransformV.p = center;
+ SupportLocal* convexMap = (idtScaleConvex ? static_cast<SupportLocal*>(PX_PLACEMENT_NEW(convexBuff, SupportLocalImpl<ConvexHullNoScaleV>)(static_cast<ConvexHullNoScaleV&>(convexHull), convexTransformV, convexHull.vertex2Shape, convexHull.shape2Vertex, idtScaleConvex)) :
+ static_cast<SupportLocal*>(PX_PLACEMENT_NEW(convexBuff, SupportLocalImpl<ConvexHullV>)(convexHull, convexTransformV, convexHull.vertex2Shape, convexHull.shape2Vertex, idtScaleConvex)));
+
+ convexMap->setShapeSpaceCenterofMass(shapeSpaceCenterOfMass);
+
+ Box hullOBB;
+ computeOBBAroundConvex(hullOBB, convexGeom, cm, tempConvexPose);
+
+ hullOBB.extents += PxVec3(boundInflation);
+
+ midPhaseQuery(triMeshGeom, pose, hullOBB, tempContainer);
+
+ // Get results
+ const PxU32 nbTriangles = tempContainer.size();
+ if(!nbTriangles)
+ break;
+
+ // Move to AABB space
+ const Cm::Matrix34 worldToConvex(tempConvexPose.getInverse());
+ const Cm::Matrix34 meshToConvex = worldToConvex*meshToWorldSkew;
+
+ const Ps::aos::Mat33V rot(V3LoadU(meshToConvex.m.column0), V3LoadU(meshToConvex.m.column1), V3LoadU(meshToConvex.m.column2));
+ const Ps::aos::PsMatTransformV meshToConvexV(V3LoadU(meshToConvex.p), rot);
+
+ bool hadContacts = false;
+
+ const PxU32 nbBatches = (nbTriangles + BATCH_TRIANGLE_NUMBER-1)/BATCH_TRIANGLE_NUMBER;
+ mtd = FMax();
+ MTDTriangle triangles[BATCH_TRIANGLE_NUMBER];
+ for(PxU32 a = 0; a < nbBatches; ++a)
+ {
+ const PxU32 startIndex = a * BATCH_TRIANGLE_NUMBER;
+ const PxU32 nbTrigs = PxMin(nbTriangles - startIndex, BATCH_TRIANGLE_NUMBER);
+ for(PxU32 k=0; k<nbTrigs; k++)
+ {
+ //triangle vertex space
+ const PxU32 triangleIndex1 = tempContainer[startIndex+k];
+ triMesh->getLocalTriangle(triangles[k], triangleIndex1, triMeshGeom.scale.hasNegativeDeterminant());
+ triangles[k].extraTriData = getConvexEdgeFlags(extraTrigData, triangleIndex1);
+ }
+
+ //ML: mtd has back face culling, so if the capsule's center is below the triangle, we won't generate any contacts
+ hadContacts = calculateMTD(polyData, convexMap, convexTransformV, meshToConvexV, isDoubleSided, inflationV, triangles, nbTrigs, startIndex, manifoldContacts, numContacts, normal, closestA, closestB, triangleIndex, mtd) || hadContacts;
+ }
+
+ if(!hadContacts)
+ break;
+
+ triangleIndex = tempContainer[triangleIndex];
+
+ foundInitial = true;
+
+ distV = mtd;
+ worldNormal = convexTransformV.rotate(normal);
+ worldContactA = convexTransformV.transform(closestA);
+ if(FAllGrtrOrEq(FZero(), distV))
+ {
+ const Vec3V t = V3Scale(worldNormal, mtd);
+ translation = V3Sub(translation, t);
+ center = V3Sub(center, t);
+ }
+ else
+ {
+ if(i == 0)
+ {
+ //First iteration so keep this normal
+ hit.distance = 0.f;
+ V3StoreU(worldContactA, hit.position);
+ V3StoreU(worldNormal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ return true;
+ }
+ break;
+ }
+ }
+
+ worldNormal = V3Normalize(translation);
+ distV = FNeg(V3Length(translation));
+ if(foundInitial)
+ {
+ //transform closestA to world space
+ FStore(distV, &hit.distance);
+ V3StoreU(worldContactA, hit.position);
+ V3StoreU(worldNormal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ }
+ return foundInitial;
+}
+
+bool physx::Gu::computeConvex_HeightFieldMTD( const PxHeightFieldGeometry& heightFieldGeom, const PxTransform& pose, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose, PxReal inflation,
+ bool isDoubleSided, const PxU32 flags, PxSweepHit& hit)
+{
+ using namespace Ps::aos;
+
+ const HeightFieldUtil hfUtil(heightFieldGeom);
+
+ const Vec3V zeroV = V3Zero();
+ MeshPersistentContact manifoldContacts[64];
+ PxU32 numContacts = 0;
+
+ bool foundInitial = false;
+ const PxU32 iterations = 2;
+
+ ConvexMesh* cm = static_cast<ConvexMesh*>(convexGeom.convexMesh);
+
+ ConvexHullData* hullData = &cm->getHull();
+
+ const bool idtScaleConvex = convexGeom.scale.isIdentity();
+
+ Cm::FastVertex2ShapeScaling convexScaling;
+ if(!idtScaleConvex)
+ convexScaling.init(convexGeom.scale);
+
+ const PxVec3 _shapeSpaceCenterOfMass = convexScaling * hullData->mCenterOfMass;
+ const Vec3V shapeSpaceCenterOfMass = V3LoadU(_shapeSpaceCenterOfMass);
+
+ const QuatV q0 = QuatVLoadU(&convexPose.q.x);
+ const Vec3V p0 = V3LoadU(&convexPose.p.x);
+ PsTransformV convexTransformV(p0, q0);
+
+ const Vec3V vScale = V3LoadU_SafeReadW(convexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
+ const QuatV vQuat = QuatVLoadU(&convexGeom.scale.rotation.x);
+ ConvexHullV convexHull(hullData, zeroV, vScale, vQuat, idtScaleConvex);
+ PX_ALIGN(16, PxU8 convexBuff[sizeof(SupportLocalImpl<ConvexHullV>)]);
+
+ const FloatV convexMargin = CalculatePCMConvexMargin(hullData, vScale);
+ const FloatV inflationV = FAdd(FLoad(inflation), convexMargin);
+ PxReal boundInflation;
+ FStore(inflationV, &boundInflation);
+
+ Ps::Array<PxU32> tempContainer;
+ tempContainer.reserve(128);
+
+ Vec3V closestA = zeroV, closestB = zeroV, normal = zeroV;
+ Vec3V worldNormal = zeroV, worldContactA = zeroV;//, worldContactB = zeroV;
+ PxU32 triangleIndex = 0xfffffff;
+
+ Vec3V translation = zeroV;
+
+ PolygonalData polyData;
+ getPCMConvexData(convexHull, idtScaleConvex, polyData);
+
+ FloatV mtd;
+ FloatV distV;
+ Vec3V center = p0;
+ PxTransform tempConvexPose = convexPose;
+ const Cm::Matrix34 meshToWorldSkew(pose);
+
+ for(PxU32 i=0; i<iterations; ++i)
+ {
+ tempContainer.forceSize_Unsafe(0);
+
+ //ML:: construct convex hull data
+
+ V3StoreU(center, tempConvexPose.p);
+ convexTransformV.p = center;
+
+ SupportLocal* convexMap = (idtScaleConvex ? static_cast<SupportLocal*>(PX_PLACEMENT_NEW(convexBuff, SupportLocalImpl<ConvexHullNoScaleV>)(static_cast<ConvexHullNoScaleV&>(convexHull), convexTransformV, convexHull.vertex2Shape, convexHull.shape2Vertex, idtScaleConvex)) :
+ static_cast<SupportLocal*>(PX_PLACEMENT_NEW(convexBuff, SupportLocalImpl<ConvexHullV>)(convexHull, convexTransformV, convexHull.vertex2Shape, convexHull.shape2Vertex, idtScaleConvex)));
+
+ convexMap->setShapeSpaceCenterofMass(shapeSpaceCenterOfMass);
+
+ Box hullOBB;
+ computeOBBAroundConvex(hullOBB, convexGeom, cm, tempConvexPose);
+ hullOBB.extents += PxVec3(boundInflation);
+
+ const PxBounds3 bounds = PxBounds3::basisExtent(hullOBB.center, hullOBB.rot, hullOBB.extents);
+
+ midPhaseQuery(hfUtil, pose, bounds, tempContainer, flags);
+
+ // Get results
+ const PxU32 nbTriangles = tempContainer.size();
+
+ if(!nbTriangles)
+ break;
+
+ // Move to AABB space
+ const Cm::Matrix34 worldToConvex(tempConvexPose.getInverse());
+ const Cm::Matrix34 meshToConvex = worldToConvex*meshToWorldSkew;
+
+ const Ps::aos::Mat33V rot(V3LoadU(meshToConvex.m.column0), V3LoadU(meshToConvex.m.column1), V3LoadU(meshToConvex.m.column2));
+ const Ps::aos::PsMatTransformV meshToConvexV(V3LoadU(meshToConvex.p), rot);
+
+ bool hadContacts = false;
+
+ const PxU32 nbBatches = (nbTriangles + BATCH_TRIANGLE_NUMBER-1)/BATCH_TRIANGLE_NUMBER;
+ mtd = FMax();
+ MTDTriangle triangles[BATCH_TRIANGLE_NUMBER];
+ for(PxU32 a = 0; a < nbBatches; ++a)
+ {
+ const PxU32 startIndex = a * BATCH_TRIANGLE_NUMBER;
+ const PxU32 nbTrigs = PxMin(nbTriangles - startIndex, BATCH_TRIANGLE_NUMBER);
+ for(PxU32 k=0; k<nbTrigs; k++)
+ {
+ //triangle vertex space
+ const PxU32 triangleIndex1 = tempContainer[startIndex+k];
+ hfUtil.getTriangle(pose, triangles[k], NULL, NULL, triangleIndex1, false, false);
+ triangles[k].extraTriData = ETD_CONVEX_EDGE_ALL;
+ }
+
+ //ML: mtd has back face culling, so if the capsule's center is below the triangle, we won't generate any contacts
+ hadContacts = calculateMTD(polyData, convexMap, convexTransformV, meshToConvexV, isDoubleSided, inflationV, triangles, nbTrigs, startIndex, manifoldContacts, numContacts, normal, closestA, closestB, triangleIndex, mtd) || hadContacts;
+ }
+
+ if(!hadContacts)
+ break;
+
+ triangleIndex = tempContainer[triangleIndex];
+
+ foundInitial = true;
+
+ distV = mtd;
+ worldNormal = convexTransformV.rotate(normal);
+ worldContactA = convexTransformV.transform(closestA);
+
+ if(FAllGrtrOrEq(FZero(), distV))
+ {
+ const Vec3V t = V3Scale(worldNormal, mtd);
+ translation = V3Sub(translation, t);
+ center = V3Sub(center, t);
+ }
+ else
+ {
+ if(i == 0)
+ {
+ //First iteration so keep this normal
+ hit.distance = 0.f;
+ V3StoreU(worldContactA, hit.position);
+ V3StoreU(worldNormal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ return true;
+ }
+ break;
+ }
+ }
+
+ worldNormal = V3Normalize(translation);
+ distV = FNeg(V3Length(translation));
+ if(foundInitial)
+ {
+ //transform closestA to world space
+ FStore(distV, &hit.distance);
+ V3StoreU(worldContactA, hit.position);
+ V3StoreU(worldNormal, hit.normal);
+ hit.faceIndex = triangleIndex;
+ }
+ return foundInitial;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool physx::Gu::computeSphere_SphereMTD(const Sphere& sphere0, const Sphere& sphere1, PxSweepHit& hit)
+{
+ const PxVec3 delta = sphere1.center - sphere0.center;
+ const PxReal d2 = delta.magnitudeSquared();
+ const PxReal radiusSum = sphere0.radius + sphere1.radius;
+
+ const PxReal d = PxSqrt(d2);
+ hit.normal = delta / d;
+ hit.distance = d - radiusSum ;
+ hit.position = sphere0.center + hit.normal * sphere0.radius;
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool physx::Gu::computeSphere_CapsuleMTD( const Sphere& sphere, const Capsule& capsule, PxSweepHit& hit)
+{
+ const PxReal radiusSum = sphere.radius + capsule.radius;
+
+ PxReal u;
+ distancePointSegmentSquared(capsule, sphere.center, &u);
+
+ const PxVec3 normal = capsule.getPointAt(u) - sphere.center;
+
+ const PxReal lenSq = normal.magnitudeSquared();
+ const PxF32 d = PxSqrt(lenSq);
+ hit.normal = normal / d;
+ hit.distance = d - radiusSum;
+ hit.position = sphere.center + hit.normal * sphere.radius;
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool physx::Gu::computeCapsule_CapsuleMTD(const Capsule& capsule0, const Capsule& capsule1, PxSweepHit& hit)
+{
+ using namespace Ps::aos;
+
+ PxReal s,t;
+ distanceSegmentSegmentSquared(capsule0, capsule1, &s, &t);
+
+ const PxReal radiusSum = capsule0.radius + capsule1.radius;
+
+ const PxVec3 pointAtCapsule0 = capsule0.getPointAt(s);
+ const PxVec3 pointAtCapsule1 = capsule1.getPointAt(t);
+
+ const PxVec3 normal = pointAtCapsule0 - pointAtCapsule1;
+ const PxReal lenSq = normal.magnitudeSquared();
+ const PxF32 len = PxSqrt(lenSq);
+ hit.normal = normal / len;
+ hit.distance = len - radiusSum;
+ hit.position = pointAtCapsule1 + hit.normal * capsule1.radius;
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool physx::Gu::computePlane_CapsuleMTD(const PxPlane& plane, const Capsule& capsule, PxSweepHit& hit)
+{
+ const PxReal d0 = plane.distance(capsule.p0);
+ const PxReal d1 = plane.distance(capsule.p1);
+ PxReal dmin;
+ PxVec3 point;
+ if(d0 < d1)
+ {
+ dmin = d0;
+ point = capsule.p0;
+ }
+ else
+ {
+ dmin = d1;
+ point = capsule.p1;
+ }
+
+ hit.normal = plane.n;
+ hit.distance = dmin - capsule.radius;
+ hit.position = point - hit.normal * dmin;
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool physx::Gu::computePlane_BoxMTD(const PxPlane& plane, const Box& box, PxSweepHit& hit)
+{
+ PxVec3 pts[8];
+ box.computeBoxPoints(pts);
+
+ PxReal dmin = plane.distance(pts[0]);
+ PxU32 index = 0;
+ for(PxU32 i=1;i<8;i++)
+ {
+ const PxReal d = plane.distance(pts[i]);
+ if(dmin > d)
+ {
+ index = i;
+ dmin = d;
+ }
+ }
+ hit.normal = plane.n;
+ hit.distance = dmin;
+ hit.position = pts[index] - plane.n*dmin;
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool physx::Gu::computePlane_ConvexMTD(const PxPlane& plane, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose, PxSweepHit& hit)
+{
+ const ConvexMesh* convexMesh = static_cast<const ConvexMesh*>(convexGeom.convexMesh);
+ const Cm::FastVertex2ShapeScaling convexScaling(convexGeom.scale);
+ PxU32 nbVerts = convexMesh->getNbVerts();
+ const PxVec3* PX_RESTRICT verts = convexMesh->getVerts();
+
+ PxVec3 worldPointMin = convexPose.transform(convexScaling * verts[0]);
+ PxReal dmin = plane.distance(worldPointMin);
+ for(PxU32 i=1;i<nbVerts;i++)
+ {
+ const PxVec3 worldPoint = convexPose.transform(convexScaling * verts[i]);
+ const PxReal d = plane.distance(worldPoint);
+ if(dmin > d)
+ {
+ dmin = d;
+ worldPointMin = worldPoint;
+ }
+ }
+
+ hit.normal = plane.n;
+ hit.distance = dmin;
+ hit.position = worldPointMin - plane.n * dmin;
+ return true;
+}