RavEngine
Loading...
Searching...
No Matches
GuPersistentContactManifold.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef Gu_PERSISTENTCONTACTMANIFOLD_H
30#define Gu_PERSISTENTCONTACTMANIFOLD_H
31
32#include "common/PxPhysXCommonConfig.h"
33#include "foundation/PxUnionCast.h"
34#include "foundation/PxMemory.h"
35#include "foundation/PxVecTransform.h"
36
37#define PCM_LOW_LEVEL_DEBUG 0
38
39namespace physx
40{
41
42#define VISUALIZE_PERSISTENT_CONTACT 1
43//This is for pritimives vs primitives
44#define GU_MANIFOLD_CACHE_SIZE 4
45//These are for pritimives vs mesh
46#define GU_SINGLE_MANIFOLD_SINGLE_POLYGONE_CACHE_SIZE 5
47#define GU_SINGLE_MANIFOLD_CACHE_SIZE 6
48#define GU_SPHERE_MANIFOLD_CACHE_SIZE 1
49#define GU_CAPSULE_MANIFOLD_CACHE_SIZE 3
50#define GU_MAX_MANIFOLD_SIZE 6
51#define GU_MESH_CONTACT_REDUCTION_THRESHOLD 16
52
53#define GU_MANIFOLD_INVALID_INDEX 0xffffffff
54
55
56//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.
57//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
58//recycling thresholds are proportionate to margin so it makes it less likely to discard previous contacts due to separation
59#define GU_PCM_MESH_MANIFOLD_EPSILON 0.05f
60
61class PxRenderOutput;
62class PxContactBuffer;
63
64namespace Gu
65{
66 struct GjkOutput;
67
68extern const PxF32 invalidateThresholds[5];
69extern const PxF32 invalidateQuatThresholds[5];
70extern const PxF32 invalidateThresholds2[3];
71extern const PxF32 invalidateQuatThresholds2[3];
72
73
74aos::Mat33V findRotationMatrixFromZAxis(const aos::Vec3VArg to);
75
76//This contact is used in the primitives vs primitives contact gen
78{
79public:
81 {
82 }
83
84 PersistentContact(aos::Vec3V _localPointA, aos::Vec3V _localPointB, aos::Vec4V _localNormalPen) :
85 mLocalPointA(_localPointA), mLocalPointB(_localPointB), mLocalNormalPen(_localNormalPen)
86 {
87
88 }
89
90 aos::Vec3V mLocalPointA;
91 aos::Vec3V mLocalPointB;
92 aos::Vec4V mLocalNormalPen; // the (x, y, z) is the local normal, and the w is the penetration depth
93};
94
95//This contact is used in the mesh contact gen to store an extra variable
97{
98public:
99 PxU32 mFaceIndex;
100};
101
102//This contact is used in the compress stream buffer(NpCacheStreamPair in the PxcNpThreadContext) to store the data we need
103PX_ALIGN_PREFIX(16)
105{
106public:
107 PxVec3 mLocalPointA; //16 byte aligned
108 PxU32 mFaceIndex; //face index
109 PxVec3 mLocalPointB; //16 byte aligned
110 PxU32 mPad; //pad
111 PxVec3 mLocalNormal; //16 byte aligned
112 PxReal mPen; //penetration
113}PX_ALIGN_SUFFIX(16);
114
115
116#if PX_VC
117 #pragma warning(push)
118 #pragma warning( disable : 4324 ) // Padding was added at the end of a structure because of a __declspec(align) value.
119#endif
120
121//This class is used to store the start and end index of the mesh persistent contacts in an array.
123{
124public:
126 {
127 mNextPatch = NULL;
128 mEndPatch = NULL;
129 mRoot = this;
130 mPatchMaxPen = aos::FMax();
131 }
132 aos::Vec3V mPatchNormal;
133 PCMContactPatch* mNextPatch;//store the next patch pointer in the patch list
134 PCMContactPatch* mEndPatch;//store the last patch pointer in the patch list
135 PCMContactPatch* mRoot;//if this is the start of the patch list which has very similar patch normal, the root will be itself
136 aos::FloatV mPatchMaxPen;//store the deepest penetration of the whole patch
137 PxU32 mStartIndex;//store the start index of the manifold contacts in the manifold contacts stream
138 PxU32 mEndIndex;//store the end index of the manifold contacts in the manifold contacts stream
139 PxU32 mTotalSize;//if this is the root, the total size will store the total number of manifold contacts in the whole patch list
140};
141
142#if PX_VC
143 #pragma warning(pop)
144#endif
145
146//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
147PX_ALIGN_PREFIX(16)
149{
150public:
151
152 PersistentContactManifold(PersistentContact* contactPointsBuff, PxU8 capacity): mNumContacts(0), mCapacity(capacity), mNumWarmStartPoints(0), mContactPoints(contactPointsBuff)
153 {
154 using namespace physx::aos;
155 mRelativeTransform.Invalidate();
156 mQuatA = QuatIdentity();
157 mQuatB = QuatIdentity();
158 }
159
160 PX_FORCE_INLINE PxU32 getNumContacts() const { return mNumContacts;}
161
162 PX_FORCE_INLINE bool isEmpty() { return mNumContacts==0; }
163
164 PX_FORCE_INLINE PersistentContact& getContactPoint(const PxU32 index)
165 {
166 PX_ASSERT(index < GU_MANIFOLD_CACHE_SIZE);
167 return mContactPoints[index];
168 }
169
170 PX_FORCE_INLINE aos::FloatV maxTransformdelta(const aos::PxTransformV& curTransform)
171 {
172 using namespace aos;
173 const Vec4V p0 = Vec4V_From_Vec3V(mRelativeTransform.p);
174 const Vec4V q0 = mRelativeTransform.q;
175 const Vec4V p1 = Vec4V_From_Vec3V(curTransform.p);
176 const Vec4V q1 = curTransform.q;
177
178 const Vec4V dp = V4Abs(V4Sub(p1, p0));
179 const Vec4V dq = V4Abs(V4Sub(q1, q0));
180
181 const Vec4V max0 = V4Max(dp, dq);
182
183 //need to work out max from a single vector...
184 return V4ExtractMax(max0);
185 }
186
187 PX_FORCE_INLINE aos::Vec4V maxTransformdelta2(const aos::PxTransformV& curTransform)
188 {
189 using namespace aos;
190 const Vec4V p0 = Vec4V_From_Vec3V(mRelativeTransform.p);
191 const Vec4V q0 = mRelativeTransform.q;
192 const Vec4V p1 = Vec4V_From_Vec3V(curTransform.p);
193 const Vec4V q1 = curTransform.q;
194
195 const Vec4V dp = V4Abs(V4Sub(p1, p0));
196 const Vec4V dq = V4Abs(V4Sub(q1, q0));
197
198 const Vec4V max0 = V4Max(dp, dq);
199
200 //need to work out max from a single vector...
201 return max0;
202 }
203
204 PX_FORCE_INLINE aos::FloatV maxTransformPositionDelta(const aos::Vec3V& curP)
205 {
206 using namespace aos;
207
208 const Vec3V deltaP = V3Sub(curP, mRelativeTransform.p);
209 const Vec4V delta = Vec4V_From_Vec3V(V3Abs(deltaP));
210 //need to work out max from a single vector...
211 return V4ExtractMax(delta);
212 }
213
214 PX_FORCE_INLINE aos::FloatV maxTransformQuatDelta(const aos::QuatV& curQ)
215 {
216 using namespace aos;
217
218 const Vec4V deltaQ = V4Sub(curQ, mRelativeTransform.q);
219 const Vec4V delta = V4Abs(deltaQ);
220 //need to work out max from a single vector...
221 return V4ExtractMax(delta);
222 }
223
224 PX_FORCE_INLINE void setRelativeTransform(const aos::PxTransformV& transform)
225 {
226 mRelativeTransform = transform;
227 }
228
229 PX_FORCE_INLINE void setRelativeTransform(const aos::PxTransformV& transform, const aos::QuatV quatA, const aos::QuatV quatB)
230 {
231 mRelativeTransform = transform;
232 mQuatA = quatA;
233 mQuatB = quatB;
234 }
235
236 //This is used for the box/convexhull vs box/convexhull contact gen to decide whether the relative movement of a pair of objects are
237 //small enough. In this case, we can skip the collision detection all together
238 PX_FORCE_INLINE PxU32 invalidate_BoxConvex(const aos::PxTransformV& curRTrans, const aos::QuatV& quatA, const aos::QuatV& quatB,
239 const aos::FloatVArg minMargin, const aos::FloatVArg radiusA, const aos::FloatVArg radiusB)
240 {
241 using namespace aos;
242 PX_ASSERT(mNumContacts <= GU_MANIFOLD_CACHE_SIZE);
243 const FloatV ratio = FLoad(invalidateThresholds[mNumContacts]);
244 const FloatV thresholdP = FMul(minMargin, ratio);
245 const FloatV deltaP = maxTransformPositionDelta(curRTrans.p);
246
247 const FloatV thresholdQ = FLoad(invalidateQuatThresholds[mNumContacts]);
248 const FloatV deltaQA = QuatDot(quatA, mQuatA);
249 const FloatV deltaQB = QuatDot(quatB, mQuatB);
250
251 const BoolV con0 = BOr(FIsGrtr(deltaP, thresholdP), BOr(FIsGrtr(thresholdQ, deltaQA), FIsGrtr(thresholdQ, deltaQB)));
252 PxU32 generateContacts = BAllEqTTTT(con0);
253 if (!generateContacts)
254 {
255
256 PxReal dqA, dqB;
257 FStore(deltaQA, &dqA);
258 FStore(deltaQB, &dqB);
259
260 const PxReal aRadian = dqA < 1.0f ? PxAcos(dqA) : 0.f;
261 const FloatV travelDistA = FMul(FLoad(aRadian), radiusA);
262
263 const PxReal bRadian = dqB < 1.0f ? PxAcos(dqB) : 0.f;
264 const FloatV travelDistB = FMul(FLoad(bRadian), radiusB);
265
266
267 const BoolV con = BOr(FIsGrtr(travelDistA, thresholdP), FIsGrtr(travelDistB, thresholdP));
268
269 generateContacts = BAllEqTTTT(con);
270 }
271
272 return generateContacts;
273 }
274
275 //This is used for the sphere/capsule vs other primitives contact gen to decide whether the relative movement of a pair of objects are
276 //small enough. In this case, we can skip the collision detection all together
277 PX_FORCE_INLINE PxU32 invalidate_SphereCapsule(const aos::PxTransformV& curRTrans, const aos::FloatVArg minMargin)
278 {
279 using namespace aos;
280 PX_ASSERT(mNumContacts <= 2);
281 const FloatV ratio = FLoad(invalidateThresholds2[mNumContacts]);
282
283 const FloatV thresholdP = FMul(minMargin, ratio);
284 const FloatV deltaP = maxTransformPositionDelta(curRTrans.p);
285
286 const FloatV thresholdQ = FLoad(invalidateQuatThresholds2[mNumContacts]);
287 const FloatV deltaQ = QuatDot(curRTrans.q, mRelativeTransform.q);
288 const BoolV con = BOr(FIsGrtr(deltaP, thresholdP), FIsGrtr(thresholdQ, deltaQ));
289
290 return BAllEqTTTT(con);
291 }
292
293 //This is used for plane contact gen to decide whether the relative movement of a pair of objects are small enough. In this case,
294 //we can skip the collision detection all together
295 PX_FORCE_INLINE PxU32 invalidate_PrimitivesPlane(const aos::PxTransformV& curRTrans, const aos::FloatVArg minMargin, const aos::FloatVArg ratio)
296 {
297 using namespace aos;
298 const FloatV thresholdP = FMul(minMargin, ratio);
299 const FloatV deltaP = maxTransformPositionDelta(curRTrans.p);
300
301 const FloatV thresholdQ = FLoad(0.99996f);//about 0.5 degree
302 const FloatV deltaQ = QuatDot(curRTrans.q, mRelativeTransform.q);
303 const BoolV con = BOr(FIsGrtr(deltaP, thresholdP), FIsGrtr(thresholdQ, deltaQ));
304
305 return BAllEqTTTT(con);
306 }
307
308 PX_FORCE_INLINE void removeContactPoint (PxU32 index)
309 {
310 mNumContacts--;
311 mContactPoints[index] = mContactPoints[mNumContacts];
312 }
313
314 bool validContactDistance(const PersistentContact& pt, const aos::FloatVArg breakingThreshold) const
315 {
316 using namespace aos;
317 const FloatV dist = V4GetW(pt.mLocalNormalPen);
318 return FAllGrtr(breakingThreshold, dist) != 0;
319 }
320
321 PX_FORCE_INLINE void clearManifold()
322 {
323 mNumWarmStartPoints = 0;
324 mNumContacts = 0;
325 mRelativeTransform.Invalidate();
326 }
327
328 PX_FORCE_INLINE void initialize()
329 {
330 clearManifold();
331 }
332
333 //This function is used to replace the existing contact with the newly created contact if their distance are within some threshold
334 bool replaceManifoldPoint(const aos::Vec3VArg localPointA, const aos::Vec3VArg localPointB, const aos::Vec4VArg localNormalPen, const aos::FloatVArg replaceBreakingThreshold);
335
336 //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
337 PxU32 addManifoldPoint( const aos::Vec3VArg localPointA, const aos::Vec3VArg localPointB, const aos::Vec4VArg localNormalAPen, const aos::FloatVArg replaceBreakingThreshold);
338 //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
339 PxU32 addManifoldPoint2( const aos::Vec3VArg localPointA, const aos::Vec3VArg localPointB, const aos::Vec4VArg localNormalAPen, const aos::FloatVArg replaceBreakingThreshold);//max two points of contacts
340 //This function is used in box-plane contact gen to add the plane contacts to the manifold
341 void addBatchManifoldContactsCluster( const PersistentContact* manifoldPoints, const PxU32 numPoints);
342
343 //This function is used in the capsule full manifold contact genenation(maximum 2 points).
344 void addBatchManifoldContacts2( const PersistentContact* manifoldPoints, const PxU32 numPoints);//max two points of contacts
345
346 //This function is used in the box/convexhull full manifold contact generation(maximum 4 points).
347 void addBatchManifoldContacts(const PersistentContact* manifoldPoints, const PxU32 numPoints, const PxReal toleranceLength);
348 //This function is using the cluster algorithm to reduce contacts
349 void reduceBatchContactsCluster(const PersistentContact* manifoldPoints, const PxU32 numPoints);
350 //This function is called by addBatchManifoldContacts2 to reduce the manifold contacts to 2 points;
351 void reduceBatchContacts2(const PersistentContact* manifoldPoints, const PxU32 numPoints);
352 //This function is called by addBatchManifoldContacts to reduce the manifold contacts to 4 points
353 void reduceBatchContacts(const PersistentContact* manifoldPoints, const PxU32 numPoints, const PxReal toleranceLength);
354
355
356 //This function is used for incremental manifold contact reduction for box/convexhull
357 PxU32 reduceContactsForPCM(const aos::Vec3VArg localPointA, const aos::Vec3VArg localPointB, const aos::Vec4VArg localNormalPen);
358 //This function is used for incremental manifold contact reduction for capsule
359 PxU32 reduceContactSegment(const aos::Vec3VArg localPointA, const aos::Vec3VArg localPointB, const aos::Vec4VArg localNormalPen);
360
361
362 /*
363 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,
364 we will keep the contacts; Otherwise, we will remove the contacts.
365 */
366 void refreshContactPoints(const aos::PxMatTransformV& relTra, const aos::FloatVArg projectBreakingThreshold, const aos::FloatVArg contactOffset);
367 //This function is just used in boxbox contact gen for fast transform
368 void addManifoldContactsToContactBuffer(PxContactBuffer& contactBuffer, const aos::Vec3VArg normal, const aos::PxMatTransformV& transf1);
369 //This function is for adding box/convexhull manifold contacts to the contact buffer
370 void addManifoldContactsToContactBuffer(PxContactBuffer& contactBuffer, const aos::Vec3VArg normal, const aos::PxTransformV& transf1, const aos::FloatVArg contactOffset);
371 //This function is for adding sphere/capsule manifold contacts to the contact buffer
372 void addManifoldContactsToContactBuffer(PxContactBuffer& contactBuffer, const aos::Vec3VArg normal, const aos::Vec3VArg projectionNormal, const aos::PxTransformV& transf0, const aos::FloatVArg radius, const aos::FloatVArg contactOffset);
373
374 //get the average normal in the manifold in world space
375 aos::Vec3V getWorldNormal(const aos::PxTransformV& trB);
376 //get the average normal in the manifold in local B object space
377 aos::Vec3V getLocalNormal();
378
379 void recordWarmStart(PxU8* aIndices, PxU8* bIndices, PxU8& nbWarmStartPoints);
380 void setWarmStart(const PxU8* aIndices, const PxU8* bIndices, const PxU8 nbWarmStartPoints);
381 void drawManifold(PxRenderOutput& out, const aos::PxTransformV& trA, const aos::PxTransformV& trB);
382 void drawManifold(PxRenderOutput& out, const aos::PxTransformV& trA, const aos::PxTransformV& trB, const aos::FloatVArg radius);
383 void drawManifold(const PersistentContact& m, PxRenderOutput& out, const aos::PxTransformV& trA, const aos::PxTransformV& trB);
384 static void drawPoint(PxRenderOutput& out, const aos::Vec3VArg p, const PxF32 size, const PxU32 color = 0x0000ff00);
385 static void drawLine(PxRenderOutput& out, const aos::Vec3VArg p0, const aos::Vec3VArg p1, const PxU32 color = 0xff00ffff);
386 static void drawTriangle(PxRenderOutput& out, const aos::Vec3VArg p0, const aos::Vec3VArg p1, const aos::Vec3VArg p2, const PxU32 color = 0xffff0000);
387 static void drawTetrahedron(PxRenderOutput& out, const aos::Vec3VArg p0, const aos::Vec3VArg p1, const aos::Vec3VArg p2, const aos::Vec3VArg p3, const PxU32 color = 0xffff0000);
388 static void drawPolygon( PxRenderOutput& out, const aos::PxTransformV& transform, aos::Vec3V* points, const PxU32 numVerts, const PxU32 color = 0xff00ffff);
389 static void drawPolygon( PxRenderOutput& out, const aos::PxMatTransformV& transform, aos::Vec3V* points, const PxU32 numVerts, const PxU32 color = 0xff00ffff);
390
391 aos::PxTransformV mRelativeTransform;//aToB
392 aos::QuatV mQuatA;
393 aos::QuatV mQuatB;
394 PxU8 mNumContacts;
395 PxU8 mCapacity;
396 PxU8 mNumWarmStartPoints;
397 PxU8 mAIndice[4];
398 PxU8 mBIndice[4];
399 PersistentContact* mContactPoints;
400} PX_ALIGN_SUFFIX(16);
401
402PX_ALIGN_PREFIX(16)
404{
405public:
406 LargePersistentContactManifold() : PersistentContactManifold(mContactPointsBuff, GU_MANIFOLD_CACHE_SIZE)
407 {
408 }
409
410 PersistentContact mContactPointsBuff[GU_MANIFOLD_CACHE_SIZE];
411}PX_ALIGN_SUFFIX(16);
412
413PX_ALIGN_PREFIX(16)
415{
416public:
417 SpherePersistentContactManifold() : PersistentContactManifold(mContactPointsBuff, GU_SPHERE_MANIFOLD_CACHE_SIZE)
418 {
419 }
420
421 PersistentContact mContactPointsBuff[GU_SPHERE_MANIFOLD_CACHE_SIZE];
422}PX_ALIGN_SUFFIX(16);
423
424PX_ALIGN_PREFIX(16)
426{
427public:
428
429 SinglePersistentContactManifold(): mNumContacts(0)
430 {
431 }
432
433 PX_FORCE_INLINE PxU32 getNumContacts() const { return mNumContacts;}
434
435 PX_FORCE_INLINE bool isEmpty() { return mNumContacts==0; }
436
437 PX_FORCE_INLINE MeshPersistentContact& getContactPoint(const PxU32 index)
438 {
439 PX_ASSERT(index < GU_SINGLE_MANIFOLD_CACHE_SIZE);
440 return mContactPoints[index];
441 }
442
443 PX_FORCE_INLINE void removeContactPoint (PxU32 index)
444 {
445 mNumContacts--;
446 mContactPoints[index] = mContactPoints[mNumContacts];
447 }
448
449 PX_FORCE_INLINE void clearManifold()
450 {
451 mNumContacts = 0;
452 }
453
454 PX_FORCE_INLINE void initialize()
455 {
456 clearManifold();
457 }
458
459
460 PX_FORCE_INLINE aos::Vec3V getWorldNormal(const aos::PxTransformV& trB)
461 {
462 using namespace aos;
463 Vec4V nPen = mContactPoints[0].mLocalNormalPen;
464 for(PxU32 i =1; i < mNumContacts; ++i)
465 {
466 nPen = V4Add(nPen, mContactPoints[i].mLocalNormalPen);
467 }
468
469 const Vec3V n = Vec3V_From_Vec4V(nPen);
470 return V3Normalize(trB.rotate(n));
471 }
472
473 PX_FORCE_INLINE aos::Vec3V getLocalNormal()
474 {
475 using namespace aos;
476 Vec4V nPen = mContactPoints[0].mLocalNormalPen;
477 for(PxU32 i =1; i < mNumContacts; ++i)
478 {
479 nPen = V4Add(nPen, mContactPoints[i].mLocalNormalPen);
480 }
481 return V3Normalize(Vec3V_From_Vec4V(nPen));
482 }
483
484 //This function reduces the manifold contact list in a patch for box/convexhull vs mesh
485 aos::FloatV reduceBatchContactsConvex(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch);
486 //This function reduces the manifold contact list in a patch for sphere vs mesh
487 aos::FloatV reduceBatchContactsSphere(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch);
488 //This function reduces the manifold contact list in a pathc for capsuel vs mesh
489 aos::FloatV reduceBatchContactsCapsule(const MeshPersistentContact* manifoldContactExt, const PxU32 numContacts, PCMContactPatch& patch);
490
491 //This function adds the manifold contact list in a patch for box/convexhull vs mesh
492 aos::FloatV addBatchManifoldContactsConvex(const MeshPersistentContact* manifoldContact, const PxU32 numContacts, PCMContactPatch& patch, const aos::FloatVArg replaceBreakingThreshold);
493 //This function adds the manifold contact list in a patch for sphere vs mesh
494 aos::FloatV addBatchManifoldContactsSphere(const MeshPersistentContact* manifoldContact, const PxU32 numContacts, PCMContactPatch& patch, const aos::FloatVArg replaceBreakingThreshold);
495 //This function adds the manifold contact list in a patch for capsule vs mesh
496 aos::FloatV addBatchManifoldContactsCapsule(const MeshPersistentContact* manifoldContact, const PxU32 numContacts, PCMContactPatch& patch, const aos::FloatVArg replaceBreakingThreshold);
497
498 //This is used for in the addContactsToPatch for convex mesh contact gen.
499 static PxU32 reduceContacts(MeshPersistentContact* manifoldContactExt, PxU32 numContacts);
500
501 //This function is to recalculate the contacts based on the relative transform between a pair of objects
502 aos::FloatV refreshContactPoints(const aos::PxMatTransformV& relTra, const aos::FloatVArg projectBreakingThreshold, const aos::FloatVArg contactOffset);
503
504 void drawManifold(PxRenderOutput& out, const aos::PxTransformV& trA, const aos::PxTransformV& trB);
505
506 MeshPersistentContact mContactPoints[GU_SINGLE_MANIFOLD_CACHE_SIZE];//384 bytes
507 PxU32 mNumContacts;//400 bytes
508
509} PX_ALIGN_SUFFIX(16);
510
511//This is a structure used to cache a multi-persistent-manifold in the cache stream
513{
514 aos::PxTransformV mRelativeTransform;//aToB
515 PxU32 mNumManifolds;
516 PxU32 pad[3];
517};
518
520{
521 PxU32 mNumContacts;
522 PxU32 pad[3];
523};
524
525#if PX_VC
526#pragma warning(push)
527#pragma warning( disable : 4251 ) // class needs to have dll-interface to be used by clients of class
528#endif
529
530PX_ALIGN_PREFIX(16)
531class PX_PHYSX_COMMON_API MultiplePersistentContactManifold
532{
533public:
534 MultiplePersistentContactManifold():mNumManifolds(0), mNumTotalContacts(0)
535 {
536 mRelativeTransform.Invalidate();
537 }
538
539 PX_FORCE_INLINE void setRelativeTransform(const aos::PxTransformV& transform)
540 {
541 mRelativeTransform = transform;
542 }
543
544 PX_FORCE_INLINE aos::FloatV maxTransformPositionDelta(const aos::Vec3V& curP)
545 {
546 using namespace aos;
547
548 const Vec3V deltaP = V3Sub(curP, mRelativeTransform.p);
549 const Vec4V delta = Vec4V_From_Vec3V(V3Abs(deltaP));
550 //need to work out max from a single vector...
551 return V4ExtractMax(delta);
552 }
553
554 PX_FORCE_INLINE aos::FloatV maxTransformQuatDelta(const aos::QuatV& curQ)
555 {
556 using namespace aos;
557
558 const Vec4V deltaQ = V4Sub(curQ, mRelativeTransform.q);
559 const Vec4V delta = V4Abs(deltaQ);
560 //need to work out max from a single vector...
561 return V4ExtractMax(delta);
562 }
563
564 PX_FORCE_INLINE PxU32 invalidate(const aos::PxTransformV& curRTrans, const aos::FloatVArg minMargin, const aos::FloatVArg ratio)
565 {
566 using namespace aos;
567
568 const FloatV thresholdP = FMul(minMargin, ratio);
569 const FloatV deltaP = maxTransformPositionDelta(curRTrans.p);
570 const FloatV thresholdQ = FLoad(0.9998f);//about 1 degree
571 const FloatV deltaQ = QuatDot(curRTrans.q, mRelativeTransform.q);
572 const BoolV con = BOr(FIsGrtr(deltaP, thresholdP), FIsGrtr(thresholdQ, deltaQ));
573
574 return BAllEqTTTT(con);
575 }
576
577 PX_FORCE_INLINE PxU32 invalidate(const aos::PxTransformV& curRTrans, const aos::FloatVArg minMargin)
578 {
579 using namespace aos;
580 return invalidate(curRTrans, minMargin, FLoad(0.2f));
581 }
582
583 /*
584 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.
585 */
586 PX_FORCE_INLINE void refineContactPatchConnective(PCMContactPatch** contactPatch, PxU32 numContactPatch, MeshPersistentContact* manifoldContacts, const aos::FloatVArg acceptanceEpsilon)
587 {
588 PX_UNUSED(manifoldContacts);
589
590 using namespace aos;
591
592 //work out the contact patch connectivity, the patchNormal should be in the local space of mesh
593 for(PxU32 i=0; i<numContactPatch; ++i)
594 {
595 PCMContactPatch* patch = contactPatch[i];
596 patch->mRoot = patch;
597 patch->mEndPatch = patch;
598 patch->mTotalSize = patch->mEndIndex - patch->mStartIndex;
599 patch->mNextPatch = NULL;
600
601 for(PxU32 j=i; j>0; --j)
602 {
603 PCMContactPatch* other = contactPatch[j-1];
604 const FloatV d = V3Dot(patch->mPatchNormal, other->mRoot->mPatchNormal);
605 if(FAllGrtrOrEq(d, acceptanceEpsilon))//less than 5 degree
606 {
607
608 other->mNextPatch = patch;
609 other->mRoot->mEndPatch = patch;
610 patch->mRoot = other->mRoot;
611 other->mRoot->mTotalSize += patch->mEndIndex - patch->mStartIndex;
612 break;
613 }
614 }
615 }
616 }
617
618
619 /*
620 This function uses to reduce the manifold contacts which are in different connected patchs but are within replace breaking threshold
621 */
622 PX_FORCE_INLINE PxU32 reduceManifoldContactsInDifferentPatches(PCMContactPatch** contactPatch, PxU32 numContactPatch, MeshPersistentContact* manifoldContacts, PxU32 numContacts, const aos::FloatVArg sqReplaceBreaking)
623 {
624 using namespace aos;
625
626 for(PxU32 i=0; i<numContactPatch; ++i)
627 {
628 PCMContactPatch* currentPatch = contactPatch[i];
629 //this make sure the patch is the root before we do the contact reduction, otherwise, we will do duplicate work
630 if(currentPatch->mRoot == currentPatch)
631 {
632 while(currentPatch)
633 {
634 PCMContactPatch* nextPatch = currentPatch->mNextPatch;
635 if(nextPatch)
636 {
637 for(PxU32 k = currentPatch->mStartIndex; k<currentPatch->mEndIndex; ++k)
638 {
639 for(PxU32 l = nextPatch->mStartIndex; l < nextPatch->mEndIndex; ++l)
640 {
641 Vec3V dif = V3Sub(manifoldContacts[l].mLocalPointB, manifoldContacts[k].mLocalPointB);
642 FloatV d = V3Dot(dif, dif);
643 if(FAllGrtr(sqReplaceBreaking, d))
644 {
645 //if two manifold contacts are within threshold, we will get rid of the manifold contacts in the other contact patch
646 manifoldContacts[l] = manifoldContacts[nextPatch->mEndIndex-1];
647 nextPatch->mEndIndex--;
648 numContacts--;
649 l--;
650 }
651 }
652 }
653 }
654 currentPatch = nextPatch;
655 }
656 }
657 }
658
659 return numContacts;
660 }
661
662
663 /*
664 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
665 */
666 PX_FORCE_INLINE void refreshManifold(const aos::PxMatTransformV& relTra, const aos::FloatVArg projectBreakingThreshold, const aos::FloatVArg contactDist)
667 {
668 using namespace aos;
669
670 //refresh manifold contacts
671 for(PxU32 i=0; i < mNumManifolds; ++i)
672 {
673 PxU8 ind = mManifoldIndices[i];
674 PX_ASSERT(mManifoldIndices[i] < GU_MAX_MANIFOLD_SIZE);
675 PxU32 nextInd = PxMin(i, mNumManifolds-2u)+1;
676 PxPrefetchLine(&mManifolds[mManifoldIndices[nextInd]]);
677 PxPrefetchLine(&mManifolds[mManifoldIndices[nextInd]],128);
678 PxPrefetchLine(&mManifolds[mManifoldIndices[nextInd]],256);
679 FloatV _maxPen = mManifolds[ind].refreshContactPoints(relTra, projectBreakingThreshold, contactDist);
680 if(mManifolds[ind].isEmpty())
681 {
682 //swap the index with the next manifolds
683 PxU8 index = mManifoldIndices[--mNumManifolds];
684 mManifoldIndices[mNumManifolds] = ind;
685 mManifoldIndices[i] = index;
686 i--;
687 }
688 else
689 {
690 FStore(_maxPen, &mMaxPen[ind]);
691 }
692 }
693 }
694
695
696 PX_FORCE_INLINE void initialize()
697 {
698 mNumManifolds = 0;
699 mNumTotalContacts = 0;
700 mRelativeTransform.Invalidate();
701 for(PxU8 i=0; i<GU_MAX_MANIFOLD_SIZE; ++i)
702 {
703 mManifolds[i].initialize();
704 mManifoldIndices[i] = i;
705 }
706 }
707
708 PX_FORCE_INLINE void clearManifold()
709 {
710 for(PxU8 i=0; i<mNumManifolds; ++i)
711 {
712 mManifolds[i].clearManifold();
713 }
714 mNumManifolds = 0;
715 mNumTotalContacts = 0;
716 mRelativeTransform.Invalidate();
717 }
718
719 PX_FORCE_INLINE SinglePersistentContactManifold* getManifold(const PxU32 index)
720 {
721 PX_ASSERT(index < GU_MAX_MANIFOLD_SIZE);
722 return &mManifolds[mManifoldIndices[index]];
723 }
724
726 {
727 if(mNumManifolds < GU_MAX_MANIFOLD_SIZE)
728 return &mManifolds[mManifoldIndices[mNumManifolds]];
729 return NULL;
730 }
731
732 //This function adds the manifold contacts with different patches into the corresponding single persistent contact manifold
733 void addManifoldContactPoints(MeshPersistentContact* manifoldContact, PxU32 numManifoldContacts, PCMContactPatch** contactPatch, const PxU32 numPatch,
734 const aos::FloatVArg sqReplaceBreakingThreshold, const aos::FloatVArg acceptanceEpsilon, PxU8 maxContactsPerManifold);
735 //This function adds the box/convexhull manifold contacts to the contact buffer
736 bool addManifoldContactsToContactBuffer(PxContactBuffer& contactBuffer, const aos::PxTransformV& transf1);
737 //This function adds the sphere/capsule manifold contacts to the contact buffer
738 bool addManifoldContactsToContactBuffer(PxContactBuffer& contactBuffer, const aos::PxTransformV& trA, const aos::PxTransformV& trB, const aos::FloatVArg radius);
739 void drawManifold(PxRenderOutput& out, const aos::PxTransformV& trA, const aos::PxTransformV& trB);
740
741 //Code to load from a buffer and store to a buffer.
742 void fromBuffer(PxU8* PX_RESTRICT buffer);
743 void toBuffer(PxU8* PX_RESTRICT buffer);
744
745 static void drawLine(PxRenderOutput& out, const aos::Vec3VArg p0, const aos::Vec3VArg p1, const PxU32 color = 0xff00ffff);
746 static void drawLine(PxRenderOutput& out, const PxVec3 p0, const PxVec3 p1, const PxU32 color = 0xff00ffff);
747 static void drawPoint(PxRenderOutput& out, const aos::Vec3VArg p, const PxF32 size, const PxU32 color = 0x00ff0000);
748 static void drawPolygon( PxRenderOutput& out, const aos::PxTransformV& transform, aos::Vec3V* points, const PxU32 numVerts, const PxU32 color = 0xff00ffff);
749
750 aos::PxTransformV mRelativeTransform;//aToB
751 PxF32 mMaxPen[GU_MAX_MANIFOLD_SIZE];
752 PxU8 mManifoldIndices[GU_MAX_MANIFOLD_SIZE];
753 PxU8 mNumManifolds;
754 PxU8 mNumTotalContacts;
755 SinglePersistentContactManifold mManifolds[GU_MAX_MANIFOLD_SIZE];
756
757
758} PX_ALIGN_SUFFIX(16);
759
760#if PX_VC
761#pragma warning(pop)
762#endif
763
764/*
765 This function calculates the average normal in the manifold in world space
766*/
767PX_FORCE_INLINE aos::Vec3V PersistentContactManifold::getWorldNormal(const aos::PxTransformV& trB)
768{
769 using namespace aos;
770
771 Vec4V nPen = mContactPoints[0].mLocalNormalPen;
772 for(PxU32 i =1; i < mNumContacts; ++i)
773 {
774 nPen = V4Add(nPen, mContactPoints[i].mLocalNormalPen);
775 }
776
777 const Vec3V n = Vec3V_From_Vec4V(nPen);
778 const FloatV sqLength = V3Dot(n, n);
779 const Vec3V nn = V3Sel(FIsGrtr(sqLength, FEps()), n, Vec3V_From_Vec4V(mContactPoints[0].mLocalNormalPen));
780 return V3Normalize(trB.rotate(nn));
781}
782
783/*
784 This function calculates the average normal in the manifold in local B space
785*/
786PX_FORCE_INLINE aos::Vec3V PersistentContactManifold::getLocalNormal()
787{
788 using namespace aos;
789
790 Vec4V nPen = mContactPoints[0].mLocalNormalPen;
791 for(PxU32 i =1; i < mNumContacts; ++i)
792 {
793 nPen = V4Add(nPen, mContactPoints[i].mLocalNormalPen);
794 }
795 return V3Normalize(Vec3V_From_Vec4V(nPen));
796}
797
798/*
799 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,
800 we will keep the contacts; Otherwise, we will remove the contacts.
801*/
802PX_FORCE_INLINE void PersistentContactManifold::refreshContactPoints(const aos::PxMatTransformV& aToB, const aos::FloatVArg projectBreakingThreshold, const aos::FloatVArg /*contactOffset*/)
803{
804 using namespace aos;
805 const FloatV sqProjectBreakingThreshold = FMul(projectBreakingThreshold, projectBreakingThreshold);
806
807 // first refresh worldspace positions and distance
808 for (PxU32 i=mNumContacts; i > 0; --i)
809 {
810 PersistentContact& manifoldPoint = mContactPoints[i-1];
811 const Vec3V localAInB = aToB.transform( manifoldPoint.mLocalPointA ); // from a to b
812 const Vec3V localBInB = manifoldPoint.mLocalPointB;
813 const Vec3V v = V3Sub(localAInB, localBInB);
814
815 const Vec3V localNormal = Vec3V_From_Vec4V(manifoldPoint.mLocalNormalPen); // normal in b space
816 const FloatV dist= V3Dot(v, localNormal);
817
818 const Vec3V projectedPoint = V3NegScaleSub(localNormal, dist, localAInB);//manifoldPoint.worldPointA - manifoldPoint.worldPointB * manifoldPoint.m_distance1;
819 const Vec3V projectedDifference = V3Sub(localBInB, projectedPoint);
820
821 const FloatV distance2d = V3Dot(projectedDifference, projectedDifference);
822 //const BoolV con = BOr(FIsGrtr(dist, contactOffset), FIsGrtr(distance2d, sqProjectBreakingThreshold));
823 const BoolV con = FIsGrtr(distance2d, sqProjectBreakingThreshold);
824 if(BAllEqTTTT(con))
825 {
826 removeContactPoint(i-1);
827 }
828 else
829 {
830 manifoldPoint.mLocalNormalPen = V4SetW(Vec4V_From_Vec3V(localNormal), dist);
831 }
832 }
833}
834
835/*
836 This function copies the mesh persistent contact from the multiple manifold to compress buffer(NpCacheStreamPair in the PxcNpThreadContext)
837*/
838PX_INLINE void MultiplePersistentContactManifold::toBuffer(PxU8* PX_RESTRICT buffer)
839{
840 using namespace aos;
841 PxU8* buff = buffer;
842
843 PX_ASSERT(((uintptr_t(buff)) & 0xF) == 0);
845 buff += sizeof(MultiPersistentManifoldHeader);
846
847 PX_ASSERT(mNumManifolds <= GU_MAX_MANIFOLD_SIZE);
848 header->mNumManifolds = mNumManifolds;
849 header->mRelativeTransform = mRelativeTransform;
850
851 for(PxU32 a = 0; a < mNumManifolds; ++a)
852 {
853 SingleManifoldHeader* manHeader = reinterpret_cast<SingleManifoldHeader*>(buff);
854 buff += sizeof(SingleManifoldHeader);
855 SinglePersistentContactManifold& manifold = *getManifold(a);
856 manHeader->mNumContacts = manifold.mNumContacts;
857 PX_ASSERT((uintptr_t(buff) & 0xf) == 0);
858 CachedMeshPersistentContact* contacts = reinterpret_cast<CachedMeshPersistentContact*>(buff);
859 //convert the mesh persistent contact to cached mesh persistent contact to save 16 byte memory per contact
860 for(PxU32 b = 0; b<manifold.mNumContacts; ++b)
861 {
862 V4StoreA(Vec4V_From_Vec3V(manifold.mContactPoints[b].mLocalPointA), &contacts[b].mLocalPointA.x);
863 V4StoreA(Vec4V_From_Vec3V(manifold.mContactPoints[b].mLocalPointB), &contacts[b].mLocalPointB.x);
864 V4StoreA(manifold.mContactPoints[b].mLocalNormalPen, &contacts[b].mLocalNormal.x);
865 //Note - this must be written last because we just wrote mLocalPointA to this memory so need to make sure
866 //that face index is written after that.
867 contacts[b].mFaceIndex = manifold.mContactPoints[b].mFaceIndex;
868 }
869 buff += sizeof(CachedMeshPersistentContact) * manifold.mNumContacts;
870 }
871}
872
873#define PX_CP_TO_PCP(contactPoint) (reinterpret_cast<PersistentContact*>(contactPoint)) //this is used in the normal pcm contact gen
874#define PX_CP_TO_MPCP(contactPoint) (reinterpret_cast<MeshPersistentContact*>(contactPoint))//this is used in the mesh pcm contact gen
875
876void addManifoldPoint(PersistentContact* manifoldContacts, PersistentContactManifold& manifold, GjkOutput& output,
877 const aos::PxMatTransformV& aToB, const aos::FloatV replaceBreakingThreshold);
878
879}//Gu
880}//physx
881
882#endif
Definition GuPersistentContactManifold.h:105
Definition GuPersistentContactManifold.h:404
Definition GuPersistentContactManifold.h:97
Definition GuPersistentContactManifold.h:532
Definition GuPersistentContactManifold.h:149
Definition GuPersistentContactManifold.h:78
Definition GuPersistentContactManifold.h:426
Definition GuPersistentContactManifold.h:415
Definition PxContactBuffer.h:42
Definition PxRenderOutput.h:50
3 Element vector class.
Definition PxVec3.h:50
Definition PxVecTransform.h:200
Definition PxVecTransform.h:43
#define PX_RESTRICT
Definition PxPreprocessor.h:355
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
#define PX_INLINE
Definition PxPreprocessor.h:320
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_FORCE_INLINE void PxPrefetchLine(const void *ptr, uint32_t offset=0)
Definition PxUnixIntrinsics.h:83
PX_CUDA_CALLABLE PX_FORCE_INLINE float PxAcos(float f)
Arccosine. Returns angle between 0 and PI in radians Unit: Radians.
Definition PxMath.h:262
PX_CUDA_CALLABLE PX_FORCE_INLINE T PxMin(T a, T b)
The return value is the lesser of the two specified values.
Definition PxMath.h:88
Definition GuGJKUtil.h:56
Definition GuPersistentContactManifold.h:513
Definition GuPersistentContactManifold.h:123
Definition GuPersistentContactManifold.h:520
Definition PxVecMathAoSScalar.h:90
Definition PxVecMathAoSScalar.h:52
Definition PxVecMathAoSScalar.h:77
Definition PxVecMathAoSScalar.h:65