aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/pcm/GuPersistentContactManifold.h
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/pcm/GuPersistentContactManifold.h
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/pcm/GuPersistentContactManifold.h')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/pcm/GuPersistentContactManifold.h846
1 files changed, 846 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/pcm/GuPersistentContactManifold.h b/PhysX_3.4/Source/GeomUtils/src/pcm/GuPersistentContactManifold.h
new file mode 100644
index 00000000..7ee6c484
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/pcm/GuPersistentContactManifold.h
@@ -0,0 +1,846 @@
+// 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.
+
+#ifndef Gu_PERSISTENTCONTACTMANIFOLD_H
+#define Gu_PERSISTENTCONTACTMANIFOLD_H
+
+#include "PxPhysXCommonConfig.h"
+#include "foundation/PxUnionCast.h"
+#include "foundation/PxMemory.h"
+#include "CmPhysXCommon.h"
+#include "PsVecTransform.h"
+
+#define PCM_LOW_LEVEL_DEBUG 0
+
+namespace physx
+{
+
+#define VISUALIZE_PERSISTENT_CONTACT 1
+//This is for pritimives vs primitives
+#define GU_MANIFOLD_CACHE_SIZE 4
+//These are for pritimives vs mesh
+#define GU_SINGLE_MANIFOLD_SINGLE_POLYGONE_CACHE_SIZE 5
+#define GU_SINGLE_MANIFOLD_CACHE_SIZE 6
+#define GU_SPHERE_MANIFOLD_CACHE_SIZE 1
+#define GU_CAPSULE_MANIFOLD_CACHE_SIZE 3
+#define GU_MAX_MANIFOLD_SIZE 6
+#define GU_MESH_CONTACT_REDUCTION_THRESHOLD 16
+
+
+//ML: this is used to compared with the shape's margin to decide the final tolerance used in the manifold to validate the existing contacts.
+//In the case of big shape and relatively speaking small triangles in the mesh, we need to take a smaller margin. This helps because the PCM
+//recycling thresholds are proportionate to margin so it makes it less likely to discard previous contacts due to separation
+#define GU_PCM_MESH_MANIFOLD_EPSILON 0.05f
+
+
+namespace Cm
+{
+ class RenderOutput;
+}
+
+
+namespace Gu
+{
+ struct ContactPoint;
+ class ContactBuffer;
+
+extern const PxF32 invalidateThresholds[5];
+extern const PxF32 invalidateQuatThresholds[5];
+extern const PxF32 invalidateThresholds2[3];
+extern const PxF32 invalidateQuatThresholds2[3];
+
+
+Ps::aos::Mat33V findRotationMatrixFromZAxis(const Ps::aos::Vec3VArg to);
+
+//This contact is used in the primitives vs primitives contact gen
+class PersistentContact
+{
+public:
+ PersistentContact()
+ {
+ }
+
+ PersistentContact(Ps::aos::Vec3V _localPointA, Ps::aos::Vec3V _localPointB, Ps::aos::Vec4V _localNormalPen) :
+ mLocalPointA(_localPointA), mLocalPointB(_localPointB), mLocalNormalPen(_localNormalPen)
+ {
+
+ }
+
+ Ps::aos::Vec3V mLocalPointA;
+ Ps::aos::Vec3V mLocalPointB;
+ Ps::aos::Vec4V mLocalNormalPen; // the (x, y, z) is the local normal, and the w is the penetration depth
+};
+
+//This contact is used in the mesh contact gen to store an extra variable
+class MeshPersistentContact : public PersistentContact
+{
+public:
+ PxU32 mFaceIndex;
+};
+
+//This contact is used in the compress stream buffer(NpCacheStreamPair in the PxcNpThreadContext) to store the data we need
+PX_ALIGN_PREFIX(16)
+class CachedMeshPersistentContact
+{
+public:
+ PxVec3 mLocalPointA; //16 byte aligned
+ PxU32 mFaceIndex; //face index
+ PxVec3 mLocalPointB; //16 byte aligned
+ PxU32 mPad; //pad
+ PxVec3 mLocalNormal; //16 byte aligned
+ PxReal mPen; //penetration
+}PX_ALIGN_SUFFIX(16);
+
+
+#if PX_VC
+ #pragma warning(push)
+ #pragma warning( disable : 4324 ) // Padding was added at the end of a structure because of a __declspec(align) value.
+#endif
+
+//This class is used to store the start and end index of the mesh persistent contacts in an array.
+struct PCMContactPatch
+{
+public:
+ PCMContactPatch()
+ {
+ mNextPatch = NULL;
+ mEndPatch = NULL;
+ mRoot = this;
+ mPatchMaxPen = Ps::aos::FMax();
+ }
+ Ps::aos::Vec3V mPatchNormal;
+ PCMContactPatch* mNextPatch;//store the next patch pointer in the patch list
+ PCMContactPatch* mEndPatch;//store the last patch pointer in the patch list
+ PCMContactPatch* mRoot;//if this is the start of the patch list which has very similar patch normal, the root will be itself
+ Ps::aos::FloatV mPatchMaxPen;//store the deepest penetration of the whole patch
+ PxU32 mStartIndex;//store the start index of the manifold contacts in the manifold contacts stream
+ PxU32 mEndIndex;//store the end index of the manifold contacts in the manifold contacts stream
+ PxU32 mTotalSize;//if this is the root, the total size will store the total number of manifold contacts in the whole patch list
+};
+
+#if PX_VC
+ #pragma warning(pop)
+#endif
+
+//ML: this is needed because it seems NEON doesn't force the alignment on SIMD type, which cause some of the PCM unit tests fail
+PX_ALIGN_PREFIX(16)
+class PersistentContactManifold
+{
+public:
+
+ PersistentContactManifold(PersistentContact* contactPointsBuff, PxU8 capacity): mNumContacts(0), mCapacity(capacity), mNumWarmStartPoints(0), mContactPoints(contactPointsBuff)
+ {
+ mRelativeTransform.Invalidate();
+ }
+
+ PX_FORCE_INLINE PxU32 getNumContacts() const { return mNumContacts;}
+
+ PX_FORCE_INLINE bool isEmpty() { return mNumContacts==0; }
+
+ PX_FORCE_INLINE PersistentContact& getContactPoint(const PxU32 index)
+ {
+ PX_ASSERT(index < GU_MANIFOLD_CACHE_SIZE);
+ return mContactPoints[index];
+ }
+
+ PX_FORCE_INLINE Ps::aos::FloatV maxTransformdelta(const Ps::aos::PsTransformV& curTransform)
+ {
+ using namespace Ps::aos;
+ const Vec4V p0 = Vec4V_From_Vec3V(mRelativeTransform.p);
+ const Vec4V q0 = mRelativeTransform.q;
+ const Vec4V p1 = Vec4V_From_Vec3V(curTransform.p);
+ const Vec4V q1 = curTransform.q;
+
+ const Vec4V dp = V4Abs(V4Sub(p1, p0));
+ const Vec4V dq = V4Abs(V4Sub(q1, q0));
+
+ const Vec4V max0 = V4Max(dp, dq);
+
+ //need to work out max from a single vector...
+ return V4ExtractMax(max0);
+ }
+
+ PX_FORCE_INLINE Ps::aos::Vec4V maxTransformdelta2(const Ps::aos::PsTransformV& curTransform)
+ {
+ using namespace Ps::aos;
+ const Vec4V p0 = Vec4V_From_Vec3V(mRelativeTransform.p);
+ const Vec4V q0 = mRelativeTransform.q;
+ const Vec4V p1 = Vec4V_From_Vec3V(curTransform.p);
+ const Vec4V q1 = curTransform.q;
+
+ const Vec4V dp = V4Abs(V4Sub(p1, p0));
+ const Vec4V dq = V4Abs(V4Sub(q1, q0));
+
+ const Vec4V max0 = V4Max(dp, dq);
+
+ //need to work out max from a single vector...
+ return max0;
+ }
+
+ PX_FORCE_INLINE Ps::aos::FloatV maxTransformPositionDelta(const Ps::aos::Vec3V& curP)
+ {
+ using namespace Ps::aos;
+
+ const Vec3V deltaP = V3Sub(curP, mRelativeTransform.p);
+ const Vec4V delta = Vec4V_From_Vec3V(V3Abs(deltaP));
+ //need to work out max from a single vector...
+ return V4ExtractMax(delta);
+ }
+
+ PX_FORCE_INLINE Ps::aos::FloatV maxTransformQuatDelta(const Ps::aos::QuatV& curQ)
+ {
+ using namespace Ps::aos;
+
+ const Vec4V deltaQ = V4Sub(curQ, mRelativeTransform.q);
+ const Vec4V delta = V4Abs(deltaQ);
+ //need to work out max from a single vector...
+ return V4ExtractMax(delta);
+ }
+
+ PX_FORCE_INLINE void setRelativeTransform(const Ps::aos::PsTransformV& transform)
+ {
+ mRelativeTransform = transform;
+ }
+
+ //This is used for the box/convexhull vs box/convexhull contact gen to decide whether the relative movement of a pair of objects are
+ //small enough. In this case, we can skip the collision detection all together
+ PX_FORCE_INLINE PxU32 invalidate_BoxConvex(const Ps::aos::PsTransformV& curRTrans, const Ps::aos::FloatVArg minMargin)
+ {
+ using namespace Ps::aos;
+ PX_ASSERT(mNumContacts <= GU_MANIFOLD_CACHE_SIZE);
+ const FloatV ratio = FLoad(invalidateThresholds[mNumContacts]);
+ const FloatV thresholdP = FMul(minMargin, ratio);
+ const FloatV deltaP = maxTransformPositionDelta(curRTrans.p);
+
+ const FloatV thresholdQ = FLoad(invalidateQuatThresholds[mNumContacts]);
+ const FloatV deltaQ = QuatDot(curRTrans.q, mRelativeTransform.q);
+ const BoolV con = BOr(FIsGrtr(deltaP, thresholdP), FIsGrtr(thresholdQ, deltaQ));
+
+ return BAllEqTTTT(con);
+ }
+
+ //This is used for the sphere/capsule vs other primitives contact gen to decide whether the relative movement of a pair of objects are
+ //small enough. In this case, we can skip the collision detection all together
+ PX_FORCE_INLINE PxU32 invalidate_SphereCapsule(const Ps::aos::PsTransformV& curRTrans, const Ps::aos::FloatVArg minMargin)
+ {
+ using namespace Ps::aos;
+ PX_ASSERT(mNumContacts <= 2);
+ const FloatV ratio = FLoad(invalidateThresholds2[mNumContacts]);
+
+ const FloatV thresholdP = FMul(minMargin, ratio);
+ const FloatV deltaP = maxTransformPositionDelta(curRTrans.p);
+
+ const FloatV thresholdQ = FLoad(invalidateQuatThresholds2[mNumContacts]);
+ const FloatV deltaQ = QuatDot(curRTrans.q, mRelativeTransform.q);
+ const BoolV con = BOr(FIsGrtr(deltaP, thresholdP), FIsGrtr(thresholdQ, deltaQ));
+
+ return BAllEqTTTT(con);
+ }
+
+ //This is used for plane contact gen to decide whether the relative movement of a pair of objects are small enough. In this case,
+ //we can skip the collision detection all together
+ PX_FORCE_INLINE PxU32 invalidate_PrimitivesPlane(const Ps::aos::PsTransformV& curRTrans, const Ps::aos::FloatVArg minMargin, const Ps::aos::FloatVArg ratio)
+ {
+ using namespace Ps::aos;
+ const FloatV thresholdP = FMul(minMargin, ratio);
+ const FloatV deltaP = maxTransformPositionDelta(curRTrans.p);
+
+ const FloatV thresholdQ = FLoad(0.9998f);//about 1 degree
+ const FloatV deltaQ = QuatDot(curRTrans.q, mRelativeTransform.q);
+ const BoolV con = BOr(FIsGrtr(deltaP, thresholdP), FIsGrtr(thresholdQ, deltaQ));
+
+ return BAllEqTTTT(con);
+ }
+
+ PX_FORCE_INLINE void removeContactPoint (PxU32 index)
+ {
+ mNumContacts--;
+ mContactPoints[index] = mContactPoints[mNumContacts];
+ }
+
+ bool validContactDistance(const PersistentContact& pt, const Ps::aos::FloatVArg breakingThreshold) const
+ {
+ using namespace Ps::aos;
+ const FloatV dist = V4GetW(pt.mLocalNormalPen);
+ return FAllGrtr(breakingThreshold, dist) != 0;
+ }
+
+ PX_FORCE_INLINE void clearManifold()
+ {
+ mNumWarmStartPoints = 0;
+ mNumContacts = 0;
+ mRelativeTransform.Invalidate();
+ }
+
+ PX_FORCE_INLINE void initialize()
+ {
+ clearManifold();
+ }
+
+ //This function is used to replace the existing contact with the newly created contact if their distance are within some threshold
+ bool replaceManifoldPoint(const Ps::aos::Vec3VArg localPointA, const Ps::aos::Vec3VArg localPointB, const Ps::aos::Vec4VArg localNormalPen, const Ps::aos::FloatVArg replaceBreakingThreshold);
+
+ //This function is to add a point(in box/convexhull contact gen) to the exising manifold. If the number of manifold is more than 4, we need to do contact reduction
+ PxU32 addManifoldPoint( const Ps::aos::Vec3VArg localPointA, const Ps::aos::Vec3VArg localPointB, const Ps::aos::Vec4VArg localNormalAPen, const Ps::aos::FloatVArg replaceBreakingThreshold);
+ //This function is to add a point(in capsule contact gen) to the exising manifold. If the number of manifold is more than 4, we need to do contact reduction
+ PxU32 addManifoldPoint2( const Ps::aos::Vec3VArg localPointA, const Ps::aos::Vec3VArg localPointB, const Ps::aos::Vec4VArg localNormalAPen, const Ps::aos::FloatVArg replaceBreakingThreshold);//max two points of contacts
+ //This function is used in box-plane contact gen to add the plane contacts to the manifold
+ void addBatchManifoldContactsCluster( const PersistentContact* manifoldPoints, const PxU32 numPoints);
+
+ //This function is used in the capsule full manifold contact genenation(maximum 2 points).
+ void addBatchManifoldContacts2( const PersistentContact* manifoldPoints, const PxU32 numPoints);//max two points of contacts
+
+ //This function is used in the box/convexhull full manifold contact generation(maximum 4 points).
+ void addBatchManifoldContacts(const PersistentContact* manifoldPoints, const PxU32 numPoints);
+ //This function is using the cluster algorithm to reduce contacts
+ void reduceBatchContactsCluster(const PersistentContact* manifoldPoints, const PxU32 numPoints);
+ //This function is called by addBatchManifoldContacts2 to reduce the manifold contacts to 2 points;
+ void reduceBatchContacts2(const PersistentContact* manifoldPoints, const PxU32 numPoints);
+ //This function is called by addBatchManifoldContacts to reduce the manifold contacts to 4 points
+ void reduceBatchContacts(const PersistentContact* manifoldPoints, const PxU32 numPoints);
+
+ //This function is used for incremental manifold contact reduction for box/convexhull
+ PxU32 reduceContactsForPCM(const Ps::aos::Vec3VArg localPointA, const Ps::aos::Vec3VArg localPointB, const Ps::aos::Vec4VArg localNormalPen);
+ //This function is used for incremental manifold contact reduction for capsule
+ PxU32 reduceContactSegment(const Ps::aos::Vec3VArg localPointA, const Ps::aos::Vec3VArg localPointB, const Ps::aos::Vec4VArg localNormalPen);
+
+
+ /*
+ This function recalculate the contacts in the manifold based on the current relative transform between a pair of objects. If the recalculated contacts are within some threshold,
+ we will keep the contacts; Otherwise, we will remove the contacts.
+ */
+ void refreshContactPoints(const Ps::aos::PsMatTransformV& relTra, const Ps::aos::FloatVArg projectBreakingThreshold, const Ps::aos::FloatVArg contactOffset);
+ //This function is just used in boxbox contact gen for fast transform
+ void addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::Vec3VArg normal, const Ps::aos::PsMatTransformV& transf1);
+ //This function is for adding box/convexhull manifold contacts to the contact buffer
+ void addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::Vec3VArg normal, const Ps::aos::PsTransformV& transf1, const Ps::aos::FloatVArg contactOffset);
+ //This function is for adding sphere/capsule manifold contacts to the contact buffer
+ void addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::Vec3VArg normal, const Ps::aos::PsTransformV& transf0, const Ps::aos::FloatVArg radius, const Ps::aos::FloatVArg contactOffset);
+
+ //get the average normal in the manifold in world space
+ Ps::aos::Vec3V getWorldNormal(const Ps::aos::PsTransformV& trB);
+ //get the average normal in the manifold in local B object space
+ Ps::aos::Vec3V getLocalNormal();
+
+ void drawManifold(Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB);
+ void drawManifold(Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB, const Ps::aos::FloatVArg radius);
+ void drawManifold(const PersistentContact& m, Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB);
+ static void drawPoint(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p, const PxF32 size, const PxU32 color = 0x0000ff00);
+ static void drawLine(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p0, const Ps::aos::Vec3VArg p1, const PxU32 color = 0xff00ffff);
+ static void drawTriangle(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p0, const Ps::aos::Vec3VArg p1, const Ps::aos::Vec3VArg p2, const PxU32 color = 0xffff0000);
+ static void drawPolygon( Cm::RenderOutput& out, const Ps::aos::PsTransformV& transform, Ps::aos::Vec3V* points, const PxU32 numVerts, const PxU32 color = 0xff00ffff);
+ static void drawPolygon( Cm::RenderOutput& out, const Ps::aos::PsMatTransformV& transform, Ps::aos::Vec3V* points, const PxU32 numVerts, const PxU32 color = 0xff00ffff);
+
+ Ps::aos::PsTransformV mRelativeTransform;//aToB
+ PxU8 mNumContacts;
+ PxU8 mCapacity;
+ PxU8 mNumWarmStartPoints;
+ PxU8 mAIndice[4];
+ PxU8 mBIndice[4];
+ PersistentContact* mContactPoints;
+} PX_ALIGN_SUFFIX(16);
+
+PX_ALIGN_PREFIX(16)
+class LargePersistentContactManifold : public PersistentContactManifold
+{
+public:
+ LargePersistentContactManifold() : PersistentContactManifold(mContactPointsBuff, GU_MANIFOLD_CACHE_SIZE)
+ {
+ }
+
+ PersistentContact mContactPointsBuff[GU_MANIFOLD_CACHE_SIZE];
+}PX_ALIGN_SUFFIX(16);
+
+PX_ALIGN_PREFIX(16)
+class SpherePersistentContactManifold : public PersistentContactManifold
+{
+public:
+ SpherePersistentContactManifold() : PersistentContactManifold(mContactPointsBuff, GU_SPHERE_MANIFOLD_CACHE_SIZE)
+ {
+ }
+
+ PersistentContact mContactPointsBuff[GU_SPHERE_MANIFOLD_CACHE_SIZE];
+}PX_ALIGN_SUFFIX(16);
+
+PX_ALIGN_PREFIX(16)
+class SinglePersistentContactManifold
+{
+public:
+
+ SinglePersistentContactManifold(): mNumContacts(0)
+ {
+ }
+
+ PX_FORCE_INLINE PxU32 getNumContacts() const { return mNumContacts;}
+
+ PX_FORCE_INLINE bool isEmpty() { return mNumContacts==0; }
+
+ PX_FORCE_INLINE MeshPersistentContact& getContactPoint(const PxU32 index)
+ {
+ PX_ASSERT(index < GU_SINGLE_MANIFOLD_CACHE_SIZE);
+ return mContactPoints[index];
+ }
+
+ PX_FORCE_INLINE void removeContactPoint (PxU32 index)
+ {
+ mNumContacts--;
+ mContactPoints[index] = mContactPoints[mNumContacts];
+ }
+
+ PX_FORCE_INLINE void clearManifold()
+ {
+ mNumContacts = 0;
+ }
+
+ PX_FORCE_INLINE void initialize()
+ {
+ clearManifold();
+ }
+
+
+ PX_FORCE_INLINE Ps::aos::Vec3V getWorldNormal(const Ps::aos::PsTransformV& trB)
+ {
+ using namespace Ps::aos;
+ Vec4V nPen = mContactPoints[0].mLocalNormalPen;
+ for(PxU32 i =1; i < mNumContacts; ++i)
+ {
+ nPen = V4Add(nPen, mContactPoints[i].mLocalNormalPen);
+ }
+
+ const Vec3V n = Vec3V_From_Vec4V(nPen);
+ return V3Normalize(trB.rotate(n));
+ }
+
+ PX_FORCE_INLINE Ps::aos::Vec3V getLocalNormal()
+ {
+ using namespace Ps::aos;
+ Vec4V nPen = mContactPoints[0].mLocalNormalPen;
+ for(PxU32 i =1; i < mNumContacts; ++i)
+ {
+ nPen = V4Add(nPen, mContactPoints[i].mLocalNormalPen);
+ }
+ return V3Normalize(Vec3V_From_Vec4V(nPen));
+ }
+
+ //This function reduces the manifold contact list in a patch for box/convexhull vs mesh
+ Ps::aos::FloatV reduceBatchContactsConvex(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch);
+ //This function reduces the manifold contact list in a patch for sphere vs mesh
+ Ps::aos::FloatV reduceBatchContactsSphere(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch);
+ //This function reduces the manifold contact list in a pathc for capsuel vs mesh
+ Ps::aos::FloatV reduceBatchContactsCapsule(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch);
+
+ //This function adds the manifold contact list in a patch for box/convexhull vs mesh
+ Ps::aos::FloatV addBatchManifoldContactsConvex(const MeshPersistentContact* manifoldContact, const PxU32 numContacts, PCMContactPatch& patch, const Ps::aos::FloatVArg replaceBreakingThreshold);
+ //This function adds the manifold contact list in a patch for sphere vs mesh
+ Ps::aos::FloatV addBatchManifoldContactsSphere(const MeshPersistentContact* manifoldContact, const PxU32 numContacts, PCMContactPatch& patch, const Ps::aos::FloatVArg replaceBreakingThreshold);
+ //This function adds the manifold contact list in a patch for capsule vs mesh
+ Ps::aos::FloatV addBatchManifoldContactsCapsule(const MeshPersistentContact* manifoldContact, const PxU32 numContacts, PCMContactPatch& patch, const Ps::aos::FloatVArg replaceBreakingThreshold);
+
+ //This is used for in the addContactsToPatch for convex mesh contact gen.
+ static PxU32 reduceContacts(MeshPersistentContact* manifoldContactExt, PxU32 numContacts);
+
+ //This function is to recalculate the contacts based on the relative transform between a pair of objects
+ Ps::aos::FloatV refreshContactPoints(const Ps::aos::PsMatTransformV& relTra, const Ps::aos::FloatVArg projectBreakingThreshold, const Ps::aos::FloatVArg contactOffset);
+
+ void drawManifold(Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB);
+
+ MeshPersistentContact mContactPoints[GU_SINGLE_MANIFOLD_CACHE_SIZE];//384 bytes
+ PxU32 mNumContacts;//400 bytes
+
+} PX_ALIGN_SUFFIX(16);
+
+//This is a structure used to cache a multi-persistent-manifold in the cache stream
+struct MultiPersistentManifoldHeader
+{
+ Ps::aos::PsTransformV mRelativeTransform;//aToB
+ PxU32 mNumManifolds;
+ PxU32 pad[3];
+};
+
+struct SingleManifoldHeader
+{
+ PxU32 mNumContacts;
+ PxU32 pad[3];
+};
+
+#if PX_VC
+#pragma warning(push)
+#pragma warning( disable : 4251 ) // class needs to have dll-interface to be used by clients of class
+#endif
+
+PX_ALIGN_PREFIX(16)
+class PX_PHYSX_COMMON_API MultiplePersistentContactManifold
+{
+public:
+ MultiplePersistentContactManifold():mNumManifolds(0), mNumTotalContacts(0)
+ {
+ mRelativeTransform.Invalidate();
+ }
+
+ PX_FORCE_INLINE void setRelativeTransform(const Ps::aos::PsTransformV& transform)
+ {
+ mRelativeTransform = transform;
+ }
+
+ PX_FORCE_INLINE Ps::aos::FloatV maxTransformPositionDelta(const Ps::aos::Vec3V& curP)
+ {
+ using namespace Ps::aos;
+
+ const Vec3V deltaP = V3Sub(curP, mRelativeTransform.p);
+ const Vec4V delta = Vec4V_From_Vec3V(V3Abs(deltaP));
+ //need to work out max from a single vector...
+ return V4ExtractMax(delta);
+ }
+
+ PX_FORCE_INLINE Ps::aos::FloatV maxTransformQuatDelta(const Ps::aos::QuatV& curQ)
+ {
+ using namespace Ps::aos;
+
+ const Vec4V deltaQ = V4Sub(curQ, mRelativeTransform.q);
+ const Vec4V delta = V4Abs(deltaQ);
+ //need to work out max from a single vector...
+ return V4ExtractMax(delta);
+ }
+
+ PX_FORCE_INLINE PxU32 invalidate(const Ps::aos::PsTransformV& curRTrans, const Ps::aos::FloatVArg minMargin, const Ps::aos::FloatVArg ratio)
+ {
+ using namespace Ps::aos;
+
+ const FloatV thresholdP = FMul(minMargin, ratio);
+ const FloatV deltaP = maxTransformPositionDelta(curRTrans.p);
+ const FloatV thresholdQ = FLoad(0.9998f);//about 1 degree
+ const FloatV deltaQ = QuatDot(curRTrans.q, mRelativeTransform.q);
+ const BoolV con = BOr(FIsGrtr(deltaP, thresholdP), FIsGrtr(thresholdQ, deltaQ));
+
+ return BAllEqTTTT(con);
+ }
+
+ PX_FORCE_INLINE PxU32 invalidate(const Ps::aos::PsTransformV& curRTrans, const Ps::aos::FloatVArg minMargin)
+ {
+ using namespace Ps::aos;
+ return invalidate(curRTrans, minMargin, FLoad(0.2f));
+ }
+
+ /*
+ This function work out the contact patch connectivity. If two patches's normal are within 5 degree, we would link these two patches together and reset the total size.
+ */
+ PX_FORCE_INLINE void refineContactPatchConnective(PCMContactPatch** contactPatch, PxU32 numContactPatch, MeshPersistentContact* manifoldContacts, const Ps::aos::FloatVArg acceptanceEpsilon)
+ {
+ PX_UNUSED(manifoldContacts);
+
+ using namespace Ps::aos;
+
+ //work out the contact patch connectivity, the patchNormal should be in the local space of mesh
+ for(PxU32 i=0; i<numContactPatch; ++i)
+ {
+ PCMContactPatch* patch = contactPatch[i];
+ patch->mRoot = patch;
+ patch->mEndPatch = patch;
+ patch->mTotalSize = patch->mEndIndex - patch->mStartIndex;
+ patch->mNextPatch = NULL;
+
+ for(PxU32 j=i; j>0; --j)
+ {
+ PCMContactPatch* other = contactPatch[j-1];
+ const FloatV d = V3Dot(patch->mPatchNormal, other->mRoot->mPatchNormal);
+ if(FAllGrtrOrEq(d, acceptanceEpsilon))//less than 5 degree
+ {
+
+ other->mNextPatch = patch;
+ other->mRoot->mEndPatch = patch;
+ patch->mRoot = other->mRoot;
+ other->mRoot->mTotalSize += patch->mEndIndex - patch->mStartIndex;
+ break;
+ }
+ }
+ }
+ }
+
+
+ /*
+ This function uses to reduce the manifold contacts which are in different connected patchs but are within replace breaking threshold
+ */
+ PX_FORCE_INLINE PxU32 reduceManifoldContactsInDifferentPatches(PCMContactPatch** contactPatch, PxU32 numContactPatch, MeshPersistentContact* manifoldContacts, PxU32 numContacts, const Ps::aos::FloatVArg sqReplaceBreaking)
+ {
+ using namespace Ps::aos;
+
+ for(PxU32 i=0; i<numContactPatch; ++i)
+ {
+ PCMContactPatch* currentPatch = contactPatch[i];
+ //this make sure the patch is the root before we do the contact reduction, otherwise, we will do duplicate work
+ if(currentPatch->mRoot == currentPatch)
+ {
+ while(currentPatch)
+ {
+ PCMContactPatch* nextPatch = currentPatch->mNextPatch;
+ if(nextPatch)
+ {
+ for(PxU32 k = currentPatch->mStartIndex; k<currentPatch->mEndIndex; ++k)
+ {
+ for(PxU32 l = nextPatch->mStartIndex; l < nextPatch->mEndIndex; ++l)
+ {
+ Vec3V dif = V3Sub(manifoldContacts[l].mLocalPointB, manifoldContacts[k].mLocalPointB);
+ FloatV d = V3Dot(dif, dif);
+ if(FAllGrtr(sqReplaceBreaking, d))
+ {
+ //if two manifold contacts are within threshold, we will get rid of the manifold contacts in the other contact patch
+ manifoldContacts[l] = manifoldContacts[nextPatch->mEndIndex-1];
+ nextPatch->mEndIndex--;
+ numContacts--;
+ l--;
+ }
+ }
+ }
+ }
+ currentPatch = nextPatch;
+ }
+ }
+ }
+
+ return numContacts;
+ }
+
+
+ /*
+ This function is for the multiple manifold loop through each individual single manifold to recalculate the contacts based on the relative transform between a pair of objects
+ */
+ PX_FORCE_INLINE void refreshManifold(const Ps::aos::PsMatTransformV& relTra, const Ps::aos::FloatVArg projectBreakingThreshold, const Ps::aos::FloatVArg contactDist)
+ {
+ using namespace Ps::aos;
+
+ //refresh manifold contacts
+ for(PxU32 i=0; i < mNumManifolds; ++i)
+ {
+ PxU8 ind = mManifoldIndices[i];
+ PX_ASSERT(mManifoldIndices[i] < GU_MAX_MANIFOLD_SIZE);
+ PxU32 nextInd = PxMin(i, mNumManifolds-2u)+1;
+ Ps::prefetchLine(&mManifolds[mManifoldIndices[nextInd]]);
+ Ps::prefetchLine(&mManifolds[mManifoldIndices[nextInd]],128);
+ Ps::prefetchLine(&mManifolds[mManifoldIndices[nextInd]],256);
+ FloatV _maxPen = mManifolds[ind].refreshContactPoints(relTra, projectBreakingThreshold, contactDist);
+ if(mManifolds[ind].isEmpty())
+ {
+ //swap the index with the next manifolds
+ PxU8 index = mManifoldIndices[--mNumManifolds];
+ mManifoldIndices[mNumManifolds] = ind;
+ mManifoldIndices[i] = index;
+ i--;
+ }
+ else
+ {
+ FStore(_maxPen, &mMaxPen[ind]);
+ }
+ }
+ }
+
+
+ PX_FORCE_INLINE void initialize()
+ {
+ mNumManifolds = 0;
+ mNumTotalContacts = 0;
+ mRelativeTransform.Invalidate();
+ for(PxU8 i=0; i<GU_MAX_MANIFOLD_SIZE; ++i)
+ {
+ mManifolds[i].initialize();
+ mManifoldIndices[i] = i;
+ }
+ }
+
+ PX_FORCE_INLINE void clearManifold()
+ {
+ for(PxU8 i=0; i<mNumManifolds; ++i)
+ {
+ mManifolds[i].clearManifold();
+ }
+ mNumManifolds = 0;
+ mNumTotalContacts = 0;
+ mRelativeTransform.Invalidate();
+ }
+
+ PX_FORCE_INLINE SinglePersistentContactManifold* getManifold(const PxU32 index)
+ {
+ PX_ASSERT(index < GU_MAX_MANIFOLD_SIZE);
+ return &mManifolds[mManifoldIndices[index]];
+ }
+
+ PX_FORCE_INLINE SinglePersistentContactManifold* getEmptyManifold()
+ {
+ if(mNumManifolds < GU_MAX_MANIFOLD_SIZE)
+ return &mManifolds[mManifoldIndices[mNumManifolds]];
+ return NULL;
+ }
+
+ //This function adds the manifold contacts with different patches into the corresponding single persistent contact manifold
+ void addManifoldContactPoints(MeshPersistentContact* manifoldContact, PxU32 numManifoldContacts, PCMContactPatch** contactPatch, const PxU32 numPatch,
+ const Ps::aos::FloatVArg sqReplaceBreakingThreshold, const Ps::aos::FloatVArg acceptanceEpsilon, PxU8 maxContactsPerManifold);
+ //This function adds the box/convexhull manifold contacts to the contact buffer
+ bool addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::PsTransformV& transf1);
+ //This function adds the sphere/capsule manifold contacts to the contact buffer
+ bool addManifoldContactsToContactBuffer(Gu::ContactBuffer& contactBuffer, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB, const Ps::aos::FloatVArg radius);
+ void drawManifold(Cm::RenderOutput& out, const Ps::aos::PsTransformV& trA, const Ps::aos::PsTransformV& trB);
+
+ //Code to load from a buffer and store to a buffer.
+ void fromBuffer(PxU8* PX_RESTRICT buffer);
+ void toBuffer(PxU8* PX_RESTRICT buffer);
+
+ static void drawLine(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p0, const Ps::aos::Vec3VArg p1, const PxU32 color = 0xff00ffff);
+ static void drawLine(Cm::RenderOutput& out, const PxVec3 p0, const PxVec3 p1, const PxU32 color = 0xff00ffff);
+ static void drawPoint(Cm::RenderOutput& out, const Ps::aos::Vec3VArg p, const PxF32 size, const PxU32 color = 0x00ff0000);
+ static void drawPolygon( Cm::RenderOutput& out, const Ps::aos::PsTransformV& transform, Ps::aos::Vec3V* points, const PxU32 numVerts, const PxU32 color = 0xff00ffff);
+
+ Ps::aos::PsTransformV mRelativeTransform;//aToB
+ PxF32 mMaxPen[GU_MAX_MANIFOLD_SIZE];
+ PxU8 mManifoldIndices[GU_MAX_MANIFOLD_SIZE];
+ PxU8 mNumManifolds;
+ PxU8 mNumTotalContacts;
+ SinglePersistentContactManifold mManifolds[GU_MAX_MANIFOLD_SIZE];
+
+
+} PX_ALIGN_SUFFIX(16);
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+/*
+ This function calculates the average normal in the manifold in world space
+*/
+PX_FORCE_INLINE Ps::aos::Vec3V PersistentContactManifold::getWorldNormal(const Ps::aos::PsTransformV& trB)
+{
+ using namespace Ps::aos;
+
+ Vec4V nPen = mContactPoints[0].mLocalNormalPen;
+ for(PxU32 i =1; i < mNumContacts; ++i)
+ {
+ nPen = V4Add(nPen, mContactPoints[i].mLocalNormalPen);
+ }
+
+ const Vec3V n = Vec3V_From_Vec4V(nPen);
+ const FloatV sqLength = V3Dot(n, n);
+ const Vec3V nn = V3Sel(FIsGrtr(sqLength, FEps()), n, Vec3V_From_Vec4V(mContactPoints[0].mLocalNormalPen));
+ return V3Normalize(trB.rotate(nn));
+}
+
+/*
+ This function calculates the average normal in the manifold in local B space
+*/
+PX_FORCE_INLINE Ps::aos::Vec3V PersistentContactManifold::getLocalNormal()
+{
+ using namespace Ps::aos;
+
+ Vec4V nPen = mContactPoints[0].mLocalNormalPen;
+ for(PxU32 i =1; i < mNumContacts; ++i)
+ {
+ nPen = V4Add(nPen, mContactPoints[i].mLocalNormalPen);
+ }
+ return V3Normalize(Vec3V_From_Vec4V(nPen));
+}
+
+/*
+ This function recalculates the contacts in the manifold based on the current relative transform between a pair of objects. If the recalculated contacts are within some threshold,
+ we will keep the contacts; Otherwise, we will remove the contacts.
+*/
+PX_FORCE_INLINE void PersistentContactManifold::refreshContactPoints(const Ps::aos::PsMatTransformV& aToB, const Ps::aos::FloatVArg projectBreakingThreshold, const Ps::aos::FloatVArg /*contactOffset*/)
+{
+ using namespace Ps::aos;
+ const FloatV sqProjectBreakingThreshold = FMul(projectBreakingThreshold, projectBreakingThreshold);
+
+ // first refresh worldspace positions and distance
+ for (PxU32 i=mNumContacts; i > 0; --i)
+ {
+ PersistentContact& 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);
+ }
+ }
+}
+
+/*
+ This function copies the mesh persistent contact from the multiple manifold to compress buffer(NpCacheStreamPair in the PxcNpThreadContext)
+*/
+PX_INLINE void MultiplePersistentContactManifold::toBuffer(PxU8* PX_RESTRICT buffer)
+{
+ using namespace Ps::aos;
+ PxU8* buff = buffer;
+
+ PX_ASSERT(((uintptr_t(buff)) & 0xF) == 0);
+ MultiPersistentManifoldHeader* PX_RESTRICT header = reinterpret_cast<MultiPersistentManifoldHeader*>(buff);
+ buff += sizeof(MultiPersistentManifoldHeader);
+
+ PX_ASSERT(mNumManifolds <= GU_MAX_MANIFOLD_SIZE);
+ header->mNumManifolds = mNumManifolds;
+ header->mRelativeTransform = mRelativeTransform;
+
+ for(PxU32 a = 0; a < mNumManifolds; ++a)
+ {
+ SingleManifoldHeader* manHeader = reinterpret_cast<SingleManifoldHeader*>(buff);
+ buff += sizeof(SingleManifoldHeader);
+ SinglePersistentContactManifold& manifold = *getManifold(a);
+ manHeader->mNumContacts = manifold.mNumContacts;
+ PX_ASSERT((uintptr_t(buff) & 0xf) == 0);
+ CachedMeshPersistentContact* contacts = reinterpret_cast<CachedMeshPersistentContact*>(buff);
+ //convert the mesh persistent contact to cached mesh persistent contact to save 16 byte memory per contact
+ for(PxU32 b = 0; b<manifold.mNumContacts; ++b)
+ {
+ V4StoreA(Vec4V_From_Vec3V(manifold.mContactPoints[b].mLocalPointA), &contacts[b].mLocalPointA.x);
+ V4StoreA(Vec4V_From_Vec3V(manifold.mContactPoints[b].mLocalPointB), &contacts[b].mLocalPointB.x);
+ V4StoreA(manifold.mContactPoints[b].mLocalNormalPen, &contacts[b].mLocalNormal.x);
+ //Note - this must be written last because we just wrote mLocalPointA to this memory so need to make sure
+ //that face index is written after that.
+ contacts[b].mFaceIndex = manifold.mContactPoints[b].mFaceIndex;
+ }
+ buff += sizeof(CachedMeshPersistentContact) * manifold.mNumContacts;
+ }
+}
+
+#define PX_CP_TO_PCP(contactPoint) (reinterpret_cast<PersistentContact*>(contactPoint)) //this is used in the normal pcm contact gen
+#define PX_CP_TO_MPCP(contactPoint) (reinterpret_cast<MeshPersistentContact*>(contactPoint))//this is used in the mesh pcm contact gen
+
+}//Gu
+}//physx
+
+#endif