aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/contact/GuContactConvexMesh.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/contact/GuContactConvexMesh.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/contact/GuContactConvexMesh.cpp')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/contact/GuContactConvexMesh.cpp1449
1 files changed, 1449 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/contact/GuContactConvexMesh.cpp b/PhysX_3.4/Source/GeomUtils/src/contact/GuContactConvexMesh.cpp
new file mode 100644
index 00000000..58142f46
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/contact/GuContactConvexMesh.cpp
@@ -0,0 +1,1449 @@
+// 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 "GuConvexUtilsInternal.h"
+#include "GuInternal.h"
+#include "GuContactPolygonPolygon.h"
+#include "GuConvexEdgeFlags.h"
+#include "GuSeparatingAxes.h"
+#include "GuContactMethodImpl.h"
+#include "GuContactBuffer.h"
+#include "GuMidphaseInterface.h"
+#include "GuConvexHelper.h"
+#include "GuTriangleCache.h"
+#include "GuHeightFieldUtil.h"
+#include "GuEntityReport.h"
+#include "GuGeometryUnion.h"
+#include "GuIntersectionTriangleBox.h"
+#include "CmUtils.h"
+#include "PsAllocator.h"
+#include "GuBox.h"
+#include "PsFPU.h"
+
+using namespace physx;
+using namespace Gu;
+using namespace shdfnd::aos;
+using namespace intrinsics;
+
+#define LOCAL_TOUCHED_TRIG_SIZE 192
+
+//#define USE_TRIANGLE_NORMAL
+#define TEST_INTERNAL_OBJECTS
+
+static PX_FORCE_INLINE void projectTriangle(const PxVec3& localSpaceDirection, const PxVec3* PX_RESTRICT triangle, PxReal& min1, PxReal& max1)
+{
+ const PxReal dp0 = triangle[0].dot(localSpaceDirection);
+ const PxReal dp1 = triangle[1].dot(localSpaceDirection);
+ min1 = selectMin(dp0, dp1);
+ max1 = selectMax(dp0, dp1);
+
+ const PxReal dp2 = triangle[2].dot(localSpaceDirection);
+ min1 = selectMin(min1, dp2);
+ max1 = selectMax(max1, dp2);
+}
+
+#ifdef TEST_INTERNAL_OBJECTS
+
+static PX_FORCE_INLINE void boxSupport(const float extents[3], const PxVec3& sv, float p[3])
+{
+ const PxU32* iextents = reinterpret_cast<const PxU32*>(extents);
+ const PxU32* isv = reinterpret_cast<const PxU32*>(&sv);
+ PxU32* ip = reinterpret_cast<PxU32*>(p);
+
+ ip[0] = iextents[0]|(isv[0]&PX_SIGN_BITMASK);
+ ip[1] = iextents[1]|(isv[1]&PX_SIGN_BITMASK);
+ ip[2] = iextents[2]|(isv[2]&PX_SIGN_BITMASK);
+}
+
+#if PX_DEBUG
+static const PxReal testInternalObjectsEpsilon = 1.0e-3f;
+#endif
+
+static PX_FORCE_INLINE bool testInternalObjects(const PxVec3& localAxis0,
+ const PolygonalData& polyData0,
+ const PxVec3* PX_RESTRICT triangleInHullSpace,
+ float dmin)
+{
+ PxReal min1, max1;
+ projectTriangle(localAxis0, triangleInHullSpace, min1, max1);
+
+ const float dp = polyData0.mCenter.dot(localAxis0);
+
+ float p0[3];
+ boxSupport(polyData0.mInternal.mExtents, localAxis0, p0);
+ const float Radius0 = p0[0]*localAxis0.x + p0[1]*localAxis0.y + p0[2]*localAxis0.z;
+ const float bestRadius = selectMax(Radius0, polyData0.mInternal.mRadius);
+ const PxReal min0 = dp - bestRadius;
+ const PxReal max0 = dp + bestRadius;
+
+ const PxReal d0 = max0 - min1;
+ const PxReal d1 = max1 - min0;
+
+ const float depth = selectMin(d0, d1);
+ if(depth>dmin)
+ return false;
+ return true;
+}
+#endif
+
+static PX_FORCE_INLINE bool testNormal( const PxVec3& sepAxis, PxReal min0, PxReal max0,
+ const PxVec3* PX_RESTRICT triangle,
+ PxReal& depth, PxReal contactDistance)
+{
+ PxReal min1, max1;
+ projectTriangle(sepAxis, triangle, min1, max1);
+
+ if(max0+contactDistance<min1 || max1+contactDistance<min0)
+ return false;
+
+ const PxReal d0 = max0 - min1;
+ const PxReal d1 = max1 - min0;
+ depth = selectMin(d0, d1);
+ return true;
+}
+
+static PX_FORCE_INLINE bool testSepAxis(const PxVec3& sepAxis,
+ const PolygonalData& polyData0,
+ const PxVec3* PX_RESTRICT triangle,
+ const Cm::Matrix34& m0to1,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ PxReal& depth, PxReal contactDistance)
+{
+ PxReal min0, max0;
+ (polyData0.mProjectHull)(polyData0, sepAxis, m0to1, convexScaling, min0, max0);
+
+ PxReal min1, max1;
+ projectTriangle(sepAxis, triangle, min1, max1);
+
+ if(max0+contactDistance < min1 || max1+contactDistance < min0)
+ return false;
+
+ const PxReal d0 = max0 - min1;
+ const PxReal d1 = max1 - min0;
+ depth = selectMin(d0, d1);
+ return true;
+}
+
+static bool testFacesSepAxesBackface( const PolygonalData& polyData0,
+ const Cm::Matrix34& /*world0*/, const Cm::Matrix34& /*world1*/,
+ const Cm::Matrix34& m0to1, const PxVec3& witness,
+ const PxVec3* PX_RESTRICT triangle,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ PxU32& numHullIndices,
+ PxU32* hullIndices_, PxReal& dmin, PxVec3& sep, PxU32& id, PxReal contactDistance,
+ bool idtConvexScale
+ )
+{
+ id = PX_INVALID_U32;
+
+ const PxU32 numHullPolys = polyData0.mNbPolygons;
+ const HullPolygonData* PX_RESTRICT polygons = polyData0.mPolygons;
+ const PxVec3* PX_RESTRICT vertices = polyData0.mVerts;
+ const PxVec3& trans = m0to1.p;
+ {
+ PxU32* hullIndices = hullIndices_;
+
+ // PT: when the center of one object is inside the other object (deep penetrations) this discards everything!
+ // PT: when this happens, the backup procedure is used to come up with good results anyway.
+ // PT: it's worth having a special codepath here for identity scales, to skip all the normalizes/division. Lot faster without.
+
+ if(idtConvexScale)
+ {
+ for(PxU32 i=0; i<numHullPolys; i++)
+ {
+ const HullPolygonData& P = polygons[i];
+ const PxPlane& PL = P.mPlane;
+
+#ifdef USE_TRIANGLE_NORMAL
+ if(PL.normal.dot(witness) > 0.0f)
+#else
+ // ### this is dubious since the triangle center is likely to be very close to the hull, if not inside. Why not use the triangle normal?
+ if(PL.distance(witness) < 0.0f)
+#endif
+ continue; //backface culled
+
+ *hullIndices++ = i;
+
+ const PxVec3 sepAxis = m0to1.rotate(PL.n);
+ const PxReal dp = sepAxis.dot(trans);
+
+ PxReal d;
+ if(!testNormal(sepAxis, P.getMin(vertices) + dp, P.getMax() + dp, triangle,
+ d, contactDistance))
+ return false;
+
+ if(d < dmin)
+ {
+ dmin = d;
+ sep = sepAxis;
+ id = i;
+ }
+ }
+ }
+ else
+ {
+#ifndef USE_TRIANGLE_NORMAL
+ //transform delta from hull0 shape into vertex space:
+ const PxVec3 vertSpaceWitness = convexScaling % witness;
+#endif
+ for(PxU32 i=0; i<numHullPolys; i++)
+ {
+ const HullPolygonData& P = polygons[i];
+ const PxPlane& PL = P.mPlane;
+
+#ifdef USE_TRIANGLE_NORMAL
+ if(PL.normal.dot(witness) > 0.0f)
+#else
+ // ### this is dubious since the triangle center is likely to be very close to the hull, if not inside. Why not use the triangle normal?
+ if(PL.distance(vertSpaceWitness) < 0.0f)
+#endif
+ continue; //backface culled
+
+ //normals transform by inverse transpose: (and transpose(skew) == skew as its symmetric)
+ PxVec3 shapeSpaceNormal = convexScaling % PL.n;
+ //renormalize: (Arr!)
+ const PxReal magnitude = shapeSpaceNormal.normalize();
+
+ *hullIndices++ = i;
+ const PxVec3 sepAxis = m0to1.rotate(shapeSpaceNormal);
+ PxReal d;
+ const PxReal dp = sepAxis.dot(trans);
+
+ const float oneOverM = 1.0f / magnitude;
+ if(!testNormal(sepAxis, P.getMin(vertices) * oneOverM + dp, P.getMax() * oneOverM + dp, triangle,
+ d, contactDistance))
+ return false;
+
+ if(d < dmin)
+ {
+ dmin = d;
+ sep = sepAxis;
+ id = i;
+ }
+ }
+ }
+ numHullIndices = PxU32(hullIndices - hullIndices_);
+ }
+
+ // Backup
+ if(id == PX_INVALID_U32)
+ {
+ if(idtConvexScale)
+ {
+ for(PxU32 i=0; i<numHullPolys; i++)
+ {
+ const HullPolygonData& P = polygons[i];
+ const PxPlane& PL = P.mPlane;
+
+ const PxVec3 sepAxis = m0to1.rotate(PL.n);
+ const PxReal dp = sepAxis.dot(trans);
+
+ PxReal d;
+ if(!testNormal(sepAxis, P.getMin(vertices) + dp, P.getMax() + dp, triangle,
+ d, contactDistance))
+ return false;
+
+ if(d < dmin)
+ {
+ dmin = d;
+ sep = sepAxis;
+ id = i;
+ }
+ hullIndices_[i] = i;
+ }
+ }
+ else
+ {
+ for(PxU32 i=0; i<numHullPolys; i++)
+ {
+ const HullPolygonData& P = polygons[i];
+ const PxPlane& PL = P.mPlane;
+
+ PxVec3 shapeSpaceNormal = convexScaling % PL.n;
+ //renormalize: (Arr!)
+ const PxReal magnitude = shapeSpaceNormal.normalize();
+
+ const PxVec3 sepAxis = m0to1.rotate(shapeSpaceNormal);
+
+ PxReal d;
+ const PxReal dp = sepAxis.dot(trans);
+
+ const float oneOverM = 1.0f / magnitude;
+ if(!testNormal(sepAxis, P.getMin(vertices) * oneOverM + dp, P.getMax() * oneOverM + dp, triangle,
+ d, contactDistance))
+ return false;
+
+ if(d < dmin)
+ {
+ dmin = d;
+ sep = sepAxis;
+ id = i;
+ }
+ hullIndices_[i] = i;
+ }
+ }
+ numHullIndices = numHullPolys;
+ }
+ return true;
+}
+
+static PX_FORCE_INLINE bool edgeCulling(const PxPlane& plane, const PxVec3& p0, const PxVec3& p1, PxReal contactDistance)
+{
+ return plane.distance(p0)<=contactDistance || plane.distance(p1)<=contactDistance;
+}
+
+static bool performEETests(
+ const PolygonalData& polyData0,
+ const PxU8 triFlags,
+ const Cm::Matrix34& m0to1, const Cm::Matrix34& m1to0,
+ const PxVec3* PX_RESTRICT triangle,
+ PxU32 numHullIndices, const PxU32* PX_RESTRICT hullIndices,
+ const PxPlane& localTriPlane,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ PxVec3& vec, PxReal& dmin, PxReal contactDistance, PxReal toleranceLength,
+ PxU32 id0, PxU32 /*triangleIndex*/)
+{
+ PX_UNUSED(toleranceLength); // Only used in Debug
+
+ // Cull candidate triangle edges vs to hull plane
+ PxU32 nbTriangleAxes = 0;
+ PxVec3 triangleAxes[3];
+ {
+ const HullPolygonData& P = polyData0.mPolygons[id0];
+ const PxPlane& vertSpacePlane = P.mPlane;
+
+ const PxVec3 newN = m1to0.rotate(vertSpacePlane.n);
+ PxPlane hullWitness(convexScaling * newN, vertSpacePlane.d - m1to0.p.dot(newN)); //technically not a fully xformed plane, just use property of x|My == Mx|y for symmetric M.
+
+ if((triFlags & ETD_CONVEX_EDGE_01) && edgeCulling(hullWitness, triangle[0], triangle[1], contactDistance))
+ triangleAxes[nbTriangleAxes++] = (triangle[0] - triangle[1]);
+
+ if((triFlags & ETD_CONVEX_EDGE_12) && edgeCulling(hullWitness, triangle[1], triangle[2], contactDistance))
+ triangleAxes[nbTriangleAxes++] = (triangle[1] - triangle[2]);
+
+ if((triFlags & ETD_CONVEX_EDGE_20) && edgeCulling(hullWitness, triangle[2], triangle[0], contactDistance))
+ triangleAxes[nbTriangleAxes++] = (triangle[2] - triangle[0]);
+ }
+
+ //PxcPlane vertexSpacePlane = localTriPlane.getTransformed(m1to0);
+ //vertexSpacePlane.normal = convexScaling * vertexSpacePlane.normal; //technically not a fully xformed plane, just use property of x|My == Mx|y for symmetric M.
+ const PxVec3 newN = m1to0.rotate(localTriPlane.n);
+ PxPlane vertexSpacePlane(convexScaling * newN, localTriPlane.d - m1to0.p.dot(newN));
+
+ const PxVec3* PX_RESTRICT hullVerts = polyData0.mVerts;
+
+ SeparatingAxes SA;
+ SA.reset();
+
+ const PxU8* PX_RESTRICT vrefBase0 = polyData0.mPolygonVertexRefs;
+ const HullPolygonData* PX_RESTRICT polygons = polyData0.mPolygons;
+ while(numHullIndices--)
+ {
+ const HullPolygonData& P = polygons[*hullIndices++];
+ const PxU8* PX_RESTRICT data = vrefBase0 + P.mVRef8;
+
+ PxU32 numEdges = nbTriangleAxes;
+ const PxVec3* edges = triangleAxes;
+
+ // TODO: cheap edge culling as in convex/convex!
+ while(numEdges--)
+ {
+ const PxVec3& currentPolyEdge = *edges++;
+
+ // Loop through polygon vertices == polygon edges;
+ PxU32 numVerts = P.mNbVerts;
+ for(PxU32 j = 0; j < numVerts; j++)
+ {
+ PxU32 j1 = j+1;
+ if(j1>=numVerts) j1 = 0;
+
+ const PxU32 VRef0 = data[j];
+ const PxU32 VRef1 = data[j1];
+
+ if(edgeCulling(vertexSpacePlane, hullVerts[VRef0], hullVerts[VRef1], contactDistance))
+ {
+ const PxVec3 currentHullEdge = m0to1.rotate(convexScaling * (hullVerts[VRef0] - hullVerts[VRef1])); //matrix mult is distributive!
+
+ PxVec3 sepAxis = currentHullEdge.cross(currentPolyEdge);
+ if(!Ps::isAlmostZero(sepAxis))
+ SA.addAxis(sepAxis.getNormalized());
+ }
+ }
+ }
+ }
+
+ dmin = PX_MAX_REAL;
+ PxU32 numAxes = SA.getNumAxes();
+ const PxVec3* PX_RESTRICT axes = SA.getAxes();
+
+#ifdef TEST_INTERNAL_OBJECTS
+ PxVec3 triangleInHullSpace[3];
+ if(numAxes)
+ {
+ triangleInHullSpace[0] = m1to0.transform(triangle[0]);
+ triangleInHullSpace[1] = m1to0.transform(triangle[1]);
+ triangleInHullSpace[2] = m1to0.transform(triangle[2]);
+ }
+#endif
+
+ while(numAxes--)
+ {
+ const PxVec3& currentAxis = *axes++;
+
+#ifdef TEST_INTERNAL_OBJECTS
+ const PxVec3 localAxis0 = m1to0.rotate(currentAxis);
+ if(!testInternalObjects(localAxis0, polyData0, triangleInHullSpace, dmin))
+ {
+ #if PX_DEBUG
+ PxReal dtest;
+ if(testSepAxis(currentAxis, polyData0, triangle, m0to1, convexScaling, dtest, contactDistance))
+ {
+ PX_ASSERT(dtest + testInternalObjectsEpsilon*toleranceLength >= dmin);
+ }
+ #endif
+ continue;
+ }
+#endif
+
+ PxReal d;
+ if(!testSepAxis(currentAxis, polyData0, triangle,
+ m0to1, convexScaling, d, contactDistance))
+ {
+ return false;
+ }
+
+ if(d < dmin)
+ {
+ dmin = d;
+ vec = currentAxis;
+ }
+ }
+ return true;
+}
+
+static bool triangleConvexTest( const PolygonalData& polyData0,
+ const PxU8 triFlags,
+ PxU32 index, const PxVec3* PX_RESTRICT localPoints,
+ const PxPlane& localPlane,
+ const PxVec3& groupCenterHull,
+ const Cm::Matrix34& world0, const Cm::Matrix34& world1, const Cm::Matrix34& m0to1, const Cm::Matrix34& m1to0,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ PxReal contactDistance, PxReal toleranceLength,
+ PxVec3& groupAxis, PxReal& groupMinDepth, bool& faceContact,
+ bool idtConvexScale
+ )
+{
+ PxU32 id0 = PX_INVALID_U32;
+ PxReal dmin0 = PX_MAX_REAL;
+ PxVec3 vec0;
+
+ PxU32 numHullIndices = 0;
+ PxU32* PX_RESTRICT const hullIndices = reinterpret_cast<PxU32*>(PxAlloca(polyData0.mNbPolygons*sizeof(PxU32)));
+
+ // PT: we test the hull normals first because they don't need any hull projection. If we can early exit thanks
+ // to those, we completely avoid all hull projections.
+ bool status = testFacesSepAxesBackface(polyData0, world0, world1, m0to1, groupCenterHull, localPoints,
+ convexScaling, numHullIndices, hullIndices, dmin0, vec0, id0, contactDistance, idtConvexScale);
+ if(!status)
+ return false;
+
+ groupAxis = PxVec3(0);
+ groupMinDepth = PX_MAX_REAL;
+
+ const PxReal eps = 0.0001f; // DE7748
+
+ //Test in mesh-space
+ PxVec3 sepAxis;
+ PxReal depth;
+
+ {
+ // Test triangle normal
+ PxReal d;
+ if(!testSepAxis(localPlane.n, polyData0, localPoints,
+ m0to1, convexScaling, d, contactDistance))
+ return false;
+
+ if(d<dmin0+eps)
+// if(d<dmin0)
+ {
+ depth = d;
+ sepAxis = localPlane.n;
+ faceContact = true;
+ }
+ else
+ {
+ depth = dmin0;
+ sepAxis = vec0;
+ faceContact = false;
+ }
+ }
+
+ if(depth < groupMinDepth)
+ {
+ groupMinDepth = depth;
+ groupAxis = world1.rotate(sepAxis);
+ }
+
+ if(!performEETests(polyData0, triFlags, m0to1, m1to0,
+ localPoints,
+ numHullIndices, hullIndices, localPlane,
+ convexScaling, sepAxis, depth, contactDistance, toleranceLength,
+ id0, index))
+ return false;
+
+ if(depth < groupMinDepth)
+ {
+ groupMinDepth = depth;
+ groupAxis = world1.rotate(sepAxis);
+ faceContact = false;
+ }
+
+ return true;
+}
+
+namespace
+{
+ struct ConvexMeshContactGeneration
+ {
+ Ps::InlineArray<PxU32,LOCAL_CONTACTS_SIZE>& mDelayedContacts;
+ Gu::CacheMap<Gu::CachedEdge, 128> mEdgeCache;
+ Gu::CacheMap<Gu::CachedVertex, 128> mVertCache;
+
+ const Cm::Matrix34 m0to1;
+ const Cm::Matrix34 m1to0;
+
+ PxVec3 mHullCenterMesh;
+ PxVec3 mHullCenterWorld;
+
+ const PolygonalData& mPolyData0;
+ const Cm::Matrix34& mWorld0;
+ const Cm::Matrix34& mWorld1;
+
+ const Cm::FastVertex2ShapeScaling& mConvexScaling;
+
+ PxReal mContactDistance;
+ PxReal mToleranceLength;
+ bool mIdtMeshScale, mIdtConvexScale;
+ PxReal mCCDEpsilon;
+ const PxTransform& mTransform0;
+ const PxTransform& mTransform1;
+ ContactBuffer& mContactBuffer;
+ bool mAnyHits;
+
+ ConvexMeshContactGeneration(
+ Ps::InlineArray<PxU32,LOCAL_CONTACTS_SIZE>& delayedContacts,
+ const PxTransform& t0to1, const PxTransform& t1to0,
+ const PolygonalData& polyData0, const Cm::Matrix34& world0, const Cm::Matrix34& world1,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ PxReal contactDistance,
+ PxReal toleranceLength,
+ bool idtConvexScale,
+ PxReal cCCDEpsilon,
+ const PxTransform& transform0, const PxTransform& transform1,
+ ContactBuffer& contactBuffer
+ );
+
+ void processTriangle(const PxVec3* verts, PxU32 triangleIndex, PxU8 triFlags, const PxU32* vertInds);
+ void generateLastContacts();
+
+ bool generateContacts(
+ const PxPlane& localPlane,
+ const PxVec3* PX_RESTRICT localPoints,
+ const PxVec3& triCenter, PxVec3& groupAxis,
+ PxReal groupMinDepth, PxU32 index) const;
+
+ private:
+ ConvexMeshContactGeneration& operator=(const ConvexMeshContactGeneration&);
+ };
+
+// 17 entries. 1088/17 = 64 triangles in the local array
+struct SavedContactData
+{
+ PxU32 mTriangleIndex;
+ PxVec3 mVerts[3];
+ PxU32 mInds[3];
+ PxVec3 mGroupAxis;
+ PxReal mGroupMinDepth;
+};
+}
+
+ConvexMeshContactGeneration::ConvexMeshContactGeneration(
+ Ps::InlineArray<PxU32,LOCAL_CONTACTS_SIZE>& delayedContacts,
+ const PxTransform& t0to1, const PxTransform& t1to0,
+ const PolygonalData& polyData0, const Cm::Matrix34& world0, const Cm::Matrix34& world1,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ PxReal contactDistance,
+ PxReal toleranceLength,
+ bool idtConvexScale,
+ PxReal cCCDEpsilon,
+ const PxTransform& transform0, const PxTransform& transform1,
+ ContactBuffer& contactBuffer
+) :
+ mDelayedContacts(delayedContacts),
+ m0to1 (t0to1),
+ m1to0 (t1to0),
+ mPolyData0 (polyData0),
+ mWorld0 (world0),
+ mWorld1 (world1),
+ mConvexScaling (convexScaling),
+ mContactDistance(contactDistance),
+ mToleranceLength(toleranceLength),
+ mIdtConvexScale (idtConvexScale),
+ mCCDEpsilon (cCCDEpsilon),
+ mTransform0 (transform0),
+ mTransform1 (transform1),
+ mContactBuffer (contactBuffer)
+{
+ delayedContacts.forceSize_Unsafe(0);
+ mAnyHits = false;
+
+ // Hull center in local space
+ const PxVec3& hullCenterLocal = mPolyData0.mCenter;
+ // Hull center in mesh space
+ mHullCenterMesh = m0to1.transform(hullCenterLocal);
+ // Hull center in world space
+ mHullCenterWorld = mWorld0.transform(hullCenterLocal);
+}
+
+struct ConvexMeshContactGenerationCallback : MeshHitCallback<PxRaycastHit>
+{
+ ConvexMeshContactGeneration mGeneration;
+ const Cm::FastVertex2ShapeScaling& mMeshScaling;
+ const PxU8* PX_RESTRICT mExtraTrigData;
+ bool mIdtMeshScale;
+ const TriangleMesh* mMeshData;
+ const BoxPadded& mBox;
+
+ ConvexMeshContactGenerationCallback(
+ Ps::InlineArray<PxU32,LOCAL_CONTACTS_SIZE>& delayedContacts,
+ const PxTransform& t0to1, const PxTransform& t1to0,
+ const PolygonalData& polyData0, const Cm::Matrix34& world0, const Cm::Matrix34& world1,
+ const TriangleMesh* meshData,
+ const PxU8* PX_RESTRICT extraTrigData,
+ const Cm::FastVertex2ShapeScaling& meshScaling,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ PxReal contactDistance,
+ PxReal toleranceLength,
+ bool idtMeshScale, bool idtConvexScale,
+ PxReal cCCDEpsilon,
+ const PxTransform& transform0, const PxTransform& transform1,
+ ContactBuffer& contactBuffer,
+ const BoxPadded& box
+ ) :
+ MeshHitCallback<PxRaycastHit> (CallbackMode::eMULTIPLE),
+ mGeneration (delayedContacts, t0to1, t1to0, polyData0, world0, world1, convexScaling, contactDistance, toleranceLength, idtConvexScale, cCCDEpsilon, transform0, transform1, contactBuffer),
+ mMeshScaling (meshScaling),
+ mExtraTrigData (extraTrigData),
+ mIdtMeshScale (idtMeshScale),
+ mMeshData (meshData),
+ mBox (box)
+ {
+ }
+
+ virtual PxAgain processHit( // all reported coords are in mesh local space including hit.position
+ const PxRaycastHit& hit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal&, const PxU32* vinds)
+ {
+ // PT: this one is safe because incoming vertices from midphase are always safe to V4Load (by design)
+ // PT: TODO: is this test really needed? Not done in midphase already?
+ if(!intersectTriangleBox(mBox, v0, v1, v2))
+ return true;
+
+ PxVec3 verts[3];
+ getScaledVertices(verts, v0, v1, v2, mIdtMeshScale, mMeshScaling);
+
+ const PxU32 triangleIndex = hit.faceIndex;
+
+ const PxU8 extraData = getConvexEdgeFlags(mExtraTrigData, triangleIndex);
+ mGeneration.processTriangle(verts, triangleIndex, extraData, vinds);
+ return true;
+ }
+
+protected:
+ ConvexMeshContactGenerationCallback &operator=(const ConvexMeshContactGenerationCallback &);
+};
+
+bool ConvexMeshContactGeneration::generateContacts(
+ const PxPlane& localPlane,
+ const PxVec3* PX_RESTRICT localPoints,
+ const PxVec3& triCenter, PxVec3& groupAxis,
+ PxReal groupMinDepth, PxU32 index) const
+{
+ const PxVec3 worldGroupCenter = mWorld1.transform(triCenter);
+ const PxVec3 deltaC = mHullCenterWorld - worldGroupCenter;
+ if(deltaC.dot(groupAxis) < 0.0f)
+ groupAxis = -groupAxis;
+
+ const PxU32 id = (mPolyData0.mSelectClosestEdgeCB)(mPolyData0, mConvexScaling, mWorld0.rotateTranspose(-groupAxis));
+
+ const HullPolygonData& HP = mPolyData0.mPolygons[id];
+ PX_ALIGN(16, PxPlane) shapeSpacePlane0;
+ if(mIdtConvexScale)
+ V4StoreA(V4LoadU(&HP.mPlane.n.x), &shapeSpacePlane0.n.x);
+ else
+ mConvexScaling.transformPlaneToShapeSpace(HP.mPlane.n, HP.mPlane.d, shapeSpacePlane0.n, shapeSpacePlane0.d);
+
+ const PxVec3 hullNormalWorld = mWorld0.rotate(shapeSpacePlane0.n);
+
+ const PxReal d0 = PxAbs(hullNormalWorld.dot(groupAxis));
+
+ const PxVec3 triNormalWorld = mWorld1.rotate(localPlane.n);
+ const PxReal d1 = PxAbs(triNormalWorld.dot(groupAxis));
+ const bool d0biggerd1 = d0 > d1;
+
+////////////////////NEW DIST HANDLING//////////////////////
+ //TODO: skip this if there is no dist involved!
+
+PxReal separation = - groupMinDepth; //convert to real distance.
+
+separation = fsel(separation, separation, 0.0f); //don't do anything when penetrating!
+
+//printf("\nseparation = %f", separation);
+
+PxReal contactGenPositionShift = separation + mCCDEpsilon; //if we're at a distance, shift so we're within penetration.
+
+PxVec3 contactGenPositionShiftVec = groupAxis * contactGenPositionShift; //shift one of the bodies this distance toward the other just for Pierre's contact generation. Then the bodies should be penetrating exactly by MIN_SEPARATION_FOR_PENALTY - ideal conditions for this contact generator.
+
+//note: for some reason this has to change sign!
+
+//this will make contact gen always generate contacts at about MSP. Shift them back to the true real distance, and then to a solver compliant distance given that
+//the solver converges to MSP penetration, while we want it to converge to 0 penetration.
+//to real distance:
+// PxReal polyPolySeparationShift = separation; //(+ or - depending on which way normal goes)
+
+//The system: We always shift convex 0 (arbitrary). If the contact is attached to convex 0 then we will need to shift the contact point, otherwise not.
+
+//TODO: make these overwrite orig location if its safe to do so.
+
+Cm::Matrix34 world0_(mWorld0);
+PxTransform transform0_(mTransform0);
+
+world0_.p -= contactGenPositionShiftVec;
+transform0_.p = world0_.p; //reset this too.
+
+PxTransform t0to1_ = mTransform1.transformInv(transform0_);
+PxTransform t1to0_ = transform0_.transformInv(mTransform1);
+Cm::Matrix34 m0to1_(t0to1_);
+Cm::Matrix34 m1to0_(t1to0_);
+
+ PxVec3* scaledVertices0;
+ PxU8* stackIndices0;
+ GET_SCALEX_CONVEX(scaledVertices0, stackIndices0, mIdtConvexScale, HP.mNbVerts, mConvexScaling, mPolyData0.mVerts, mPolyData0.getPolygonVertexRefs(HP))
+
+ const PxU8 indices[3] = {0, 1, 2};
+
+ const PxMat33 RotT0 = findRotationMatrixFromZ(shapeSpacePlane0.n);
+ const PxMat33 RotT1 = findRotationMatrixFromZ(localPlane.n);
+
+ if(d0biggerd1)
+ {
+ if(contactPolygonPolygonExt(
+ HP.mNbVerts, scaledVertices0, stackIndices0, world0_, shapeSpacePlane0,
+ RotT0,
+ 3, localPoints, indices, mWorld1, localPlane,
+ RotT1,
+ hullNormalWorld, m0to1_, m1to0_, PXC_CONTACT_NO_FACE_INDEX, index,
+ mContactBuffer,
+ true,
+ contactGenPositionShiftVec, contactGenPositionShift))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if(contactPolygonPolygonExt(
+ 3, localPoints, indices, mWorld1, localPlane,
+ RotT1,
+ HP.mNbVerts, scaledVertices0, stackIndices0, world0_, shapeSpacePlane0,
+ RotT0,
+ triNormalWorld, m1to0_, m0to1_, PXC_CONTACT_NO_FACE_INDEX, index,
+ mContactBuffer,
+ false,
+ contactGenPositionShiftVec, contactGenPositionShift))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+enum FeatureCode
+{
+ FC_VERTEX0,
+ FC_VERTEX1,
+ FC_VERTEX2,
+ FC_EDGE01,
+ FC_EDGE12,
+ FC_EDGE20,
+ FC_FACE,
+
+ FC_UNDEFINED
+};
+
+static FeatureCode computeFeatureCode(const PxVec3& point, const PxVec3* verts)
+{
+ const PxVec3& triangleOrigin = verts[0];
+ const PxVec3 triangleEdge0 = verts[1] - verts[0];
+ const PxVec3 triangleEdge1 = verts[2] - verts[0];
+
+ const PxVec3 kDiff = triangleOrigin - point;
+ const PxReal fA00 = triangleEdge0.magnitudeSquared();
+ const PxReal fA01 = triangleEdge0.dot(triangleEdge1);
+ const PxReal fA11 = triangleEdge1.magnitudeSquared();
+ const PxReal fB0 = kDiff.dot(triangleEdge0);
+ const PxReal fB1 = kDiff.dot(triangleEdge1);
+ const PxReal fDet = PxAbs(fA00*fA11 - fA01*fA01);
+ const PxReal u = fA01*fB1-fA11*fB0;
+ const PxReal v = fA01*fB0-fA00*fB1;
+
+ FeatureCode fc = FC_UNDEFINED;
+
+ if(u + v <= fDet)
+ {
+ if(u < 0.0f)
+ {
+ if(v < 0.0f) // region 4
+ {
+ if(fB0 < 0.0f)
+ {
+ if(-fB0 >= fA00)
+ fc = FC_VERTEX1;
+ else
+ fc = FC_EDGE01;
+ }
+ else
+ {
+ if(fB1 >= 0.0f)
+ fc = FC_VERTEX0;
+ else if(-fB1 >= fA11)
+ fc = FC_VERTEX2;
+ else
+ fc = FC_EDGE20;
+ }
+ }
+ else // region 3
+ {
+ if(fB1 >= 0.0f)
+ fc = FC_VERTEX0;
+ else if(-fB1 >= fA11)
+ fc = FC_VERTEX2;
+ else
+ fc = FC_EDGE20;
+ }
+ }
+ else if(v < 0.0f) // region 5
+ {
+ if(fB0 >= 0.0f)
+ fc = FC_VERTEX0;
+ else if(-fB0 >= fA00)
+ fc = FC_VERTEX1;
+ else
+ fc = FC_EDGE01;
+ }
+ else // region 0
+ {
+ // minimum at interior PxVec3
+ if(fDet==0.0f)
+ fc = FC_VERTEX0;
+ else
+ fc = FC_FACE;
+ }
+ }
+ else
+ {
+ PxReal fTmp0, fTmp1, fNumer, fDenom;
+
+ if(u < 0.0f) // region 2
+ {
+ fTmp0 = fA01 + fB0;
+ fTmp1 = fA11 + fB1;
+ if(fTmp1 > fTmp0)
+ {
+ fNumer = fTmp1 - fTmp0;
+ fDenom = fA00-2.0f*fA01+fA11;
+ if(fNumer >= fDenom)
+ fc = FC_VERTEX1;
+ else
+ fc = FC_EDGE12;
+ }
+ else
+ {
+ if(fTmp1 <= 0.0f)
+ fc = FC_VERTEX2;
+ else if(fB1 >= 0.0f)
+ fc = FC_VERTEX0;
+ else
+ fc = FC_EDGE20;
+ }
+ }
+ else if(v < 0.0f) // region 6
+ {
+ fTmp0 = fA01 + fB1;
+ fTmp1 = fA00 + fB0;
+ if(fTmp1 > fTmp0)
+ {
+ fNumer = fTmp1 - fTmp0;
+ fDenom = fA00-2.0f*fA01+fA11;
+ if(fNumer >= fDenom)
+ fc = FC_VERTEX2;
+ else
+ fc = FC_EDGE12;
+ }
+ else
+ {
+ if(fTmp1 <= 0.0f)
+ fc = FC_VERTEX1;
+ else if(fB0 >= 0.0f)
+ fc = FC_VERTEX0;
+ else
+ fc = FC_EDGE01;
+ }
+ }
+ else // region 1
+ {
+ fNumer = fA11 + fB1 - fA01 - fB0;
+ if(fNumer <= 0.0f)
+ {
+ fc = FC_VERTEX2;
+ }
+ else
+ {
+ fDenom = fA00-2.0f*fA01+fA11;
+ if(fNumer >= fDenom)
+ fc = FC_VERTEX1;
+ else
+ fc = FC_EDGE12;
+ }
+ }
+ }
+ return fc;
+}
+
+
+//static bool validateVertex(PxU32 vref, const PxU32 count, const ContactPoint* PX_RESTRICT contacts, const TriangleMesh& meshData)
+//{
+// PxU32 previous = 0xffffffff;
+// for(PxU32 i=0;i<count;i++)
+// {
+// if(contacts[i].internalFaceIndex1==previous)
+// continue;
+// previous = contacts[i].internalFaceIndex1;
+//
+// const TriangleIndices T(meshData, contacts[i].internalFaceIndex1);
+// if( T.mVRefs[0]==vref
+// || T.mVRefs[1]==vref
+// || T.mVRefs[2]==vref)
+// return false;
+// }
+// return true;
+//}
+
+
+//static PX_FORCE_INLINE bool testEdge(PxU32 vref0, PxU32 vref1, PxU32 tvref0, PxU32 tvref1)
+//{
+// if(tvref0>tvref1)
+// Ps::swap(tvref0, tvref1);
+//
+// if(tvref0==vref0 && tvref1==vref1)
+// return false;
+// return true;
+//}
+
+//static bool validateEdge(PxU32 vref0, PxU32 vref1, const PxU32 count, const ContactPoint* PX_RESTRICT contacts, const TriangleMesh& meshData)
+//{
+// if(vref0>vref1)
+// Ps::swap(vref0, vref1);
+//
+// PxU32 previous = 0xffffffff;
+// for(PxU32 i=0;i<count;i++)
+// {
+// if(contacts[i].internalFaceIndex1==previous)
+// continue;
+// previous = contacts[i].internalFaceIndex1;
+//
+// const TriangleIndices T(meshData, contacts[i].internalFaceIndex1);
+//
+///* if(T.mVRefs[0]==vref0 || T.mVRefs[0]==vref1)
+// return false;
+// if(T.mVRefs[1]==vref0 || T.mVRefs[1]==vref1)
+// return false;
+// if(T.mVRefs[2]==vref0 || T.mVRefs[2]==vref1)
+// return false;*/
+// // PT: wow, this was wrong??? ###FIX
+// if(!testEdge(vref0, vref1, T.mVRefs[0], T.mVRefs[1]))
+// return false;
+// if(!testEdge(vref0, vref1, T.mVRefs[1], T.mVRefs[2]))
+// return false;
+// if(!testEdge(vref0, vref1, T.mVRefs[2], T.mVRefs[0]))
+// return false;
+// }
+// return true;
+//}
+
+//static bool validateEdge(PxU32 vref0, PxU32 vref1, const PxU32* vertIndices, const PxU32 nbIndices)
+//{
+// if(vref0>vref1)
+// Ps::swap(vref0, vref1);
+//
+// for(PxU32 i=0;i<nbIndices;i+=3)
+// {
+// if(!testEdge(vref0, vref1, vertIndices[i+0], vertIndices[i+1]))
+// return false;
+// if(!testEdge(vref0, vref1, vertIndices[i+1], vertIndices[i+2]))
+// return false;
+// if(!testEdge(vref0, vref1, vertIndices[i+2], vertIndices[i+0]))
+// return false;
+// }
+// return true;
+//}
+
+//#endif
+
+void ConvexMeshContactGeneration::processTriangle(const PxVec3* verts, PxU32 triangleIndex, PxU8 triFlags, const PxU32* vertInds)
+{
+ const PxPlane localPlane(verts[0], verts[1], verts[2]);
+
+ // Backface culling
+ if(localPlane.distance(mHullCenterMesh)<0.0f)
+// if(localPlane.normal.dot(mHullCenterMesh - T.mVerts[0]) <= 0.0f)
+ return;
+
+ //////////////////////////////////////////////////////////////////////////
+
+ const PxVec3 triCenter = (verts[0] + verts[1] + verts[2])*(1.0f/3.0f);
+
+ // Group center in hull space
+#ifdef USE_TRIANGLE_NORMAL
+ const PxVec3 groupCenterHull = m1to0.rotate(localPlane.normal);
+#else
+ const PxVec3 groupCenterHull = m1to0.transform(triCenter);
+#endif
+ //////////////////////////////////////////////////////////////////////////
+
+ PxVec3 groupAxis;
+ PxReal groupMinDepth;
+ bool faceContact;
+ if(!triangleConvexTest( mPolyData0, triFlags,
+ triangleIndex, verts,
+ localPlane,
+ groupCenterHull,
+ mWorld0, mWorld1, m0to1, m1to0,
+ mConvexScaling,
+ mContactDistance, mToleranceLength,
+ groupAxis, groupMinDepth, faceContact,
+ mIdtConvexScale
+ ))
+ return;
+
+ if(faceContact)
+ {
+ // PT: generate face contacts immediately to save memory & avoid recomputing triangle data later
+ if(generateContacts(
+ localPlane,
+ verts,
+ triCenter, groupAxis,
+ groupMinDepth, triangleIndex))
+ {
+ mAnyHits = true;
+ mEdgeCache.addData(CachedEdge(vertInds[0], vertInds[1]));
+ mEdgeCache.addData(CachedEdge(vertInds[0], vertInds[2]));
+ mEdgeCache.addData(CachedEdge(vertInds[1], vertInds[2]));
+ mVertCache.addData(CachedVertex(vertInds[0]));
+ mVertCache.addData(CachedVertex(vertInds[1]));
+ mVertCache.addData(CachedVertex(vertInds[2]));
+ }
+ else
+ {
+ int stop=1;
+ (void)stop;
+ }
+ }
+ else
+ {
+ const PxU32 nb = sizeof(SavedContactData)/sizeof(PxU32);
+
+ // PT: no "pushBack" please (useless data copy + LHS)
+ PxU32 newSize = nb + mDelayedContacts.size();
+ mDelayedContacts.reserve(newSize);
+ SavedContactData* PX_RESTRICT cd = reinterpret_cast<SavedContactData*>(mDelayedContacts.end());
+ mDelayedContacts.forceSize_Unsafe(newSize);
+
+ cd->mTriangleIndex = triangleIndex;
+ cd->mVerts[0] = verts[0];
+ cd->mVerts[1] = verts[1];
+ cd->mVerts[2] = verts[2];
+ cd->mInds[0] = vertInds[0];
+ cd->mInds[1] = vertInds[1];
+ cd->mInds[2] = vertInds[2];
+ cd->mGroupAxis = groupAxis;
+ cd->mGroupMinDepth = groupMinDepth;
+ }
+}
+
+void ConvexMeshContactGeneration::generateLastContacts()
+{
+ // Process delayed contacts
+ PxU32 nbEntries = mDelayedContacts.size();
+ if(nbEntries)
+ {
+ nbEntries /= sizeof(SavedContactData)/sizeof(PxU32);
+
+ // PT: TODO: replicate this fix in sphere-vs-mesh ###FIX
+ //const PxU32 count = mContactBuffer.count;
+ //const ContactPoint* PX_RESTRICT contacts = mContactBuffer.contacts;
+
+ const SavedContactData* PX_RESTRICT cd = reinterpret_cast<const SavedContactData*>(mDelayedContacts.begin());
+ for(PxU32 i=0;i<nbEntries;i++)
+ {
+ const SavedContactData& currentContact = cd[i];
+
+ const PxU32 triangleIndex = currentContact.mTriangleIndex;
+
+ // PT: unfortunately we must recompute this triangle-data here.
+ // PT: TODO: find a way not to
+// const TriangleVertices T(*mMeshData, mMeshScaling, triangleIndex);
+// const TriangleIndices T(*mMeshData, triangleIndex);
+
+ const PxU32 ref0 = currentContact.mInds[0];
+ const PxU32 ref1 = currentContact.mInds[1];
+ const PxU32 ref2 = currentContact.mInds[2];
+
+ // PT: TODO: why bother with the feature code at all? Use edge cache directly?
+// const FeatureCode FC = computeFeatureCode(mHullCenterMesh, T.mVerts);
+ const FeatureCode FC = computeFeatureCode(mHullCenterMesh, currentContact.mVerts);
+
+ bool generateContact = false;
+ switch(FC)
+ {
+ // PT: trying the same as in sphere-mesh here
+ case FC_VERTEX0:
+ generateContact = !mVertCache.contains(CachedVertex(ref0));
+ break;
+ case FC_VERTEX1:
+ generateContact =!mVertCache.contains(CachedVertex(ref1));
+ break;
+ case FC_VERTEX2:
+ generateContact = !mVertCache.contains(CachedVertex(ref2));
+ break;
+ case FC_EDGE01:
+ generateContact = !mEdgeCache.contains(CachedEdge(ref0, ref1));
+ break;
+ case FC_EDGE12:
+ generateContact = !mEdgeCache.contains(CachedEdge(ref1, ref2));
+ break;
+ case FC_EDGE20:
+ generateContact = !mEdgeCache.contains(CachedEdge(ref0, ref2));
+ break;
+ case FC_FACE:
+ generateContact = true;
+ break;
+ case FC_UNDEFINED:
+ break;
+ };
+
+ if(!generateContact)
+ continue;
+
+// const PxcPlane localPlane(T.mVerts[0], T.mVerts[1], T.mVerts[2]);
+ const PxPlane localPlane(currentContact.mVerts[0], currentContact.mVerts[1], currentContact.mVerts[2]);
+// const PxVec3 triCenter = (T.mVerts[0] + T.mVerts[1] + T.mVerts[2])*(1.0f/3.0f);
+ const PxVec3 triCenter = (currentContact.mVerts[0] + currentContact.mVerts[1] + currentContact.mVerts[2])*(1.0f/3.0f);
+
+ PxVec3 groupAxis = currentContact.mGroupAxis;
+ if(generateContacts(
+ localPlane,
+// T.mVerts,
+ currentContact.mVerts,
+ triCenter, groupAxis,
+ currentContact.mGroupMinDepth, triangleIndex))
+ {
+ mAnyHits = true;
+
+ //We don't add the edges to the data - this is important because we don't want to reject triangles
+ //because we generated an edge contact with an adjacent triangle
+ /*mEdgeCache.addData(CachedEdge(ref0, ref1));
+ mEdgeCache.addData(CachedEdge(ref0, ref2));
+ mEdgeCache.addData(CachedEdge(ref1, ref2));
+ mVertCache.addData(CachedVertex(ref0));
+ mVertCache.addData(CachedVertex(ref1));
+ mVertCache.addData(CachedVertex(ref2));*/
+
+ }
+ }
+ }
+}
+
+/////////////
+
+static bool contactHullMesh2(const PolygonalData& polyData0, const PxBounds3& hullAABB, const PxTriangleMeshGeometryLL& shape1,
+ const PxTransform& transform0, const PxTransform& transform1,
+ const NarrowPhaseParams& params, ContactBuffer& contactBuffer,
+ const Cm::FastVertex2ShapeScaling& convexScaling, const Cm::FastVertex2ShapeScaling& meshScaling,
+ bool idtConvexScale, bool idtMeshScale)
+{
+ //Just a sanity-check in debug-mode
+ PX_ASSERT(shape1.getType() == PxGeometryType::eTRIANGLEMESH);
+ ////////////////////
+
+ // Compute matrices
+ const Cm::Matrix34 world0(transform0);
+ const Cm::Matrix34 world1(transform1);
+
+ // Compute relative transforms
+ const PxTransform t0to1 = transform1.transformInv(transform0);
+ const PxTransform t1to0 = transform0.transformInv(transform1);
+
+ BoxPadded hullOBB;
+ computeHullOBB(hullOBB, hullAABB, params.mContactDistance, world0, world1, meshScaling, idtMeshScale);
+
+ // Setup the collider
+ const TriangleMesh* PX_RESTRICT meshData = shape1.meshData;
+
+ Ps::InlineArray<PxU32,LOCAL_CONTACTS_SIZE> delayedContacts;
+
+ ConvexMeshContactGenerationCallback blockCallback(
+ delayedContacts,
+ t0to1, t1to0, polyData0, world0, world1, meshData, meshData->getExtraTrigData(), meshScaling,
+ convexScaling, params.mContactDistance, params.mToleranceLength,
+ idtMeshScale, idtConvexScale, params.mMeshContactMargin,
+ transform0, transform1,
+ contactBuffer, hullOBB
+ );
+
+ Midphase::intersectOBB(meshData, hullOBB, blockCallback, false);
+
+ blockCallback.mGeneration.generateLastContacts();
+
+ return blockCallback.mGeneration.mAnyHits;
+}
+
+/////////////
+
+bool Gu::contactConvexMesh(GU_CONTACT_METHOD_ARGS)
+{
+ PX_UNUSED(cache);
+ PX_UNUSED(renderOutput);
+
+ const PxTriangleMeshGeometryLL& shapeMesh = shape1.get<const PxTriangleMeshGeometryLL>();
+
+ const bool idtScaleMesh = shapeMesh.scale.isIdentity();
+
+ Cm::FastVertex2ShapeScaling meshScaling;
+ if(!idtScaleMesh)
+ meshScaling.init(shapeMesh.scale);
+
+ Cm::FastVertex2ShapeScaling convexScaling;
+ PxBounds3 hullAABB;
+ PolygonalData polyData0;
+ const bool idtScaleConvex = getConvexData(shape0, convexScaling, hullAABB, polyData0);
+
+ return contactHullMesh2(polyData0, hullAABB, shapeMesh, transform0, transform1, params, contactBuffer, convexScaling, meshScaling, idtScaleConvex, idtScaleMesh);
+}
+
+bool Gu::contactBoxMesh(GU_CONTACT_METHOD_ARGS)
+{
+ PX_UNUSED(cache);
+ PX_UNUSED(renderOutput);
+
+ const PxBoxGeometry& shapeBox = shape0.get<const PxBoxGeometry>();
+ const PxTriangleMeshGeometryLL& shapeMesh = shape1.get<const PxTriangleMeshGeometryLL>();
+
+ PolygonalData polyData0;
+ PolygonalBox polyBox(shapeBox.halfExtents);
+ polyBox.getPolygonalData(&polyData0);
+
+ const PxBounds3 hullAABB(-shapeBox.halfExtents, shapeBox.halfExtents);
+
+ const bool idtScaleMesh = shapeMesh.scale.isIdentity();
+
+ Cm::FastVertex2ShapeScaling meshScaling;
+ if(!idtScaleMesh)
+ meshScaling.init(shapeMesh.scale);
+
+ Cm::FastVertex2ShapeScaling idtScaling;
+ return contactHullMesh2(polyData0, hullAABB, shapeMesh, transform0, transform1, params, contactBuffer, idtScaling, meshScaling, true, idtScaleMesh);
+}
+
+/////////////
+
+namespace
+{
+struct ConvexVsHeightfieldContactGenerationCallback : EntityReport<PxU32>
+{
+ ConvexMeshContactGeneration mGeneration;
+ HeightFieldUtil& mHfUtil;
+
+ ConvexVsHeightfieldContactGenerationCallback(
+ HeightFieldUtil& hfUtil,
+ Ps::InlineArray<PxU32,LOCAL_CONTACTS_SIZE>& delayedContacts,
+ const PxTransform& t0to1, const PxTransform& t1to0,
+ const PolygonalData& polyData0, const Cm::Matrix34& world0, const Cm::Matrix34& world1,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ PxReal contactDistance,
+ PxReal toleranceLength,
+ bool idtConvexScale,
+ PxReal cCCDEpsilon,
+ const PxTransform& transform0, const PxTransform& transform1,
+ ContactBuffer& contactBuffer
+ ) : mGeneration(delayedContacts, t0to1, t1to0, polyData0, world0, world1, convexScaling, contactDistance, toleranceLength, idtConvexScale, cCCDEpsilon, transform0,
+ transform1, contactBuffer),
+ mHfUtil(hfUtil)
+ {
+ }
+
+ // PT: TODO: refactor/unify with similar code in other places
+ virtual bool onEvent(PxU32 nb, PxU32* indices)
+ {
+ const PxU8 nextInd[] = {2,0,1};
+
+ while(nb--)
+ {
+ const PxU32 triangleIndex = *indices++;
+
+ PxU32 vertIndices[3];
+ PxTriangle currentTriangle; // in world space
+ PxU32 adjInds[3];
+ mHfUtil.getTriangle(mGeneration.mTransform1, currentTriangle, vertIndices, adjInds, triangleIndex, false, false);
+
+ PxVec3 normal;
+ currentTriangle.normal(normal);
+
+ PxU8 triFlags = 0; //KS - temporary until we can calculate triFlags for HF
+
+ for(PxU32 a = 0; a < 3; ++a)
+ {
+ if(adjInds[a] != 0xFFFFFFFF)
+ {
+ PxTriangle adjTri;
+ mHfUtil.getTriangle(mGeneration.mTransform1, adjTri, NULL, NULL, adjInds[a], false, false);
+ //We now compare the triangles to see if this edge is active
+
+ PxVec3 adjNormal;
+ adjTri.denormalizedNormal(adjNormal);
+ PxU32 otherIndex = nextInd[a];
+ PxF32 projD = adjNormal.dot(currentTriangle.verts[otherIndex] - adjTri.verts[0]);
+ if(projD < 0.f)
+ {
+ adjNormal.normalize();
+
+ PxF32 proj = adjNormal.dot(normal);
+
+ if(proj < 0.999f)
+ {
+ triFlags |= 1 << (a+3);
+ }
+ }
+ }
+ else
+ triFlags |= (1 << (a+3));
+ }
+ mGeneration.processTriangle(currentTriangle.verts, triangleIndex, triFlags, vertIndices);
+ }
+ return true;
+ }
+
+protected:
+ ConvexVsHeightfieldContactGenerationCallback &operator=(const ConvexVsHeightfieldContactGenerationCallback &);
+};
+}
+
+static bool contactHullHeightfield2(const PolygonalData& polyData0, const PxBounds3& hullAABB, const PxHeightFieldGeometry& shape1,
+ const PxTransform& transform0, const PxTransform& transform1,
+ const NarrowPhaseParams& params, ContactBuffer& contactBuffer,
+ const Cm::FastVertex2ShapeScaling& convexScaling,
+ bool idtConvexScale)
+{
+ //We need to create a callback that fills triangles from the HF
+
+ const HeightField& hf = *static_cast<HeightField*>(shape1.heightField);
+
+ HeightFieldUtil hfUtil(shape1, hf);
+
+ const Cm::Matrix34 world0(transform0);
+ const Cm::Matrix34 world1(transform1);
+
+ ////////////////////
+
+ // Compute relative transforms
+ const PxTransform t0to1 = transform1.transformInv(transform0);
+ const PxTransform t1to0 = transform0.transformInv(transform1);
+
+ Ps::InlineArray<PxU32, LOCAL_CONTACTS_SIZE> delayedContacts;
+
+ ConvexVsHeightfieldContactGenerationCallback blockCallback(hfUtil, delayedContacts, t0to1, t1to0, polyData0, world0, world1, convexScaling, params.mContactDistance, params.mToleranceLength,
+ idtConvexScale, params.mMeshContactMargin, transform0, transform1, contactBuffer);
+
+ hfUtil.overlapAABBTriangles(transform1, PxBounds3::transformFast(t0to1, hullAABB), 0, &blockCallback);
+
+ blockCallback.mGeneration.generateLastContacts();
+
+ return blockCallback.mGeneration.mAnyHits;
+}
+
+bool Gu::contactConvexHeightfield(GU_CONTACT_METHOD_ARGS)
+{
+ PX_UNUSED(cache);
+ PX_UNUSED(renderOutput);
+
+ //Create a triangle cache from the HF triangles and then feed triangles to NP mesh methods
+ const physx::PxHeightFieldGeometryLL& shapeMesh = shape1.get<const PxHeightFieldGeometryLL>();
+
+ Cm::FastVertex2ShapeScaling convexScaling;
+ PxBounds3 hullAABB;
+ PolygonalData polyData0;
+ const bool idtScaleConvex = getConvexData(shape0, convexScaling, hullAABB, polyData0);
+ const PxVec3 inflation(params.mContactDistance);
+ hullAABB.minimum -= inflation;
+ hullAABB.maximum += inflation;
+
+ return contactHullHeightfield2(polyData0, hullAABB, shapeMesh, transform0, transform1, params, contactBuffer, convexScaling, idtScaleConvex);
+}
+
+bool Gu::contactBoxHeightfield(GU_CONTACT_METHOD_ARGS)
+{
+ PX_UNUSED(cache);
+ PX_UNUSED(renderOutput);
+
+ //Create a triangle cache from the HF triangles and then feed triangles to NP mesh methods
+ const physx::PxHeightFieldGeometryLL& shapeMesh = shape1.get<const PxHeightFieldGeometryLL>();
+
+ const PxBoxGeometry& shapeBox = shape0.get<const PxBoxGeometry>();
+
+ PolygonalData polyData0;
+ PolygonalBox polyBox(shapeBox.halfExtents);
+ polyBox.getPolygonalData(&polyData0);
+
+ const PxVec3 inflatedExtents = shapeBox.halfExtents + PxVec3(params.mContactDistance);
+
+ const PxBounds3 hullAABB = PxBounds3(-inflatedExtents, inflatedExtents);
+
+ const Cm::FastVertex2ShapeScaling idtScaling;
+
+ return contactHullHeightfield2(polyData0, hullAABB, shapeMesh, transform0, transform1, params, contactBuffer, idtScaling, true);
+}