RavEngine
Loading...
Searching...
No Matches
DyContactReduction.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 DY_CONTACT_REDUCTION_H
30#define DY_CONTACT_REDUCTION_H
31
32#include "geomutils/PxContactPoint.h"
33#include "PxsMaterialManager.h"
34
35namespace physx
36{
37
38
39namespace Dy
40{
41
42//KS - might be OK with 4 but 5 guarantees the deepest + 4 contacts that contribute to largest surface area
43#define CONTACT_REDUCTION_MAX_CONTACTS 6
44#define CONTACT_REDUCTION_MAX_PATCHES 32
45#define PXS_NORMAL_TOLERANCE 0.995f
46#define PXS_SEPARATION_TOLERANCE 0.001f
47
48
49 //A patch contains a normal, pair of material indices and a list of indices. These indices are
50 //used to index into the PxContact array that's passed by the user
52 {
53 PxU32 numContactPoints;
54 PxU32 contactPoints[CONTACT_REDUCTION_MAX_CONTACTS];
55 };
56
58 {
59 PxVec3 rootNormal;
60 ContactPatch* mNextPatch;
61 PxReal maxPenetration;
62 PxU16 startIndex;
63 PxU16 stride;
64 PxU16 rootIndex;
65 PxU16 index;
66 };
67
69 {
70 bool operator()(const ContactPatch* idx1, const ContactPatch* idx2) const
71 {
72 return idx1->maxPenetration < idx2->maxPenetration;
73 }
74 };
75
76
77
78 template <PxU32 MaxPatches>
80 {
81 public:
82 ReducedContactPatch mPatches[MaxPatches];
83 PxU32 mNumPatches;
84 ContactPatch mIntermediatePatches[CONTACT_REDUCTION_MAX_PATCHES];
85 ContactPatch* mIntermediatePatchesPtrs[CONTACT_REDUCTION_MAX_PATCHES];
86 PxU32 mNumIntermediatePatches;
87 PxContactPoint* PX_RESTRICT mOriginalContacts;
88 PxsMaterialInfo* PX_RESTRICT mMaterialInfo;
89 PxU32 mNumOriginalContacts;
90
91 ContactReduction(PxContactPoint* PX_RESTRICT originalContacts, PxsMaterialInfo* PX_RESTRICT materialInfo, PxU32 numContacts) :
92 mNumPatches(0), mNumIntermediatePatches(0), mOriginalContacts(originalContacts), mMaterialInfo(materialInfo), mNumOriginalContacts(numContacts)
93 {
94 }
95
96 void reduceContacts()
97 {
98 //First pass, break up into contact patches, storing the start and stride of the patches
99 //We will need to have contact patches and then coallesce them
100 mIntermediatePatches[0].rootNormal = mOriginalContacts[0].normal;
101 mIntermediatePatches[0].mNextPatch = NULL;
102 mIntermediatePatches[0].startIndex = 0;
103 mIntermediatePatches[0].rootIndex = 0;
104 mIntermediatePatches[0].maxPenetration = mOriginalContacts[0].separation;
105 mIntermediatePatches[0].index = 0;
106 PxU16 numPatches = 1;
107 //PxU32 startIndex = 0;
108 PxU32 numUniquePatches = 1;
109 PxU16 m = 1;
110 for(; m < mNumOriginalContacts; ++m)
111 {
112 PxI32 index = -1;
113 for(PxU32 b = numPatches; b > 0; --b)
114 {
115 ContactPatch& patch = mIntermediatePatches[b-1];
116 if(mMaterialInfo[patch.startIndex].mMaterialIndex0 == mMaterialInfo[m].mMaterialIndex0 && mMaterialInfo[patch.startIndex].mMaterialIndex1 == mMaterialInfo[m].mMaterialIndex1 &&
117 patch.rootNormal.dot(mOriginalContacts[m].normal) >= PXS_NORMAL_TOLERANCE)
118 {
119 index = PxI32(b-1);
120 break;
121 }
122 }
123
124 if(index != numPatches - 1)
125 {
126 mIntermediatePatches[numPatches-1].stride = PxU16(m - mIntermediatePatches[numPatches - 1].startIndex);
127 //Create a new patch...
128 if(numPatches == CONTACT_REDUCTION_MAX_PATCHES)
129 {
130 break;
131 }
132 mIntermediatePatches[numPatches].startIndex = m;
133 mIntermediatePatches[numPatches].mNextPatch = NULL;
134 if(index == -1)
135 {
136 mIntermediatePatches[numPatches].rootIndex = numPatches;
137 mIntermediatePatches[numPatches].rootNormal = mOriginalContacts[m].normal;
138 mIntermediatePatches[numPatches].maxPenetration = mOriginalContacts[m].separation;
139 mIntermediatePatches[numPatches].index = numPatches;
140 ++numUniquePatches;
141 }
142 else
143 {
144 //Find last element in the link
145 PxU16 rootIndex = mIntermediatePatches[index].rootIndex;
146 mIntermediatePatches[index].mNextPatch = &mIntermediatePatches[numPatches];
147 mIntermediatePatches[numPatches].rootNormal = mIntermediatePatches[index].rootNormal;
148 mIntermediatePatches[rootIndex].maxPenetration = mIntermediatePatches[numPatches].maxPenetration = PxMin(mIntermediatePatches[rootIndex].maxPenetration, mOriginalContacts[m].separation);
149 mIntermediatePatches[numPatches].rootIndex = rootIndex;
150 mIntermediatePatches[numPatches].index = numPatches;
151 }
152 ++numPatches;
153 }
154 }
155 mIntermediatePatches[numPatches-1].stride = PxU16(m - mIntermediatePatches[numPatches-1].startIndex);
156
157 //OK, we have a list of contact patches so that we can start contact reduction per-patch
158
159 //OK, now we can go and reduce the contacts on a per-patch basis...
160
161 for(PxU32 a = 0; a < numPatches; ++a)
162 {
163 mIntermediatePatchesPtrs[a] = &mIntermediatePatches[a];
164 }
165
166
168 PxSort(mIntermediatePatchesPtrs, numPatches, predicate);
169
170 PxU32 numReducedPatches = 0;
171 for(PxU32 a = 0; a < numPatches; ++a)
172 {
173 if(mIntermediatePatchesPtrs[a]->rootIndex == mIntermediatePatchesPtrs[a]->index)
174 {
175 //Reduce this patch...
176 if(numReducedPatches == MaxPatches)
177 break;
178
179 ReducedContactPatch& reducedPatch = mPatches[numReducedPatches++];
180 //OK, now we need to work out if we have to reduce patches...
181 PxU32 contactCount = 0;
182 {
183 ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a];
184
185 while(tmpPatch)
186 {
187 contactCount += tmpPatch->stride;
188 tmpPatch = tmpPatch->mNextPatch;
189 }
190 }
191
192 if(contactCount <= CONTACT_REDUCTION_MAX_CONTACTS)
193 {
194 //Just add the contacts...
195 ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a];
196
197 PxU32 ind = 0;
198 while(tmpPatch)
199 {
200 for(PxU32 b = 0; b < tmpPatch->stride; ++b)
201 {
202 reducedPatch.contactPoints[ind++] = tmpPatch->startIndex + b;
203 }
204 tmpPatch = tmpPatch->mNextPatch;
205 }
206 reducedPatch.numContactPoints = contactCount;
207 }
208 else
209 {
210 //Iterate through and find the most extreme point
211
212
213 PxU32 ind = 0;
214
215 {
216 PxReal dist = 0.f;
217 ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a];
218 while(tmpPatch)
219 {
220 for(PxU32 b = 0; b < tmpPatch->stride; ++b)
221 {
222 PxReal magSq = mOriginalContacts[tmpPatch->startIndex + b].point.magnitudeSquared();
223 if(dist < magSq)
224 {
225 ind = tmpPatch->startIndex + b;
226 dist = magSq;
227 }
228 }
229 tmpPatch = tmpPatch->mNextPatch;
230 }
231 }
232 reducedPatch.contactPoints[0] = ind;
233 const PxVec3 p0 = mOriginalContacts[ind].point;
234
235 //Now find the point farthest from this point...
236 {
237 PxReal maxDist = 0.f;
238 ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a];
239 while(tmpPatch)
240 {
241 for(PxU32 b = 0; b < tmpPatch->stride; ++b)
242 {
243 PxReal magSq = (p0 - mOriginalContacts[tmpPatch->startIndex + b].point).magnitudeSquared();
244 if(magSq > maxDist)
245 {
246 ind = tmpPatch->startIndex + b;
247 maxDist = magSq;
248 }
249 }
250 tmpPatch = tmpPatch->mNextPatch;
251 }
252 }
253 reducedPatch.contactPoints[1] = ind;
254 const PxVec3 p1 = mOriginalContacts[ind].point;
255
256 //Now find the point farthest from the segment
257
258 PxVec3 n = (p0 - p1).cross(mIntermediatePatchesPtrs[a]->rootNormal);
259
260 //PxReal tVal = 0.f;
261 {
262 PxReal maxDist = 0.f;
263 //PxReal tmpTVal;
264
265 ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a];
266 while(tmpPatch)
267 {
268 for(PxU32 b = 0; b < tmpPatch->stride; ++b)
269 {
270
271 //PxReal magSq = tmpDistancePointSegmentSquared(p0, p1, mOriginalContacts[tmpPatch->startIndex + b].point, tmpTVal);
272 PxReal magSq = (mOriginalContacts[tmpPatch->startIndex + b].point - p0).dot(n);
273 if(magSq > maxDist)
274 {
275 ind = tmpPatch->startIndex + b;
276 //tVal = tmpTVal;
277 maxDist = magSq;
278 }
279 }
280 tmpPatch = tmpPatch->mNextPatch;
281 }
282 }
283 reducedPatch.contactPoints[2] = ind;
284
285 //const PxVec3 closest = (p0 + (p1 - p0) * tVal);
286
287 const PxVec3 dir = -n;//closest - p3;
288
289 {
290 PxReal maxDist = 0.f;
291 //PxReal tVal = 0.f;
292 ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a];
293 while(tmpPatch)
294 {
295 for(PxU32 b = 0; b < tmpPatch->stride; ++b)
296 {
297 PxReal magSq = (mOriginalContacts[tmpPatch->startIndex + b].point - p0).dot(dir);
298 if(magSq > maxDist)
299 {
300 ind = tmpPatch->startIndex + b;
301 maxDist = magSq;
302 }
303 }
304 tmpPatch = tmpPatch->mNextPatch;
305 }
306 }
307 reducedPatch.contactPoints[3] = ind;
308
309 //Now, we iterate through all the points, and cluster the points. From this, we establish the deepest point that's within a
310 //tolerance of this point and keep that point
311
312 PxReal separation[CONTACT_REDUCTION_MAX_CONTACTS];
313 PxU32 deepestInd[CONTACT_REDUCTION_MAX_CONTACTS];
314 for(PxU32 i = 0; i < 4; ++i)
315 {
316 PxU32 index = reducedPatch.contactPoints[i];
317 separation[i] = mOriginalContacts[index].separation - PXS_SEPARATION_TOLERANCE;
318 deepestInd[i] = index;
319 }
320
321 ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a];
322 while(tmpPatch)
323 {
324 for(PxU32 b = 0; b < tmpPatch->stride; ++b)
325 {
326 PxContactPoint& point = mOriginalContacts[tmpPatch->startIndex + b];
327
328 PxReal distance = PX_MAX_REAL;
329 PxU32 index = 0;
330 for(PxU32 c = 0; c < 4; ++c)
331 {
332 PxVec3 dif = mOriginalContacts[reducedPatch.contactPoints[c]].point - point.point;
333 PxReal d = dif.magnitudeSquared();
334 if(distance > d)
335 {
336 distance = d;
337 index = c;
338 }
339 }
340 if(separation[index] > point.separation)
341 {
342 deepestInd[index] = tmpPatch->startIndex+b;
343 separation[index] = point.separation;
344 }
345
346 }
347 tmpPatch = tmpPatch->mNextPatch;
348 }
349
350 bool chosen[64];
351 PxMemZero(chosen, sizeof(chosen));
352 for(PxU32 i = 0; i < 4; ++i)
353 {
354 reducedPatch.contactPoints[i] = deepestInd[i];
355 chosen[deepestInd[i]] = true;
356 }
357
358 for(PxU32 i = 4; i < CONTACT_REDUCTION_MAX_CONTACTS; ++i)
359 {
360 separation[i] = PX_MAX_REAL;
361 deepestInd[i] = 0;
362 }
363 tmpPatch = mIntermediatePatchesPtrs[a];
364 while(tmpPatch)
365 {
366 for(PxU32 b = 0; b < tmpPatch->stride; ++b)
367 {
368 if(!chosen[tmpPatch->startIndex+b])
369 {
370 PxContactPoint& point = mOriginalContacts[tmpPatch->startIndex + b];
371 for(PxU32 j = 4; j < CONTACT_REDUCTION_MAX_CONTACTS; ++j)
372 {
373 if(point.separation < separation[j])
374 {
375 for(PxU32 k = CONTACT_REDUCTION_MAX_CONTACTS-1; k > j; --k)
376 {
377 separation[k] = separation[k-1];
378 deepestInd[k] = deepestInd[k-1];
379 }
380 separation[j] = point.separation;
381 deepestInd[j] = tmpPatch->startIndex+b;
382 break;
383 }
384 }
385 }
386 }
387 tmpPatch = tmpPatch->mNextPatch;
388 }
389
390 for(PxU32 i = 4; i < CONTACT_REDUCTION_MAX_CONTACTS; ++i)
391 {
392 reducedPatch.contactPoints[i] = deepestInd[i];
393 }
394
395 reducedPatch.numContactPoints = CONTACT_REDUCTION_MAX_CONTACTS;
396 }
397 }
398 }
399 mNumPatches = numReducedPatches;
400 }
401
402 };
403}
404
405}
406
407
408#endif
Definition DyContactReduction.h:80
3 Element vector class.
Definition PxVec3.h:50
PX_CUDA_CALLABLE PX_FORCE_INLINE float magnitudeSquared() const
returns the squared magnitude
Definition PxVec3.h:175
#define PX_RESTRICT
Definition PxPreprocessor.h:355
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_FORCE_INLINE void * PxMemZero(void *dest, PxU32 count)
Sets the bytes of the provided buffer to zero.
Definition PxMemory.h:53
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 DyContactReduction.h:58
Definition DyContactReduction.h:52
Definition DyContactReduction.h:69
Definition PxContactPoint.h:40
PxReal separation
The separation of the shapes at the contact point. A negative separation denotes a penetration.
Definition PxContactPoint.h:51
Definition PxsMaterialManager.h:43