RavEngine
Loading...
Searching...
No Matches
GuGJKRaycast.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_GJKRAYCAST_H
30#define GU_GJKRAYCAST_H
31
32#include "GuGJKType.h"
33#include "GuGJKSimplex.h"
34#include "GuConvexSupportTable.h"
35#include "GuGJKPenetration.h"
36#include "GuEPA.h"
37
38namespace physx
39{
40
41namespace Gu
42{
43 /*
44 ConvexA is in the local space of ConvexB
45 lambda : the time of impact(TOI)
46 initialLambda : the start time of impact value (disable)
47 s : the sweep ray origin
48 r : the normalized sweep ray direction scaled by the sweep distance. r should be in ConvexB's space
49 normal : the contact normal
50 inflation : the amount by which we inflate the swept shape. If the inflated shapes aren't initially-touching,
51 the TOI will return the time at which both shapes are at a distance equal to inflation separated. If inflation is 0
52 the TOI will return the time at which both shapes are touching.
53 */
54 template<class ConvexA, class ConvexB>
55 bool gjkRaycast(const ConvexA& a, const ConvexB& b, const aos::Vec3VArg initialDir, const aos::FloatVArg initialLambda, const aos::Vec3VArg s, const aos::Vec3VArg r, aos::FloatV& lambda, aos::Vec3V& normal, aos::Vec3V& closestA, const PxReal _inflation)
56 {
57 PX_UNUSED(initialLambda);
58
59 using namespace aos;
60
61 const FloatV inflation = FLoad(_inflation);
62 const Vec3V zeroV = V3Zero();
63 const FloatV zero = FZero();
64 const FloatV one = FOne();
65 const BoolV bTrue = BTTTT();
66
67 const FloatV maxDist = FLoad(PX_MAX_REAL);
68
69 FloatV _lambda = zero;//initialLambda;
70 Vec3V x = V3ScaleAdd(r, _lambda, s);
71 PxU32 size=1;
72
73 //const Vec3V dir = V3Sub(a.getCenter(), b.getCenter());
74 const Vec3V _initialSearchDir = V3Sel(FIsGrtr(V3Dot(initialDir, initialDir), FEps()), initialDir, V3UnitX());
75 const Vec3V initialSearchDir = V3Normalize(_initialSearchDir);
76
77 const Vec3V initialSupportA(a.ConvexA::support(V3Neg(initialSearchDir)));
78 const Vec3V initialSupportB( b.ConvexB::support(initialSearchDir));
79
80 Vec3V Q[4] = {V3Sub(initialSupportA, initialSupportB), zeroV, zeroV, zeroV}; //simplex set
81 Vec3V A[4] = {initialSupportA, zeroV, zeroV, zeroV}; //ConvexHull a simplex set
82 Vec3V B[4] = {initialSupportB, zeroV, zeroV, zeroV}; //ConvexHull b simplex set
83
84 Vec3V v = V3Neg(Q[0]);
85 Vec3V supportA = initialSupportA;
86 Vec3V supportB = initialSupportB;
87 Vec3V support = Q[0];
88
89 const FloatV minMargin = FMin(a.ConvexA::getSweepMargin(), b.ConvexB::getSweepMargin());
90 const FloatV eps1 = FMul(minMargin, FLoad(0.1f));
91 const FloatV inflationPlusEps(FAdd(eps1, inflation));
92 const FloatV eps2 = FMul(eps1, eps1);
93
94 const FloatV inflation2 = FMul(inflationPlusEps, inflationPlusEps);
95
96 Vec3V clos(Q[0]);
97 Vec3V preClos = clos;
98 //Vec3V closA(initialSupportA);
99 FloatV sDist = V3Dot(v, v);
100 FloatV minDist = sDist;
101 //Vec3V closAA = initialSupportA;
102 //Vec3V closBB = initialSupportB;
103
104 BoolV bNotTerminated = FIsGrtr(sDist, eps2);
105 BoolV bNotDegenerated = bTrue;
106
107 Vec3V nor = v;
108
109 while(BAllEqTTTT(bNotTerminated))
110 {
111 minDist = sDist;
112 preClos = clos;
113
114 const Vec3V vNorm = V3Normalize(v);
115 const Vec3V nvNorm = V3Neg(vNorm);
116
117 supportA=a.ConvexA::support(vNorm);
118 supportB=V3Add(x, b.ConvexB::support(nvNorm));
119
120 //calculate the support point
121 support = V3Sub(supportA, supportB);
122 const Vec3V w = V3Neg(support);
123 const FloatV vw = FSub(V3Dot(vNorm, w), inflationPlusEps);
124 if(FAllGrtr(vw, zero))
125 {
126 const FloatV vr = V3Dot(vNorm, r);
127 if(FAllGrtrOrEq(vr, zero))
128 {
129 return false;
130 }
131 else
132 {
133 const FloatV _oldLambda = _lambda;
134 _lambda = FSub(_lambda, FDiv(vw, vr));
135 if(FAllGrtr(_lambda, _oldLambda))
136 {
137 if(FAllGrtr(_lambda, one))
138 {
139 return false;
140 }
141 const Vec3V bPreCenter = x;
142 x = V3ScaleAdd(r, _lambda, s);
143
144 const Vec3V offSet =V3Sub(x, bPreCenter);
145 const Vec3V b0 = V3Add(B[0], offSet);
146 const Vec3V b1 = V3Add(B[1], offSet);
147 const Vec3V b2 = V3Add(B[2], offSet);
148
149 B[0] = b0;
150 B[1] = b1;
151 B[2] = b2;
152
153 Q[0]=V3Sub(A[0], b0);
154 Q[1]=V3Sub(A[1], b1);
155 Q[2]=V3Sub(A[2], b2);
156
157 supportB = V3Add(x, b.ConvexB::support(nvNorm));
158 support = V3Sub(supportA, supportB);
159 minDist = maxDist;
160 nor = v;
161 //size=0;
162 }
163 }
164 }
165
166 PX_ASSERT(size < 4);
167 A[size]=supportA;
168 B[size]=supportB;
169 Q[size++]=support;
170
171 //calculate the closest point between two convex hull
172 clos = GJKCPairDoSimplex(Q, A, B, support, size);
173 v = V3Neg(clos);
174 sDist = V3Dot(clos, clos);
175
176 bNotDegenerated = FIsGrtr(minDist, sDist);
177 bNotTerminated = BAnd(FIsGrtr(sDist, inflation2), bNotDegenerated);
178 }
179
180 const BoolV aQuadratic = a.isMarginEqRadius();
181 //ML:if the Minkowski sum of two objects are too close to the original(eps2 > sDist), we can't take v because we will lose lots of precision. Therefore, we will take
182 //previous configuration's normal which should give us a reasonable approximation. This effectively means that, when we do a sweep with inflation, we always keep v because
183 //the shapes converge separated. If we do a sweep without inflation, we will usually use the previous configuration's normal.
184 nor = V3Sel(BAnd(FIsGrtr(sDist, eps2), bNotDegenerated), v, nor);
185 nor = V3Neg(V3NormalizeSafe(nor, V3Zero()));
186 normal = nor;
187 lambda = _lambda;
188
189 const Vec3V closestP = V3Sel(bNotDegenerated, clos, preClos);
190 Vec3V closA = zeroV, closB = zeroV;
191 getClosestPoint(Q, A, B, closestP, closA, closB, size);
192 closestA = V3Sel(aQuadratic, V3NegScaleSub(nor, a.getMargin(), closA), closA);
193
194 return true;
195 }
196
197
198 /*
199 ConvexA is in the local space of ConvexB
200 lambda : the time of impact(TOI)
201 initialLambda : the start time of impact value (disable)
202 s : the sweep ray origin in ConvexB's space
203 r : the normalized sweep ray direction scaled by the sweep distance. r should be in ConvexB's space
204 normal : the contact normal in ConvexB's space
205 closestA : the tounching contact in ConvexB's space
206 inflation : the amount by which we inflate the swept shape. If the inflated shapes aren't initially-touching,
207 the TOI will return the time at which both shapes are at a distance equal to inflation separated. If inflation is 0
208 the TOI will return the time at which both shapes are touching.
209 */
210 template<class ConvexA, class ConvexB>
211 bool gjkRaycastPenetration(const ConvexA& a, const ConvexB& b, const aos::Vec3VArg initialDir, const aos::FloatVArg initialLambda, const aos::Vec3VArg s, const aos::Vec3VArg r, aos::FloatV& lambda,
212 aos::Vec3V& normal, aos::Vec3V& closestA, const PxReal _inflation, const bool initialOverlap)
213 {
214 using namespace aos;
215 Vec3V closA;
216 Vec3V norm;
217 FloatV _lambda;
218 if(gjkRaycast(a, b, initialDir, initialLambda, s, r, _lambda, norm, closA, _inflation))
219 {
220 const FloatV zero = FZero();
221 lambda = _lambda;
222 if(FAllEq(_lambda, zero) && initialOverlap)
223 {
224 //time of impact is zero, the sweep shape is intesect, use epa to get the normal and contact point
225 const FloatV contactDist = getSweepContactEps(a.getMargin(), b.getMargin());
226
227 FloatV sDist(zero);
228 PxU8 aIndices[4];
229 PxU8 bIndices[4];
230 PxU8 size=0;
231 GjkOutput output;
232
233 //PX_COMPILE_TIME_ASSERT(typename Shrink<ConvexB>::Type != Gu::BoxV);
234
235#ifdef USE_VIRTUAL_GJK
236 GjkStatus status = gjkPenetration<ConvexA, ConvexB>(a, b,
237#else
238 typename ConvexA::ConvexGeomType convexA = a.getGjkConvex();
239 typename ConvexB::ConvexGeomType convexB = b.getGjkConvex();
240
241 GjkStatus status = gjkPenetration<typename ConvexA::ConvexGeomType, typename ConvexB::ConvexGeomType>(convexA, convexB,
242#endif
243 initialDir, contactDist, false, aIndices, bIndices, size, output);
244 //norm = V3Neg(norm);
245 if(status == GJK_CONTACT)
246 {
247 closA = output.closestA;
248 sDist = output.penDep;
249 norm = output.normal;
250 }
251 else if(status == EPA_CONTACT)
252 {
253 status = epaPenetration(a, b, aIndices, bIndices, size, false, FLoad(1.f), output);
254
255 if (status == EPA_CONTACT || status == EPA_DEGENERATE)
256 {
257 closA = output.closestA;
258 sDist = output.penDep;
259 norm = output.normal;
260 }
261 else
262 {
263 //ML: if EPA fail, we will use the ray direction as the normal and set pentration to be zero
264 closA = V3Zero();
265 sDist = zero;
266 norm = V3Normalize(V3Neg(r));
267 }
268 }
269 else
270 {
271 //ML:: this will be gjk degenerate case. However, we can still
272 //reply on the previous iteration's closest feature information
273 closA = output.closestA;
274 sDist = output.penDep;
275 norm = output.normal;
276 }
277 lambda = FMin(zero, sDist);
278 }
279 closestA = closA;
280 normal = norm;
281 return true;
282 }
283 return false;
284 }
285}
286}
287
288#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