RavEngine
Loading...
Searching...
No Matches
GuGJKSimplex.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_GJKSIMPLEX_H
30#define GU_GJKSIMPLEX_H
31
32#include "foundation/PxVecMath.h"
33#include "GuBarycentricCoordinates.h"
34
35#if (defined __GNUC__ && defined _DEBUG)
36#define PX_GJK_INLINE PX_INLINE
37#define PX_GJK_FORCE_INLINE PX_INLINE
38#else
39#define PX_GJK_INLINE PX_INLINE
40#define PX_GJK_FORCE_INLINE PX_FORCE_INLINE
41#endif
42
43
44namespace physx
45{
46namespace Gu
47{
48 PX_NOALIAS aos::Vec3V closestPtPointTetrahedron(aos::Vec3V* PX_RESTRICT Q, aos::Vec3V* PX_RESTRICT A, aos::Vec3V* PX_RESTRICT B, PxU32& size);
49
50 PX_NOALIAS aos::Vec3V closestPtPointTetrahedron(aos::Vec3V* PX_RESTRICT Q, aos::Vec3V* PX_RESTRICT A, aos::Vec3V* PX_RESTRICT B, PxI32* PX_RESTRICT aInd, PxI32* PX_RESTRICT bInd,
51 PxU32& size);
52
53 PX_NOALIAS PX_FORCE_INLINE aos::BoolV PointOutsideOfPlane4(const aos::Vec3VArg _a, const aos::Vec3VArg _b, const aos::Vec3VArg _c, const aos::Vec3VArg _d)
54 {
55 using namespace aos;
56
57 const Vec4V zero = V4Load(0.f);
58
59 const Vec3V ab = V3Sub(_b, _a);
60 const Vec3V ac = V3Sub(_c, _a);
61 const Vec3V ad = V3Sub(_d, _a);
62 const Vec3V bd = V3Sub(_d, _b);
63 const Vec3V bc = V3Sub(_c, _b);
64
65 const Vec3V v0 = V3Cross(ab, ac);
66 const Vec3V v1 = V3Cross(ac, ad);
67 const Vec3V v2 = V3Cross(ad, ab);
68 const Vec3V v3 = V3Cross(bd, bc);
69
70 const FloatV signa0 = V3Dot(v0, _a);
71 const FloatV signa1 = V3Dot(v1, _a);
72 const FloatV signa2 = V3Dot(v2, _a);
73 const FloatV signd3 = V3Dot(v3, _a);
74
75 const FloatV signd0 = V3Dot(v0, _d);
76 const FloatV signd1 = V3Dot(v1, _b);
77 const FloatV signd2 = V3Dot(v2, _c);
78 const FloatV signa3 = V3Dot(v3, _b);
79
80 const Vec4V signa = V4Merge(signa0, signa1, signa2, signa3);
81 const Vec4V signd = V4Merge(signd0, signd1, signd2, signd3);
82 return V4IsGrtrOrEq(V4Mul(signa, signd), zero);//same side, outside of the plane
83 }
84
85 PX_NOALIAS PX_FORCE_INLINE aos::Vec3V closestPtPointSegment(aos::Vec3V* PX_RESTRICT Q, PxU32& size)
86 {
87 using namespace aos;
88 const Vec3V a = Q[0];
89 const Vec3V b = Q[1];
90
91 //const Vec3V origin = V3Zero();
92 const FloatV zero = FZero();
93 const FloatV one = FOne();
94
95 //Test degenerated case
96 const Vec3V ab = V3Sub(b, a);
97 const FloatV denom = V3Dot(ab, ab);
98 const Vec3V ap = V3Neg(a);//V3Sub(origin, a);
99 const FloatV nom = V3Dot(ap, ab);
100 const BoolV con = FIsGrtrOrEq(FEps(), denom);//FIsEq(denom, zero);
101 //TODO - can we get rid of this branch? The problem is size, which isn't a vector!
102 if(BAllEqTTTT(con))
103 {
104 size = 1;
105 return Q[0];
106 }
107
108 /* const PxU32 count = BAllEq(con, bTrue);
109 size = 2 - count;*/
110
111 const FloatV tValue = FClamp(FDiv(nom, denom), zero, one);
112 return V3ScaleAdd(ab, tValue, a);
113 }
114
115 PX_FORCE_INLINE void getClosestPoint(const aos::Vec3V* PX_RESTRICT Q, const aos::Vec3V* PX_RESTRICT A, const aos::Vec3V* PX_RESTRICT B, const aos::Vec3VArg closest, aos::Vec3V& closestA, aos::Vec3V& closestB, const PxU32 size)
116 {
117 using namespace aos;
118
119 switch(size)
120 {
121 case 1:
122 {
123 closestA = A[0];
124 closestB = B[0];
125 break;
126 }
127 case 2:
128 {
129 FloatV v;
130 barycentricCoordinates(closest, Q[0], Q[1], v);
131 const Vec3V av = V3Sub(A[1], A[0]);
132 const Vec3V bv = V3Sub(B[1], B[0]);
133 closestA = V3ScaleAdd(av, v, A[0]);
134 closestB = V3ScaleAdd(bv, v, B[0]);
135
136 break;
137 }
138 case 3:
139 {
140 //calculate the Barycentric of closest point p in the mincowsky sum
141 FloatV v, w;
142 barycentricCoordinates(closest, Q[0], Q[1], Q[2], v, w);
143
144 const Vec3V av0 = V3Sub(A[1], A[0]);
145 const Vec3V av1 = V3Sub(A[2], A[0]);
146 const Vec3V bv0 = V3Sub(B[1], B[0]);
147 const Vec3V bv1 = V3Sub(B[2], B[0]);
148
149 closestA = V3Add(A[0], V3Add(V3Scale(av0, v), V3Scale(av1, w)));
150 closestB = V3Add(B[0], V3Add(V3Scale(bv0, v), V3Scale(bv1, w)));
151 }
152 };
153 }
154
155 PX_NOALIAS PX_GJK_FORCE_INLINE aos::FloatV closestPtPointTriangleBaryCentric(const aos::Vec3VArg a, const aos::Vec3VArg b, const aos::Vec3VArg c,
156 PxU32* PX_RESTRICT indices, PxU32& size, aos::Vec3V& closestPt)
157 {
158 using namespace aos;
159
160 size = 3;
161 const FloatV zero = FZero();
162 const FloatV eps = FEps();
163
164 const Vec3V ab = V3Sub(b, a);
165 const Vec3V ac = V3Sub(c, a);
166
167 const Vec3V n = V3Cross(ab, ac);
168 //ML: if the shape is oblong, the degeneracy test sometime can't catch the degeneracy in the tetraheron. Therefore, we need to make sure we still can ternimate with the previous
169 //triangle by returning the maxinum distance.
170 const FloatV nn = V3Dot(n, n);
171 if (FAllEq(nn, zero))
172 return FMax();
173
174 //const FloatV va = FNegScaleSub(d5, d4, FMul(d3, d6));//edge region of BC
175 //const FloatV vb = FNegScaleSub(d1, d6, FMul(d5, d2));//edge region of AC
176 //const FloatV vc = FNegScaleSub(d3, d2, FMul(d1, d4));//edge region of AB
177
178 //const FloatV va = V3Dot(n, V3Cross(b, c));//edge region of BC, signed area rbc, u = S(rbc)/S(abc) for a
179 //const FloatV vb = V3Dot(n, V3Cross(c, a));//edge region of AC, signed area rac, v = S(rca)/S(abc) for b
180 //const FloatV vc = V3Dot(n, V3Cross(a, b));//edge region of AB, signed area rab, w = S(rab)/S(abc) for c
181
182 const VecCrossV crossA = V3PrepareCross(a);
183 const VecCrossV crossB = V3PrepareCross(b);
184 const VecCrossV crossC = V3PrepareCross(c);
185 const Vec3V bCrossC = V3Cross(crossB, crossC);
186 const Vec3V cCrossA = V3Cross(crossC, crossA);
187 const Vec3V aCrossB = V3Cross(crossA, crossB);
188
189 const FloatV va = V3Dot(n, bCrossC);//edge region of BC, signed area rbc, u = S(rbc)/S(abc) for a
190 const FloatV vb = V3Dot(n, cCrossA);//edge region of AC, signed area rac, v = S(rca)/S(abc) for b
191 const FloatV vc = V3Dot(n, aCrossB);//edge region of AB, signed area rab, w = S(rab)/S(abc) for c
192
193 const BoolV isFacePoints = BAnd(FIsGrtrOrEq(va, zero), BAnd(FIsGrtrOrEq(vb, zero), FIsGrtrOrEq(vc, zero)));
194
195 //face region
196 if(BAllEqTTTT(isFacePoints))
197 {
198 const FloatV t = FDiv(V3Dot(n, a), nn);
199 const Vec3V q = V3Scale(n, t);
200 closestPt = q;
201 return V3Dot(q, q);
202 }
203
204 const Vec3V ap = V3Neg(a);
205 const Vec3V bp = V3Neg(b);
206 const Vec3V cp = V3Neg(c);
207
208 const FloatV d1 = V3Dot(ab, ap); // snom
209 const FloatV d2 = V3Dot(ac, ap); // tnom
210 const FloatV d3 = V3Dot(ab, bp); // -sdenom
211 const FloatV d4 = V3Dot(ac, bp); // unom = d4 - d3
212 const FloatV d5 = V3Dot(ab, cp); // udenom = d5 - d6
213 const FloatV d6 = V3Dot(ac, cp); // -tdenom
214
215 const FloatV unom = FSub(d4, d3);
216 const FloatV udenom = FSub(d5, d6);
217
218 size = 2;
219 //check if p in edge region of AB
220 const BoolV con30 = FIsGrtrOrEq(zero, vc);
221 const BoolV con31 = FIsGrtrOrEq(d1, zero);
222 const BoolV con32 = FIsGrtrOrEq(zero, d3);
223 const BoolV con3 = BAnd(con30, BAnd(con31, con32));//edge AB region
224 if(BAllEqTTTT(con3))
225 {
226 const FloatV toRecipAB = FSub(d1, d3);
227 const FloatV recipAB = FSel(FIsGrtr(FAbs(toRecipAB), eps), FRecip(toRecipAB), zero);
228 const FloatV t = FMul(d1, recipAB);
229 const Vec3V q = V3ScaleAdd(ab, t, a);
230 closestPt = q;
231 return V3Dot(q, q);
232 }
233
234 //check if p in edge region of BC
235 const BoolV con40 = FIsGrtrOrEq(zero, va);
236 const BoolV con41 = FIsGrtrOrEq(d4, d3);
237 const BoolV con42 = FIsGrtrOrEq(d5, d6);
238 const BoolV con4 = BAnd(con40, BAnd(con41, con42)); //edge BC region
239 if(BAllEqTTTT(con4))
240 {
241 const Vec3V bc = V3Sub(c, b);
242 const FloatV toRecipBC = FAdd(unom, udenom);
243 const FloatV recipBC = FSel(FIsGrtr(FAbs(toRecipBC), eps), FRecip(toRecipBC), zero);
244 const FloatV t = FMul(unom, recipBC);
245 indices[0] = indices[1];
246 indices[1] = indices[2];
247 const Vec3V q = V3ScaleAdd(bc, t, b);
248 closestPt = q;
249 return V3Dot(q, q);
250 }
251
252 //check if p in edge region of AC
253 const BoolV con50 = FIsGrtrOrEq(zero, vb);
254 const BoolV con51 = FIsGrtrOrEq(d2, zero);
255 const BoolV con52 = FIsGrtrOrEq(zero, d6);
256
257 const BoolV con5 = BAnd(con50, BAnd(con51, con52));//edge AC region
258 if(BAllEqTTTT(con5))
259 {
260 const FloatV toRecipAC = FSub(d2, d6);
261 const FloatV recipAC = FSel(FIsGrtr(FAbs(toRecipAC), eps), FRecip(toRecipAC), zero);
262 const FloatV t = FMul(d2, recipAC);
263 indices[1]=indices[2];
264 const Vec3V q = V3ScaleAdd(ac, t, a);
265 closestPt = q;
266 return V3Dot(q, q);
267 }
268
269 size = 1;
270 //check if p in vertex region outside a
271 const BoolV con00 = FIsGrtrOrEq(zero, d1); // snom <= 0
272 const BoolV con01 = FIsGrtrOrEq(zero, d2); // tnom <= 0
273 const BoolV con0 = BAnd(con00, con01); // vertex region a
274 if(BAllEqTTTT(con0))
275 {
276 closestPt = a;
277 return V3Dot(a, a);
278 }
279
280 //check if p in vertex region outside b
281 const BoolV con10 = FIsGrtrOrEq(d3, zero);
282 const BoolV con11 = FIsGrtrOrEq(d3, d4);
283 const BoolV con1 = BAnd(con10, con11); // vertex region b
284 if(BAllEqTTTT(con1))
285 {
286 indices[0] = indices[1];
287 closestPt = b;
288 return V3Dot(b, b);
289 }
290
291 //p is in vertex region outside c
292 indices[0] = indices[2];
293 closestPt = c;
294 return V3Dot(c, c);
295 }
296
297 PX_NOALIAS PX_GJK_FORCE_INLINE aos::Vec3V closestPtPointTriangle(aos::Vec3V* PX_RESTRICT Q, aos::Vec3V* A, aos::Vec3V* B, PxU32& size)
298 {
299 using namespace aos;
300
301 size = 3;
302
303 const FloatV eps = FEps();
304 const Vec3V a = Q[0];
305 const Vec3V b = Q[1];
306 const Vec3V c = Q[2];
307 const Vec3V ab = V3Sub(b, a);
308 const Vec3V ac = V3Sub(c, a);
309 const Vec3V signArea = V3Cross(ab, ac);//0.5*(abXac)
310 const FloatV area = V3Dot(signArea, signArea);
311 if(FAllGrtrOrEq(eps, area))
312 {
313 //degenerate
314 size = 2;
315 return closestPtPointSegment(Q, size);
316 }
317
318 PxU32 _size;
319 PxU32 indices[3]={0, 1, 2};
320 Vec3V closestPt;
321 closestPtPointTriangleBaryCentric(a, b, c, indices, _size, closestPt);
322
323 if(_size != 3)
324 {
325 const Vec3V q0 = Q[indices[0]]; const Vec3V q1 = Q[indices[1]];
326 const Vec3V a0 = A[indices[0]]; const Vec3V a1 = A[indices[1]];
327 const Vec3V b0 = B[indices[0]]; const Vec3V b1 = B[indices[1]];
328
329 Q[0] = q0; Q[1] = q1;
330 A[0] = a0; A[1] = a1;
331 B[0] = b0; B[1] = b1;
332
333 size = _size;
334 }
335
336 return closestPt;
337 }
338
339 PX_NOALIAS PX_GJK_FORCE_INLINE aos::Vec3V closestPtPointTriangle(aos::Vec3V* PX_RESTRICT Q, aos::Vec3V* A, aos::Vec3V* B, PxI32* PX_RESTRICT aInd, PxI32* PX_RESTRICT bInd,
340 PxU32& size)
341 {
342 using namespace aos;
343
344 size = 3;
345
346 const FloatV eps = FEps();
347
348 const Vec3V a = Q[0];
349 const Vec3V b = Q[1];
350 const Vec3V c = Q[2];
351 const Vec3V ab = V3Sub(b, a);
352 const Vec3V ac = V3Sub(c, a);
353 const Vec3V signArea = V3Cross(ab, ac);//0.5*(abXac)
354 const FloatV area = V3Dot(signArea, signArea);
355 if(FAllGrtrOrEq(eps, area))
356 {
357 //degenerate
358 size = 2;
359 return closestPtPointSegment(Q, size);
360 }
361
362 PxU32 _size;
363 PxU32 indices[3]={0, 1, 2};
364 Vec3V closestPt;
365 closestPtPointTriangleBaryCentric(a, b, c, indices, _size, closestPt);
366
367 if(_size != 3)
368 {
369 const Vec3V q0 = Q[indices[0]]; const Vec3V q1 = Q[indices[1]];
370 const Vec3V a0 = A[indices[0]]; const Vec3V a1 = A[indices[1]];
371 const Vec3V b0 = B[indices[0]]; const Vec3V b1 = B[indices[1]];
372 const PxI32 aInd0 = aInd[indices[0]]; const PxI32 aInd1 = aInd[indices[1]];
373 const PxI32 bInd0 = bInd[indices[0]]; const PxI32 bInd1 = bInd[indices[1]];
374
375 Q[0] = q0; Q[1] = q1;
376 A[0] = a0; A[1] = a1;
377 B[0] = b0; B[1] = b1;
378 aInd[0] = aInd0; aInd[1] = aInd1;
379 bInd[0] = bInd0; bInd[1] = bInd1;
380
381 size = _size;
382 }
383
384 return closestPt;
385 }
386
387 PX_NOALIAS PX_FORCE_INLINE aos::Vec3V GJKCPairDoSimplex(aos::Vec3V* PX_RESTRICT Q, aos::Vec3V* PX_RESTRICT A, aos::Vec3V* PX_RESTRICT B, const aos::Vec3VArg support,
388 PxU32& size)
389 {
390 using namespace aos;
391
392 //const PxU32 tempSize = size;
393 //calculate a closest from origin to the simplex
394 switch(size)
395 {
396 case 1:
397 {
398 return support;
399 }
400 case 2:
401 {
402 return closestPtPointSegment(Q, size);
403 }
404 case 3:
405 {
406 return closestPtPointTriangle(Q, A, B, size);
407 }
408 case 4:
409 return closestPtPointTetrahedron(Q, A, B, size);
410 default:
411 PX_ASSERT(0);
412 }
413 return support;
414 }
415
416 PX_NOALIAS PX_FORCE_INLINE aos::Vec3V GJKCPairDoSimplex(aos::Vec3V* PX_RESTRICT Q, aos::Vec3V* PX_RESTRICT A, aos::Vec3V* PX_RESTRICT B, PxI32* PX_RESTRICT aInd, PxI32* PX_RESTRICT bInd,
417 const aos::Vec3VArg support, PxU32& size)
418 {
419 using namespace aos;
420
421 //const PxU32 tempSize = size;
422 //calculate a closest from origin to the simplex
423 switch(size)
424 {
425 case 1:
426 {
427 return support;
428 }
429 case 2:
430 {
431 return closestPtPointSegment(Q, size);
432 }
433 case 3:
434 {
435 return closestPtPointTriangle(Q, A, B, aInd, bInd, size);
436 }
437 case 4:
438 return closestPtPointTetrahedron(Q, A, B, aInd, bInd, size);
439 default:
440 PX_ASSERT(0);
441 }
442 return support;
443 }
444}
445
446}
447
448#endif
#define PX_RESTRICT
Definition PxPreprocessor.h:355
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
#define PX_NOALIAS
Definition PxPreprocessor.h:364
GLM_FUNC_DECL GLM_CONSTEXPR genType zero()
Definition constants.inl:6
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39