RavEngine
Loading...
Searching...
No Matches
GuBV4_Common.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_COMMON_H
30#define GU_BV4_COMMON_H
31
32#include "foundation/PxMat44.h"
33#include "geometry/PxTriangle.h"
34#include "GuBox.h"
35#include "GuSphere.h"
36#include "GuCapsule.h"
37#include "GuBV4.h"
38
39#define BV4_ALIGN16(x) PX_ALIGN_PREFIX(16) x PX_ALIGN_SUFFIX(16)
40
41namespace physx
42{
43namespace Gu
44{
45 enum QueryModifierFlag
46 {
47 QUERY_MODIFIER_ANY_HIT = (1<<0),
48 QUERY_MODIFIER_DOUBLE_SIDED = (1<<1),
49 QUERY_MODIFIER_MESH_BOTH_SIDES = (1<<2)
50 };
51
52 template<class ParamsT>
53 PX_FORCE_INLINE void setupParamsFlags(ParamsT* PX_RESTRICT params, PxU32 flags)
54 {
55 params->mBackfaceCulling = (flags & (QUERY_MODIFIER_DOUBLE_SIDED|QUERY_MODIFIER_MESH_BOTH_SIDES)) ? 0 : 1u;
56 params->mEarlyExit = flags & QUERY_MODIFIER_ANY_HIT;
57 }
58
60 {
63 HIT_EXIT = 2
64 };
65
67 {
68 public:
71
72 float mDistance;
73 PxU32 mTriangleID;
74 };
75
77 {
78 public:
81
83 float mDistance;
84
85 PxVec3 mPos;
86 PxVec3 mNormal;
87 };
88
89 typedef HitCode (*MeshRayCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, float dist, float u, float v);
90 typedef bool (*MeshOverlapCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, const PxU32* vertexIndices);
91 typedef bool (*TetMeshOverlapCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& p3, PxU32 tetIndex, const PxU32* vertexIndices);
92 typedef bool (*MeshSweepCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, /*const PxU32* vertexIndices,*/ float& dist);
93 typedef bool (*SweepUnlimitedCallback) (void* userData, const SweepHit& hit);
94
95 template<class ParamsT>
96 PX_FORCE_INLINE void reportUnlimitedCallbackHit(ParamsT* PX_RESTRICT params, const SweepHit& hit)
97 {
98 // PT: we can't reuse the MeshSweepCallback here since it's designed for doing the sweep test inside the callback
99 // (in the user's code) rather than inside the traversal code. So we use the SweepUnlimitedCallback instead to
100 // report the already fully computed hit to users.
101 // PT: TODO: this may not be very efficient, since computing the full hit is expensive. If we use this codepath
102 // to implement the Epic Tweak, the resulting code will not be optimal.
103 (params->mCallback)(params->mUserData, hit);
104
105 // PT: the existing traversal code already shrunk the ray. For real "sweep all" calls we must undo that by reseting the max dist.
106 // (params->mStabbedFace.mDistance is used in computeImpactDataX code, so we need it before that point - we can't simply avoid
107 // modifying this value before this point).
108 if(!params->mNodeSorting)
109 params->mStabbedFace.mDistance = params->mMaxDist;
110 }
111
112 PX_FORCE_INLINE void invertPRMatrix(PxMat44* PX_RESTRICT dest, const PxMat44* PX_RESTRICT src)
113 {
114 const float m30 = src->column3.x;
115 const float m31 = src->column3.y;
116 const float m32 = src->column3.z;
117
118 const float m00 = src->column0.x;
119 const float m01 = src->column0.y;
120 const float m02 = src->column0.z;
121
122 dest->column0.x = m00;
123 dest->column1.x = m01;
124 dest->column2.x = m02;
125 dest->column3.x = -(m30*m00 + m31*m01 + m32*m02);
126
127 const float m10 = src->column1.x;
128 const float m11 = src->column1.y;
129 const float m12 = src->column1.z;
130
131 dest->column0.y = m10;
132 dest->column1.y = m11;
133 dest->column2.y = m12;
134 dest->column3.y = -(m30*m10 + m31*m11 + m32*m12);
135
136 const float m20 = src->column2.x;
137 const float m21 = src->column2.y;
138 const float m22 = src->column2.z;
139
140 dest->column0.z = m20;
141 dest->column1.z = m21;
142 dest->column2.z = m22;
143 dest->column3.z = -(m30*m20 + m31*m21 + m32*m22);
144
145 dest->column0.w = 0.0f;
146 dest->column1.w = 0.0f;
147 dest->column2.w = 0.0f;
148 dest->column3.w = 1.0f;
149 }
150
151 PX_FORCE_INLINE void invertBoxMatrix(PxMat33& m, PxVec3& t, const Gu::Box& box)
152 {
153 const float m30 = box.center.x;
154 const float m31 = box.center.y;
155 const float m32 = box.center.z;
156
157 const float m00 = box.rot.column0.x;
158 const float m01 = box.rot.column0.y;
159 const float m02 = box.rot.column0.z;
160
161 m.column0.x = m00;
162 m.column1.x = m01;
163 m.column2.x = m02;
164 t.x = -(m30*m00 + m31*m01 + m32*m02);
165
166 const float m10 = box.rot.column1.x;
167 const float m11 = box.rot.column1.y;
168 const float m12 = box.rot.column1.z;
169
170 m.column0.y = m10;
171 m.column1.y = m11;
172 m.column2.y = m12;
173 t.y = -(m30*m10 + m31*m11 + m32*m12);
174
175 const float m20 = box.rot.column2.x;
176 const float m21 = box.rot.column2.y;
177 const float m22 = box.rot.column2.z;
178
179 m.column0.z = m20;
180 m.column1.z = m21;
181 m.column2.z = m22;
182 t.z = -(m30*m20 + m31*m21 + m32*m22);
183 }
184
185#ifdef GU_BV4_USE_SLABS
186 // PT: this class moved here to make things compile with pedantic compilers.
187
188 // PT: now duplicated because not easy to do otherwise
189
191 {
192 struct Data
193 {
194 PxI16 mMin;
195 PxI16 mMax;
196 };
197
198 Data mX[4];
199 Data mY[4];
200 Data mZ[4];
201
202 PxU32 mData[4];
203
204 PX_FORCE_INLINE PxU32 isLeaf(PxU32 i) const { return mData[i]&1; }
205 PX_FORCE_INLINE PxU32 getPrimitive(PxU32 i) const { return mData[i]>>1; }
206 PX_FORCE_INLINE PxU32 getChildOffset(PxU32 i) const { return mData[i]>>GU_BV4_CHILD_OFFSET_SHIFT_COUNT; }
207 PX_FORCE_INLINE PxU32 getChildType(PxU32 i) const { return (mData[i]>>1)&3; }
208 PX_FORCE_INLINE PxU32 getChildData(PxU32 i) const { return mData[i]; }
209 PX_FORCE_INLINE PxU32 decodePNSNoShift(PxU32 i) const { return mData[i]; }
210 };
211
213 {
214 float mMinX[4];
215 float mMinY[4];
216 float mMinZ[4];
217 float mMaxX[4];
218 float mMaxY[4];
219 float mMaxZ[4];
220
221 PxU32 mData[4];
222
223 PX_FORCE_INLINE PxU32 isLeaf(PxU32 i) const { return mData[i]&1; }
224 PX_FORCE_INLINE PxU32 getPrimitive(PxU32 i) const { return mData[i]>>1; }
225 PX_FORCE_INLINE PxU32 getChildOffset(PxU32 i) const { return mData[i]>>GU_BV4_CHILD_OFFSET_SHIFT_COUNT; }
226 PX_FORCE_INLINE PxU32 getChildType(PxU32 i) const { return (mData[i]>>1)&3; }
227 PX_FORCE_INLINE PxU32 getChildData(PxU32 i) const { return mData[i]; }
228 PX_FORCE_INLINE PxU32 decodePNSNoShift(PxU32 i) const { return mData[i]; }
229 };
230
231#else
232 #define SSE_CONST4(name, val) static const __declspec(align(16)) PxU32 name[4] = { (val), (val), (val), (val) }
233 #define SSE_CONST(name) *(const __m128i *)&name
234 #define SSE_CONSTF(name) *(const __m128 *)&name
235#endif
236
237 PX_FORCE_INLINE PxU32 getNbPrimitives(PxU32& primIndex)
238 {
239 PxU32 NbToGo = (primIndex & 15)-1;
240 primIndex>>=4;
241 return NbToGo;
242 }
243
244 template<class ParamsT>
245 PX_FORCE_INLINE void setupMeshPointersAndQuantizedCoeffs(ParamsT* PX_RESTRICT params, const SourceMesh* PX_RESTRICT mesh, const BV4Tree* PX_RESTRICT tree)
246 {
247 using namespace physx::aos;
248
249 params->mTris32 = mesh->getTris32();
250 params->mTris16 = mesh->getTris16();
251 params->mVerts = mesh->getVerts();
252
253 V4StoreA_Safe(V4LoadU_Safe(&tree->mCenterOrMinCoeff.x), &params->mCenterOrMinCoeff_PaddedAligned.x);
254 V4StoreA_Safe(V4LoadU_Safe(&tree->mExtentsOrMaxCoeff.x), &params->mExtentsOrMaxCoeff_PaddedAligned.x);
255 }
256
257 template<class ParamsT>
258 PX_FORCE_INLINE void setupMeshPointersAndQuantizedCoeffs(ParamsT* PX_RESTRICT params, const TetrahedronSourceMesh* PX_RESTRICT mesh, const BV4Tree* PX_RESTRICT tree)
259 {
260 params->mTets32 = mesh->getTetrahedrons32();
261 params->mTets16 = mesh->getTetrahedrons16();
262 params->mVerts = mesh->getVerts();
263
264 V4StoreA_Safe(V4LoadU_Safe(&tree->mCenterOrMinCoeff.x), &params->mCenterOrMinCoeff_PaddedAligned.x);
265 V4StoreA_Safe(V4LoadU_Safe(&tree->mExtentsOrMaxCoeff.x), &params->mExtentsOrMaxCoeff_PaddedAligned.x);
266 }
267
268 PX_FORCE_INLINE void rotateBox(Gu::Box& dst, const PxMat44& m, const Gu::Box& src)
269 {
270 // The extents remain constant
271 dst.extents = src.extents;
272 // The center gets x-formed
273 dst.center = m.transform(src.center);
274 // Combine rotations
275 // PT: TODO: revisit.. this is awkward... grab 3x3 part of 4x4 matrix (TA34704)
276 const PxMat33 tmp( PxVec3(m.column0.x, m.column0.y, m.column0.z),
277 PxVec3(m.column1.x, m.column1.y, m.column1.z),
278 PxVec3(m.column2.x, m.column2.y, m.column2.z));
279 dst.rot = tmp * src.rot;
280 }
281
282 PX_FORCE_INLINE PxVec3 inverseRotate(const PxMat44* PX_RESTRICT src, const PxVec3& p)
283 {
284 const float m00 = src->column0.x;
285 const float m01 = src->column0.y;
286 const float m02 = src->column0.z;
287
288 const float m10 = src->column1.x;
289 const float m11 = src->column1.y;
290 const float m12 = src->column1.z;
291
292 const float m20 = src->column2.x;
293 const float m21 = src->column2.y;
294 const float m22 = src->column2.z;
295
296 return PxVec3( m00*p.x + m01*p.y + m02*p.z,
297 m10*p.x + m11*p.y + m12*p.z,
298 m20*p.x + m21*p.y + m22*p.z);
299 }
300
301 PX_FORCE_INLINE PxVec3 inverseTransform(const PxMat44* PX_RESTRICT src, const PxVec3& p)
302 {
303 const float m30 = src->column3.x;
304 const float m31 = src->column3.y;
305 const float m32 = src->column3.z;
306
307 const float m00 = src->column0.x;
308 const float m01 = src->column0.y;
309 const float m02 = src->column0.z;
310
311 const float m10 = src->column1.x;
312 const float m11 = src->column1.y;
313 const float m12 = src->column1.z;
314
315 const float m20 = src->column2.x;
316 const float m21 = src->column2.y;
317 const float m22 = src->column2.z;
318
319 return PxVec3( m00*p.x + m01*p.y + m02*p.z -(m30*m00 + m31*m01 + m32*m02),
320 m10*p.x + m11*p.y + m12*p.z -(m30*m10 + m31*m11 + m32*m12),
321 m20*p.x + m21*p.y + m22*p.z -(m30*m20 + m31*m21 + m32*m22));
322 }
323
324 PX_FORCE_INLINE void computeLocalRay(PxVec3& localDir, PxVec3& localOrigin, const PxVec3& dir, const PxVec3& origin, const PxMat44* PX_RESTRICT worldm_Aligned)
325 {
326 if(worldm_Aligned)
327 {
328 localDir = inverseRotate(worldm_Aligned, dir);
329 localOrigin = inverseTransform(worldm_Aligned, origin);
330 }
331 else
332 {
333 localDir = dir;
334 localOrigin = origin;
335 }
336 }
337
338 PX_FORCE_INLINE void computeLocalSphere(float& radius2, PxVec3& local_center, const Sphere& sphere, const PxMat44* PX_RESTRICT worldm_Aligned)
339 {
340 radius2 = sphere.radius * sphere.radius;
341 if(worldm_Aligned)
342 {
343 local_center = inverseTransform(worldm_Aligned, sphere.center);
344 }
345 else
346 {
347 local_center = sphere.center;
348 }
349 }
350
351 PX_FORCE_INLINE void computeLocalCapsule(Capsule& localCapsule, const Capsule& capsule, const PxMat44* PX_RESTRICT worldm_Aligned)
352 {
353 localCapsule.radius = capsule.radius;
354 if(worldm_Aligned)
355 {
356 localCapsule.p0 = inverseTransform(worldm_Aligned, capsule.p0);
357 localCapsule.p1 = inverseTransform(worldm_Aligned, capsule.p1);
358 }
359 else
360 {
361 localCapsule.p0 = capsule.p0;
362 localCapsule.p1 = capsule.p1;
363 }
364 }
365
366 PX_FORCE_INLINE void computeLocalBox(Gu::Box& dst, const Gu::Box& src, const PxMat44* PX_RESTRICT worldm_Aligned)
367 {
368 if(worldm_Aligned)
369 {
370 PxMat44 invWorldM;
371 invertPRMatrix(&invWorldM, worldm_Aligned);
372
373 rotateBox(dst, invWorldM, src);
374 }
375 else
376 {
377 dst = src; // PT: TODO: check asm for operator= (TA34704)
378 }
379 }
380
381 template<class ImpactFunctionT, class ShapeT, class ParamsT>
382 static PX_FORCE_INLINE bool computeImpactDataT(const ShapeT& shape, const PxVec3& dir, SweepHit* PX_RESTRICT hit, const ParamsT* PX_RESTRICT params, const PxMat44* PX_RESTRICT worldm, bool isDoubleSided, bool meshBothSides)
383 {
384 if(params->mStabbedFace.mTriangleID==PX_INVALID_U32)
385 return false; // We didn't touch any triangle
386
387 if(hit)
388 {
389 const float t = params->getReportDistance();
390 hit->mTriangleID = params->mStabbedFace.mTriangleID;
391 hit->mDistance = t;
392
393 if(t==0.0f)
394 {
395 hit->mPos = PxVec3(0.0f);
396 hit->mNormal = -dir;
397 }
398 else
399 {
400 // PT: TODO: we shouldn't compute impact in world space, and in fact moving this to local space is necessary if we want to reuse this for box-sweeps (TA34704)
402 if(worldm)
403 {
404 WP.verts[0] = worldm->transform(params->mP0);
405 WP.verts[1] = worldm->transform(params->mP1);
406 WP.verts[2] = worldm->transform(params->mP2);
407 }
408 else
409 {
410 WP.verts[0] = params->mP0;
411 WP.verts[1] = params->mP1;
412 WP.verts[2] = params->mP2;
413 }
414
415 PxVec3 impactNormal;
416 ImpactFunctionT::computeImpact(hit->mPos, impactNormal, shape, dir, t, WP);
417
418 // PT: by design, returned normal is opposed to the sweep direction.
419 if(shouldFlipNormal(impactNormal, meshBothSides, isDoubleSided, params->mBestTriNormal, dir))
420 impactNormal = -impactNormal;
421
422 hit->mNormal = impactNormal;
423 }
424 }
425 return true;
426 }
427
428 // PT: we don't create a structure for small meshes with just a few triangles. We use brute-force tests on these.
429 template<class LeafFunction_AnyT, class LeafFunction_ClosestT, class ParamsT>
430 void doBruteForceTests(PxU32 nbTris, ParamsT* PX_RESTRICT params)
431 {
432 PX_ASSERT(nbTris<16);
433 if(params->mEarlyExit)
434 LeafFunction_AnyT::doLeafTest(params, nbTris);
435 else
436 LeafFunction_ClosestT::doLeafTest(params, nbTris);
437 }
438
439#ifndef GU_BV4_USE_SLABS
440 template<class ParamsT>
441 PX_FORCE_INLINE void setupRayData(ParamsT* PX_RESTRICT params, float max_dist, const PxVec3& origin, const PxVec3& dir)
442 {
443 const float Half = 0.5f*max_dist;
444 const FloatV HalfV = FLoad(Half);
445 const Vec4V DataV = V4Scale(V4LoadU(&dir.x), HalfV);
446 const Vec4V Data2V = V4Add(V4LoadU(&origin.x), DataV);
447 const Vec4V FDirV = V4Abs(DataV);
448 V4StoreA_Safe(DataV, &params->mData_PaddedAligned.x);
449 V4StoreA_Safe(Data2V, &params->mData2_PaddedAligned.x);
450 V4StoreA_Safe(FDirV, &params->mFDir_PaddedAligned.x);
451 }
452#endif
453
454}
455}
456
457#endif // GU_BV4_COMMON_H
Definition GuBV4.h:341
Represents an oriented bounding box.
Definition GuBox.h:72
Represents a capsule.
Definition GuCapsule.h:47
Definition GuBV4_Common.h:67
PxVec3 p0
Start of segment.
Definition GuSegment.h:170
PxVec3 p1
End of segment.
Definition GuSegment.h:171
Definition GuBV4.h:181
Definition GuSphere.h:46
Definition GuBV4_Common.h:77
PxU32 mTriangleID
Index of touched face.
Definition GuBV4_Common.h:82
float mDistance
Impact distance.
Definition GuBV4_Common.h:83
Definition GuBV4.h:230
3x3 matrix class
Definition PxMat33.h:91
4x4 matrix class
Definition PxMat44.h:55
PX_CUDA_CALLABLE PX_INLINE const PxVec4 transform(const PxVec4 &other) const
Transform vector by matrix, equal to v' = M*v.
Definition PxMat44.h:279
A padded version of PxTriangle, to safely load its data using SIMD.
Definition PxTriangle.h:145
PxVec3 verts[3]
Array of Vertices.
Definition PxTriangle.h:140
Definition PxUserAllocated.h:43
3 Element vector class.
Definition PxVec3.h:50
#define PX_RESTRICT
Definition PxPreprocessor.h:355
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
HitCode
Definition GuBV4_Common.h:60
@ HIT_NONE
No hit.
Definition GuBV4_Common.h:61
@ HIT_CONTINUE
Hit found, but keep looking for closer one.
Definition GuBV4_Common.h:62
@ HIT_EXIT
Hit found, you can early-exit (raycast any)
Definition GuBV4_Common.h:63
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
Definition GuBV4_Common.h:213
Definition GuBV4_Common.h:193
PxI16 mMax
Quantized max.
Definition GuBV4_Common.h:195
PxI16 mMin
Quantized min.
Definition GuBV4_Common.h:194
Definition GuBV4_Common.h:191
Definition PxVecMathAoSScalar.h:52
Definition PxVecMathAoSScalar.h:65