RavEngine
Loading...
Searching...
No Matches
GuGJK.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_GJK_H
30#define GU_GJK_H
31
32
33#include "GuGJKType.h"
34#include "GuGJKUtil.h"
35#include "GuConvexSupportTable.h"
36#include "GuGJKSimplex.h"
37#include "foundation/PxFPU.h"
38
39#define GJK_SEPERATING_AXIS_VALIDATE 0
40
41namespace physx
42{
43namespace Gu
44{
45
46 class ConvexV;
47
48#if GJK_SEPERATING_AXIS_VALIDATE
49 template<typename ConvexA, typename ConvexB>
50 static void validateSeparatingAxis(const ConvexA& a, const ConvexB& b, const aos::Vec3VArg separatingAxis)
51 {
52 using namespace aos;
53 const Vec3V minV0 = a.ConvexA::support(V3Neg(separatingAxis));
54 const Vec3V maxV0 = a.ConvexA::support(separatingAxis);
55
56 const Vec3V minV1 = b.ConvexB::support(V3Neg(separatingAxis));
57 const Vec3V maxV1 = b.ConvexB::support(separatingAxis);
58
59 const FloatV min0 = V3Dot(minV0, separatingAxis);
60 const FloatV max0 = V3Dot(maxV0, separatingAxis);
61
62 const FloatV min1 = V3Dot(minV1, separatingAxis);
63 const FloatV max1 = V3Dot(maxV1, separatingAxis);
64
65 PX_ASSERT(FAllGrtr(min1, max0) || FAllGrtr(min0, max1));
66 }
67#endif
68
69
70 /*
71
72 initialSearchDir :initial search direction in the mincowsky sum, it should be in the local space of ConvexB
73 closestA :it is the closest point in ConvexA in the local space of ConvexB if acceptance threshold is sufficent large. Otherwise, it will be garbage
74 closestB :it is the closest point in ConvexB in the local space of ConvexB if acceptance threshold is sufficent large. Otherwise, it will be garbage
75 normal :normal pointing from ConvexA to ConvexB in the local space of ConvexB if acceptance threshold is sufficent large. Otherwise, it will be garbage
76 distance :the distance of the closest points between ConvexA and ConvexB if acceptance threshold is sufficent large. Otherwise, it will be garbage
77 contactDist :the distance which we will generate contact information if ConvexA and ConvexB are both separated within contactDist
78 */
79
80 //*Each convex has
81 //* a support function
82 //* a margin - the amount by which we shrunk the shape for a convex or box. If the shape are sphere/capsule, margin is the radius
83 //* a minMargin - some percentage of margin, which is used to determine the termination condition for gjk
84
85 //*We'll report:
86 //* GJK_NON_INTERSECT if the sign distance between the shapes is greater than the sum of the margins and the the contactDistance
87 //* GJK_CLOSE if the minimum distance between the shapes is less than the sum of the margins and the the contactDistance
88 //* GJK_CONTACT if the two shapes are overlapped with each other
89 template<typename ConvexA, typename ConvexB>
90 GjkStatus gjk(const ConvexA& a, const ConvexB& b, const aos::Vec3V& initialSearchDir, const aos::FloatV& contactDist, aos::Vec3V& closestA, aos::Vec3V& closestB, aos::Vec3V& normal,
91 aos::FloatV& distance)
92 {
93 using namespace aos;
94 Vec3V Q[4];
95 Vec3V A[4];
96 Vec3V B[4];
97
98 const FloatV zero = FZero();
99 PxU32 size=0;
100
101 //const Vec3V _initialSearchDir = aToB.p;
102 Vec3V closest = V3Sel(FIsGrtr(V3Dot(initialSearchDir, initialSearchDir), zero), initialSearchDir, V3UnitX());
103 Vec3V v = V3Normalize(closest);
104
105 // ML: eps2 is the square value of an epsilon value which applied in the termination condition for two shapes overlap.
106 // GJK will terminate based on sq(v) < eps and indicate that two shapes are overlapping.
107 // we calculate the eps based on 10% of the minimum margin of two shapes
108 const FloatV tenPerc = FLoad(0.1f);
109 const FloatV minMargin = FMin(a.getMinMargin(), b.getMinMargin());
110 const FloatV eps = FMax(FLoad(1e-6f), FMul(minMargin, tenPerc));
111
112 // ML:epsRel is square value of 1.5% which applied to the distance of a closest point(v) to the origin.
113 // If |v|- v/|v|.dot(w) < epsRel*|v|,
114 // two shapes are clearly separated, GJK terminate and return non intersect.
115 // This adjusts the termination condition based on the length of v
116 // which avoids ill-conditioned terminations.
117 const FloatV epsRel = FLoad(0.000225f);//1.5%.
118
119 FloatV dist = FMax();
120 FloatV prevDist;
121 Vec3V prevClos, prevDir;
122
123 const BoolV bTrue = BTTTT();
124 BoolV bNotTerminated = bTrue;
125 BoolV bNotDegenerated = bTrue;
126
127 //ML: we treate sphere as a point and capsule as segment in the support function, so that we need to add on radius
128 const BoolV aQuadratic = a.isMarginEqRadius();
129 const BoolV bQuadratic = b.isMarginEqRadius();
130
131 const FloatV sumMargin = FAdd(FSel(aQuadratic, a.getMargin(), zero), FSel(bQuadratic, b.getMargin(), zero));
132 const FloatV separatingDist = FAdd(sumMargin, contactDist);
133 const FloatV relDif = FSub(FOne(), epsRel);
134
135 do
136 {
137 prevDist = dist;
138 prevClos = closest;
139 prevDir = v;
140
141 //de-virtualize, we don't need to use a normalize direction to get the support point
142 //this will allow the cpu better pipeline the normalize calculation while it does the
143 //support map
144 const Vec3V supportA=a.ConvexA::support(V3Neg(closest));
145 const Vec3V supportB=b.ConvexB::support(closest);
146
147 //calculate the support point
148 const Vec3V support = V3Sub(supportA, supportB);
149
150 const FloatV signDist = V3Dot(v, support);
151
152 if(FAllGrtr(signDist, separatingDist))
153 {
154 //ML:gjk found a separating axis for these two objects and the distance is large than the seperating distance, gjk might not converage so that
155 //we won't generate contact information
156#if GJK_SEPERATING_AXIS_VALIDATE
157 validateSeparatingAxis(a, b, v);
158#endif
159 return GJK_NON_INTERSECT;
160 }
161
162 const BoolV con = BAnd(FIsGrtr(signDist, sumMargin), FIsGrtr(signDist, FMul(relDif, dist)));
163
164 if(BAllEqTTTT(con))
165 {
166 //ML:: gjk converage and we get the closest point information
167 Vec3V closA, closB;
168 //normal point from A to B
169 const Vec3V n = V3Neg(v);
170 getClosestPoint(Q, A, B, closest, closA, closB, size);
171 closestA = V3Sel(aQuadratic, V3ScaleAdd(n, a.getMargin(), closA), closA);
172 closestB = V3Sel(bQuadratic, V3NegScaleSub(n, b.getMargin(), closB), closB);
173 distance = FMax(zero, FSub(dist, sumMargin));
174 normal = n;//V3Normalize(V3Neg(closest));
175 return GJK_CLOSE;
176 }
177
178 PX_ASSERT(size < 4);
179 A[size]=supportA;
180 B[size]=supportB;
181 Q[size++]=support;
182
183 //calculate the closest point between two convex hull
184 closest = GJKCPairDoSimplex(Q, A, B, support, size);
185
186 dist = V3Length(closest);
187 v = V3ScaleInv(closest, dist);
188 bNotDegenerated = FIsGrtr(prevDist, dist);
189 bNotTerminated = BAnd(FIsGrtr(dist, eps), bNotDegenerated);
190 }while(BAllEqTTTT(bNotTerminated));
191
192 if(BAllEqTTTT(bNotDegenerated))
193 {
194 //GJK_CONTACT
195 distance = zero;
196 return GJK_CONTACT;
197 }
198
199 //GJK degenerated, use the previous closest point
200 const FloatV acceptancePerc = FLoad(0.2f);
201 const FloatV acceptanceMargin = FMul(acceptancePerc, FMin(a.getMargin(), b.getMargin()));
202 const FloatV acceptanceDist = FSel(FIsGrtr(sumMargin, zero), sumMargin, acceptanceMargin);
203 Vec3V closA, closB;
204 const Vec3V n = V3Neg(prevDir);//V3Normalize(V3Neg(prevClos));
205 getClosestPoint(Q, A, B, prevClos, closA, closB, size);
206 closestA = V3Sel(aQuadratic, V3ScaleAdd(n, a.getMargin(), closA), closA);
207 closestB = V3Sel(bQuadratic, V3NegScaleSub(n, b.getMargin(), closB), closB);
208 normal = n;
209 dist = FMax(zero, FSub(prevDist, sumMargin));
210 distance = dist;
211
212 return FAllGrtr(dist, acceptanceDist) ? GJK_CLOSE: GJK_CONTACT;
213 }
214}
215
216}
217
218#endif
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