RavEngine
Loading...
Searching...
No Matches
GuBV4_CapsuleSweep_Internal.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_BV4_CAPSULE_SWEEP_INTERNAL_H
30#define GU_BV4_CAPSULE_SWEEP_INTERNAL_H
31
32// PT: for capsule-sweeps please refer to %SDKRoot%\InternalDocumentation\GU\Sweep strategies.ppt.
33// We use:
34// - method 3 if the capsule is axis-aligned (SWEEP_AABB_IMPL is defined)
35// - method 2 otherwise (SWEEP_AABB_IMPL is undefined)
36
37// PT: TODO: get rid of that one
38static PX_FORCE_INLINE bool sweepSphereVSTriangle( const PxVec3& center, const float radius,
39 const PxVec3* PX_RESTRICT triVerts, const PxVec3& triUnitNormal,
40 const PxVec3& unitDir,
41 float& curT, bool& directHit)
42{
43 float currentDistance;
44 if(!sweepSphereVSTri(triVerts, triUnitNormal, center, radius, unitDir, currentDistance, directHit, true))
45 return false;
46
47 // PT: using ">" or ">=" is enough to block the CCT or not in the DE5967 visual test. Change to ">=" if a repro is needed.
48 if(currentDistance > curT + GU_EPSILON_SAME_DISTANCE * PxMax(1.0f, curT))
49 return false;
50 curT = currentDistance;
51 return true;
52}
53
54static PX_FORCE_INLINE bool sweepSphereVSQuad( const PxVec3& center, const float radius,
55 const PxVec3* PX_RESTRICT quadVerts, const PxVec3& quadUnitNormal,
56 const PxVec3& unitDir,
57 float& curT)
58{
59 float currentDistance;
60 if(!sweepSphereVSQuad(quadVerts, quadUnitNormal, center, radius, unitDir, currentDistance))
61 return false;
62
63 // PT: using ">" or ">=" is enough to block the CCT or not in the DE5967 visual test. Change to ">=" if a repro is needed.
64 if(currentDistance > curT + GU_EPSILON_SAME_DISTANCE * PxMax(1.0f, curT))
65 return false;
66 curT = currentDistance;
67 return true;
68}
69
71
72// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
73static bool /*__fastcall*/ testTri( const CapsuleSweepParams* PX_RESTRICT params, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& N,
74 const PxVec3& unitDir, const float capsuleRadius, const float dpc0, float& curT, bool& status)
75{
76 // PT: TODO: check the assembly here (TA34704)
77 PxVec3 currentTri[3];
78 // PT: TODO: optimize this copy (TA34704)
79 currentTri[0] = p0;
80 currentTri[1] = p1;
81 currentTri[2] = p2;
82
83 // PT: beware, culling is only ok on the sphere I think
84 if(rejectTriangle(params->mCapsuleCenter, unitDir, curT, capsuleRadius, currentTri, dpc0))
85 return false;
86
87 float magnitude = N.magnitude();
88 if(magnitude==0.0f)
89 return false;
90
91 PxVec3 triNormal = N / magnitude;
92
93 bool DirectHit;
94 if(sweepSphereVSTriangle(params->mCapsuleCenter, capsuleRadius, currentTri, triNormal, unitDir, curT, DirectHit))
95 {
96 status = true;
97 }
98 return DirectHit;
99}
100
101// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
102static void /*__fastcall*/ testQuad(const CapsuleSweepParams* PX_RESTRICT params, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& p3, const PxVec3& N,
103 const PxVec3& unitDir, const float capsuleRadius, const float dpc0, float& curT, bool& status)
104{
105 // PT: TODO: optimize this copy (TA34704)
106 PxVec3 currentQuad[4];
107 currentQuad[0] = p0;
108 currentQuad[1] = p1;
109 currentQuad[2] = p2;
110 currentQuad[3] = p3;
111
112 // PT: beware, culling is only ok on the sphere I think
113 if(rejectQuad(params->mCapsuleCenter, unitDir, curT, capsuleRadius, currentQuad, dpc0))
114 return;
115
116 float magnitude = N.magnitude();
117 if(magnitude==0.0f)
118 return;
119
120 PxVec3 triNormal = N / magnitude;
121
122 if(sweepSphereVSQuad(params->mCapsuleCenter, capsuleRadius, currentQuad, triNormal, unitDir, curT))
123 {
124 status = true;
125 }
126}
127
128static PX_FORCE_INLINE float Set2(const PxVec3& p0, const PxVec3& n, const PxVec3& p)
129{
130 return (p-p0).dot(n);
131}
132
133static PX_FORCE_INLINE bool sweepCapsuleVsTriangle(const CapsuleSweepParams* PX_RESTRICT params, const PxTriangle& triangle, float& t, bool isDoubleSided, PxVec3& normal)
134{
135 const PxVec3& unitDir = params->mLocalDir_Padded;
136
137 // Create triangle normal
138 PxVec3 denormalizedNormal = (triangle.verts[0] - triangle.verts[1]).cross(triangle.verts[0] - triangle.verts[2]);
139
140 normal = denormalizedNormal;
141
142 // Backface culling
143 const bool culled = denormalizedNormal.dot(unitDir) > 0.0f;
144 if(culled)
145 {
146 if(!isDoubleSided)
147 return false;
148
149 denormalizedNormal = -denormalizedNormal;
150 }
151
152 const float capsuleRadius = params->mLocalCapsule.radius;
153 float curT = params->mStabbedFace.mDistance;// + GU_EPSILON_SAME_DISTANCE*20.0f;
154 const float dpc0 = params->mCapsuleCenter.dot(unitDir);
155
156 bool status = false;
157
158 // Extrude mesh on the fly
159 const PxVec3 p0 = triangle.verts[0] - params->mExtrusionDir;
160 const PxVec3 p1 = triangle.verts[1+culled] - params->mExtrusionDir;
161 const PxVec3 p2 = triangle.verts[2-culled] - params->mExtrusionDir;
162
163 const PxVec3 p0b = triangle.verts[0] + params->mExtrusionDir;
164 const PxVec3 p1b = triangle.verts[1+culled] + params->mExtrusionDir;
165 const PxVec3 p2b = triangle.verts[2-culled] + params->mExtrusionDir;
166
167 const float extrusionSign = denormalizedNormal.dot(params->mExtrusionDir);
168
169 const PxVec3 p2b_p1b = p2b - p1b;
170 const PxVec3 p0b_p1b = p0b - p1b;
171 const PxVec3 p2b_p2 = 2.0f * params->mExtrusionDir;
172 const PxVec3 p1_p1b = -p2b_p2;
173
174 const PxVec3 N1 = p2b_p1b.cross(p0b_p1b);
175 const float dp0 = Set2(p0b, N1, params->mCapsuleCenter);
176
177 const PxVec3 N2 = (p2 - p1).cross(p0 - p1);
178 const float dp1 = -Set2(p0, N2, params->mCapsuleCenter);
179
180 bool directHit;
181 if(extrusionSign >= 0.0f)
182 directHit = testTri(params, p0b, p1b, p2b, N1, unitDir, capsuleRadius, dpc0, curT, status);
183 else
184 directHit = testTri(params, p0, p1, p2, N2, unitDir, capsuleRadius, dpc0, curT, status);
185
186 const PxVec3 N3 = p2b_p1b.cross(p1_p1b);
187 const float dp2 = -Set2(p1, N3, params->mCapsuleCenter);
188 if(!directHit)
189 {
190 const float dp = N3.dot(unitDir);
191 if(dp*extrusionSign>=0.0f)
192 testQuad(params, p1, p1b, p2, p2b, N3, unitDir, capsuleRadius, dpc0, curT, status);
193 }
194
195 const PxVec3 N5 = p2b_p2.cross(p0 - p2);
196 const float dp3 = -Set2(p0, N5, params->mCapsuleCenter);
197 if(!directHit)
198 {
199 const float dp = N5.dot(unitDir);
200 if(dp*extrusionSign>=0.0f)
201 testQuad(params, p2, p2b, p0, p0b, N5, unitDir, capsuleRadius, dpc0, curT, status);
202 }
203
204 const PxVec3 N7 = p1_p1b.cross(p0b_p1b);
205 const float dp4 = -Set2(p0b, N7, params->mCapsuleCenter);
206 if(!directHit)
207 {
208 const float dp = N7.dot(unitDir);
209 if(dp*extrusionSign>=0.0f)
210 testQuad(params, p0, p0b, p1, p1b, N7, unitDir, capsuleRadius, dpc0, curT, status);
211 }
212
213 if(1)
214 {
215 bool originInside = true;
216 if(extrusionSign<0.0f)
217 {
218 if(dp0<0.0f || dp1<0.0f || dp2<0.0f || dp3<0.0f || dp4<0.0f)
219 originInside = false;
220 }
221 else
222 {
223 if(dp0>0.0f || dp1>0.0f || dp2>0.0f || dp3>0.0f || dp4>0.0f)
224 originInside = false;
225 }
226 if(originInside)
227 {
228 t = 0.0f;
229 return true;
230 }
231 }
232
233 if(!status)
234 return false; // We didn't touch any triangle
235
236 t = curT;
237
238 return true;
239}
240
241// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
242static bool /*__fastcall*/ triCapsuleSweep(CapsuleSweepParams* PX_RESTRICT params, PxU32 primIndex, bool nodeSorting=true)
243{
244 PxU32 VRef0, VRef1, VRef2;
245 getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
246
247 const PxVec3& p0 = params->mVerts[VRef0];
248 const PxVec3& p1 = params->mVerts[VRef1];
249 const PxVec3& p2 = params->mVerts[VRef2];
250
251 const PxTriangle Tri(p0, p1, p2); // PT: TODO: check calls to empty ctor/dtor here (TA34704)
252
253 const bool isDoubleSided = params->mBackfaceCulling==0;
254
255 float dist;
256 PxVec3 denormalizedNormal;
257 if(sweepCapsuleVsTriangle(params, Tri, dist, isDoubleSided, denormalizedNormal))
258 {
259 denormalizedNormal.normalize();
260 const PxReal alignmentValue = computeAlignmentValue(denormalizedNormal, params->mLocalDir_Padded);
261
262 if(keepTriangle(dist, alignmentValue, params->mBestDistance, params->mBestAlignmentValue, params->mMaxDist))
263 {
264 params->mStabbedFace.mDistance = dist;
265 params->mStabbedFace.mTriangleID = primIndex;
266
267 params->mP0 = p0;
268 params->mP1 = p1;
269 params->mP2 = p2;
270
271 params->mBestDistance = PxMin(params->mBestDistance, dist); // exact lower bound
272 params->mBestAlignmentValue = alignmentValue;
273 params->mBestTriNormal = denormalizedNormal;
274
275 if(nodeSorting)
276 {
277#ifdef SWEEP_AABB_IMPL
278 #ifndef GU_BV4_USE_SLABS
279 //setupRayData(params, dist, params->mOrigin_Padded, params->mLocalDir_PaddedAligned);
280 setupRayData(params, params->mBestDistance, params->mOrigin_Padded, params->mLocalDir_PaddedAligned);
281 #endif
282#else
283 //params->ShrinkOBB(dist);
284 params->ShrinkOBB(params->mBestDistance);
285#endif
286 }
287 return true;
288 }
290 else if(keepTriangleBasic(dist, params->mBestDistance, params->mMaxDist))
291 {
292 params->mStabbedFace.mDistance = dist;
293 params->mBestDistance = PxMin(params->mBestDistance, dist); // exact lower bound
294 }
296 }
297 return false;
298}
299
300#include "GuDistanceSegmentTriangleSIMD.h"
301
302namespace
303{
304class LeafFunction_CapsuleSweepClosest
305{
306public:
307 static PX_FORCE_INLINE void doLeafTest(CapsuleSweepParams* PX_RESTRICT params, PxU32 primIndex)
308 {
309 PxU32 nbToGo = getNbPrimitives(primIndex);
310 do
311 {
312 triCapsuleSweep(params, primIndex);
313 primIndex++;
314 }while(nbToGo--);
315 }
316};
317
318class LeafFunction_CapsuleSweepAny
319{
320public:
321
322 static PX_FORCE_INLINE PxIntBool doLeafTest(CapsuleSweepParams* PX_RESTRICT params, PxU32 primIndex)
323 {
324 PxU32 nbToGo = getNbPrimitives(primIndex);
325 do
326 {
327 if(triCapsuleSweep(params, primIndex))
328 return 1;
329 primIndex++;
330 }while(nbToGo--);
331
332 return 0;
333 }
334};
335
336class ImpactFunctionCapsule
337{
338public:
339 static PX_FORCE_INLINE void computeImpact(PxVec3& impactPos, PxVec3& impactNormal, const Capsule& capsule, const PxVec3& dir, const PxReal t, const PxTrianglePadded& triangle)
340 {
341 const PxVec3 delta = dir * t;
342 const PxVec3p P0 = capsule.p0 + delta;
343 const PxVec3p P1 = capsule.p1 + delta;
344 Vec3V pointOnSeg, pointOnTri;
345 distanceSegmentTriangleSquared(
346 // PT: we use PxVec3p so it is safe to V4LoadU P0 and P1
347 V3LoadU_SafeReadW(P0), V3LoadU_SafeReadW(P1),
348 // PT: we use PxTrianglePadded so it is safe to V4LoadU the triangle vertices
349 V3LoadU_SafeReadW(triangle.verts[0]), V3LoadU_SafeReadW(triangle.verts[1]), V3LoadU_SafeReadW(triangle.verts[2]),
350 pointOnSeg, pointOnTri);
351
352 PxVec3 localImpactPos, tmp;
353 V3StoreU(pointOnTri, localImpactPos);
354 V3StoreU(pointOnSeg, tmp);
355
356 // PT: TODO: refactor with computeSphereTriImpactData (TA34704)
357 PxVec3 localImpactNormal = tmp - localImpactPos;
358 const float M = localImpactNormal.magnitude();
359 if(M<1e-3f)
360 {
361 localImpactNormal = (triangle.verts[0] - triangle.verts[1]).cross(triangle.verts[0] - triangle.verts[2]);
362 localImpactNormal.normalize();
363 }
364 else
365 localImpactNormal /= M;
366
367 impactPos = localImpactPos;
368 impactNormal = localImpactNormal;
369 }
370};
371}
372
373static void computeBoxAroundCapsule(const Capsule& capsule, Box& box, PxVec3& extrusionDir)
374{
375 // Box center = center of the two capsule's endpoints
376 box.center = capsule.computeCenter();
377
378 extrusionDir = (capsule.p0 - capsule.p1)*0.5f;
379 const PxF32 d = extrusionDir.magnitude();
380
381 // Box extents
382 box.extents.x = capsule.radius + d;
383 box.extents.y = capsule.radius;
384 box.extents.z = capsule.radius;
385
386 // Box orientation
387 if(d==0.0f)
388 {
389 box.rot = PxMat33(PxIdentity);
390 }
391 else
392 {
393 PxVec3 dir, right, up;
394 PxComputeBasisVectors(capsule.p0, capsule.p1, dir, right, up);
395 box.setAxes(dir, right, up);
396 }
397}
398
399template<class ParamsT>
400static PX_FORCE_INLINE void setupCapsuleParams(ParamsT* PX_RESTRICT params, const Capsule& capsule, const PxVec3& dir, float maxDist, const BV4Tree* PX_RESTRICT tree, const SourceMesh* PX_RESTRICT mesh, PxU32 flags)
401{
402 params->mStabbedFace.mTriangleID = PX_INVALID_U32;
403 params->mBestAlignmentValue = 2.0f;
404 params->mBestDistance = maxDist + GU_EPSILON_SAME_DISTANCE;
405 params->mMaxDist = maxDist;
406
407 setupParamsFlags(params, flags);
408
409 setupMeshPointersAndQuantizedCoeffs(params, mesh, tree);
410
411 params->mLocalCapsule = capsule;
412
413 Box localBox;
414 computeBoxAroundCapsule(capsule, localBox, params->mExtrusionDir);
415
416 params->mCapsuleCenter = localBox.center;
417
418 const PxVec3& localDir = dir;
419
420#ifdef SWEEP_AABB_IMPL
421 const PxVec3& localP0 = params->mLocalCapsule.p0;
422 const PxVec3& localP1 = params->mLocalCapsule.p1;
423 const PxVec3 sweepOrigin = (localP0+localP1)*0.5f;
424 const PxVec3 sweepExtents = PxVec3(params->mLocalCapsule.radius) + (localP0-localP1).abs()*0.5f;
425
426 #ifndef GU_BV4_USE_SLABS
427 params->mLocalDir_PaddedAligned = localDir;
428 #endif
429 params->mOrigin_Padded = sweepOrigin;
430
431 const Box aabb(sweepOrigin, sweepExtents, PxMat33(PxIdentity));
432 prepareSweepData(aabb, localDir, maxDist, params); // PT: TODO: optimize this call for idt rotation (TA34704)
433
434 #ifndef GU_BV4_USE_SLABS
435 setupRayData(params, maxDist, sweepOrigin, localDir);
436 #endif
437#else
438 prepareSweepData(localBox, localDir, maxDist, params);
439#endif
440}
441
442#endif // GU_BV4_CAPSULE_SWEEP_INTERNAL_H
PX_CUDA_CALLABLE PX_FORCE_INLINE Type magnitude() const
returns the magnitude
Definition PxVec3.h:181
PX_CUDA_CALLABLE PX_FORCE_INLINE Type dot(const PxVec3T &v) const
returns the scalar product of this and other.
Definition PxVec3.h:274
PX_CUDA_CALLABLE PX_FORCE_INLINE Type normalize()
normalizes the vector in place
Definition PxVec3.h:297
PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3T cross(const PxVec3T &v) const
cross product
Definition PxVec3.h:282
GLM_FUNC_QUALIFIER vec< 3, T, Q > cross(vec< 3, T, Q > const &x, vec< 3, T, Q > const &y)
Definition func_geometric.inl:175
#define PX_RESTRICT
Definition PxPreprocessor.h:355
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
PX_FORCE_INLINE bool keepTriangle(float triImpactDistance, float triAlignmentValue, float bestImpactDistance, float bestAlignmentValue, float maxDistance)
Definition GuInternal.h:110
PX_FORCE_INLINE PxReal computeAlignmentValue(const PxVec3 &triNormal, const PxVec3 &unitDir)
Definition GuInternal.h:88
bool sweepSphereVSTri(const PxVec3 *PX_RESTRICT triVerts, const PxVec3 &triUnitNormal, const PxVec3 &sphereCenter, PxReal sphereRadius, const PxVec3 &unitDir, PxReal &impactDistance, bool &directHit, bool testInitialOverlap)
Definition GuSweepSphereTriangle.cpp:203
void computeBoxAroundCapsule(const Capsule &capsule, Box &box)
Definition GuCapsule.cpp:40
PX_INLINE void PxComputeBasisVectors(const PxVec3 &dir, PxVec3 &right, PxVec3 &up)
Compute two normalized vectors (right and up) that are perpendicular to an input normalized vector (d...
Definition PxMathUtils.h:271
PX_CUDA_CALLABLE PX_FORCE_INLINE T PxMax(T a, T b)
The return value is the greater of the two specified values.
Definition PxMath.h:72
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