RavEngine
Loading...
Searching...
No Matches
GuQuerySystem.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_QUERY_SYSTEM_H
30#define GU_QUERY_SYSTEM_H
31
32#include "foundation/PxUserAllocated.h"
33#include "foundation/PxBitMap.h"
34#include "foundation/PxArray.h"
35#include "foundation/PxMutex.h"
36#include "foundation/PxBounds3.h"
37#include "GuPruner.h"
38#include "GuActorShapeMap.h"
39
40namespace physx
41{
42 class PxGeometry;
43
44namespace Gu
45{
46 class BVH;
47
48 class Adapter
49 {
50 public:
51 Adapter() {}
52 virtual ~Adapter() {}
53
54 virtual const PxGeometry& getGeometry(const PrunerPayload& payload) const = 0;
55 };
56
58 {
59 public:
60 PrunerFilter() {}
61 virtual ~PrunerFilter() {}
62
63 virtual bool processPruner(PxU32 prunerIndex/*, const PxQueryThreadContext* context*/) const = 0;
64 };
65
66 typedef PxU32 PrunerInfo;
67 PX_FORCE_INLINE PrunerInfo createPrunerInfo(PxU32 prunerIndex, bool isDynamic) { return (prunerIndex << 1) | PxU32(isDynamic); }
68 PX_FORCE_INLINE PxU32 getPrunerIndex(PrunerInfo info) { return PxU32(info)>>1; }
69 PX_FORCE_INLINE PxU32 getDynamic(PrunerInfo info) { return PxU32(info) & 1; }
70
71 PX_FORCE_INLINE ActorShapeData createActorShapeData(PrunerInfo info, PrunerHandle h) { return (ActorShapeData(h) << 32) | ActorShapeData(info); }
72 PX_FORCE_INLINE PrunerInfo getPrunerInfo(ActorShapeData data) { return PrunerInfo(data); }
73 PX_FORCE_INLINE PrunerHandle getPrunerHandle(ActorShapeData data) { return PrunerHandle(data >> 32); }
74
75 #define INVALID_ACTOR_SHAPE_DATA PxU64(-1)
76
78 {
79 public: // PT: TODO: public only to implement checkPrunerIndex easily, revisit this
80 struct PrunerExt : public PxUserAllocated
81 {
82 PrunerExt(Pruner* pruner, PxU32 preallocated);
83 ~PrunerExt();
84
85 void flushMemory();
86
87 void addToDirtyList(PrunerHandle handle, PxU32 dynamic, const PxTransform& transform, const PxBounds3* userBounds=NULL);
88 void removeFromDirtyList(PrunerHandle handle);
89 bool processDirtyList(const Adapter& adapter, float inflation);
90
91 Pruner* mPruner;
92 PxBitMap mDirtyMap;
93 PxArray<PrunerHandle> mDirtyList;
94 PxU32 mNbStatic; // nb static objects in pruner
95 PxU32 mNbDynamic; // nb dynamic objects in pruner
96 bool mDirtyStatic; // true if dirty list contains a static
97
98 struct Data
99 {
100 PxTransform mPose;
101 PxBounds3 mBounds;
102 };
103 PxArray<Data> mDirtyData;
104
105 PX_NOCOPY(PrunerExt)
106 };
107
108 public:
109 PX_PHYSX_COMMON_API QuerySystem(PxU64 contextID, float inflation, const Adapter& adapter, bool usesTreeOfPruners=false);
110 PX_PHYSX_COMMON_API ~QuerySystem();
111
112 PX_FORCE_INLINE PxU64 getContextId() const { return mContextID; }
113 PX_FORCE_INLINE const Adapter& getAdapter() const { return mAdapter; }
114 PX_FORCE_INLINE PxU32 getStaticTimestamp() const { return mStaticTimestamp; }
115
116 PX_PHYSX_COMMON_API PxU32 addPruner(Pruner* pruner, PxU32 preallocated);
117 PX_PHYSX_COMMON_API void removePruner(PxU32 prunerIndex);
118 PX_FORCE_INLINE PxU32 getNbPruners() const { return mPrunerExt.size(); }
119 PX_FORCE_INLINE const Pruner* getPruner(PxU32 index) const { return mPrunerExt[index]->mPruner; }
120 PX_FORCE_INLINE Pruner* getPruner(PxU32 index) { return mPrunerExt[index]->mPruner; }
121
122 PX_PHYSX_COMMON_API ActorShapeData addPrunerShape(const PrunerPayload& payload, PxU32 prunerIndex, bool dynamic, const PxTransform& transform, const PxBounds3* userBounds=NULL);
123 PX_PHYSX_COMMON_API void removePrunerShape(ActorShapeData data, PrunerPayloadRemovalCallback* removalCallback);
124 PX_PHYSX_COMMON_API void updatePrunerShape(ActorShapeData data, bool immediately, const PxTransform& transform, const PxBounds3* userBounds=NULL);
125
126 PX_PHYSX_COMMON_API const PrunerPayload& getPayloadData(ActorShapeData data, PrunerPayloadData* ppd=NULL) const;
127
128 PX_PHYSX_COMMON_API void commitUpdates();
129 PX_PHYSX_COMMON_API void update(bool buildStep, bool commit);
130 PX_PHYSX_COMMON_API void sync(PxU32 prunerIndex, const PrunerHandle* handles, const PxU32* boundsIndices, const PxBounds3* bounds, const PxTransform32* transforms, PxU32 count);
131
132 PX_PHYSX_COMMON_API void flushMemory();
133
134 PX_PHYSX_COMMON_API void raycast(const PxVec3& origin, const PxVec3& unitDir, float& inOutDistance, PrunerRaycastCallback& cb, const PrunerFilter* prunerFilter) const;
135 PX_PHYSX_COMMON_API void overlap(const ShapeData& queryVolume, PrunerOverlapCallback& cb, const PrunerFilter* prunerFilter) const;
136 PX_PHYSX_COMMON_API void sweep(const ShapeData& queryVolume, const PxVec3& unitDir, float& inOutDistance, PrunerRaycastCallback& cb, const PrunerFilter* prunerFilter) const;
137
138 PxU32 startCustomBuildstep();
139 void customBuildstep(PxU32 index);
140 void finishCustomBuildstep();
141
142 void createTreeOfPruners();
143 private:
144 const Adapter& mAdapter;
145 PxArray<PrunerExt*> mPrunerExt;
146 PxArray<PxU32> mDirtyPruners;
147 PxArray<PxU32> mFreePruners;
148
149 Gu::BVH* mTreeOfPruners;
150
151 const PxU64 mContextID;
152 PxU32 mStaticTimestamp;
153 const float mInflation; // SQ_PRUNER_EPSILON
154
155 PxMutex mSQLock; // to make sure only one query updates the dirty pruner structure if multiple queries run in parallel
156
157 volatile bool mPrunerNeedsUpdating;
158 volatile bool mTimestampNeedsUpdating;
159 const bool mUsesTreeOfPruners;
160
161 void processDirtyLists();
162 PX_FORCE_INLINE void invalidateStaticTimestamp() { mStaticTimestamp++; }
163
164 PX_NOCOPY(QuerySystem)
165 };
166}
167}
168
169
170#include "geometry/PxGeometryHit.h"
171#include "geometry/PxSphereGeometry.h"
172#include "geometry/PxCapsuleGeometry.h"
173#include "geometry/PxBoxGeometry.h"
174#include "geometry/PxConvexMeshGeometry.h"
175#include "GuCachedFuncs.h"
176#include "GuCapsule.h"
177#include "GuBounds.h"
178
179#if PX_VC
180#pragma warning(disable: 4355 ) // "this" used in base member initializer list
181#endif
182
183namespace physx
184{
185namespace Gu
186{
187 // PT: TODO: use templates instead of v-calls?
188
189 // PT: we decouple the filter callback from the rest, so that the same filter callback can easily be reused for all pruner queries.
190 // This combines the pre-filter callback and fetching the payload's geometry in a single call. Return null to ignore that object.
192 {
193 virtual ~PrunerFilterCallback() {}
194
195 // Query's hit flags can be tweaked per object. (Note that 'hitFlags' is unused for overlaps though)
196 virtual const PxGeometry* validatePayload(const PrunerPayload& payload, PxHitFlags& hitFlags) = 0;
197 };
198
200 {
201 PxRaycastThreadContext* mContext;
202 PrunerFilterCallback& mFilterCB;
203 const GeomRaycastTable& mCachedRaycastFuncs;
204 const PxVec3& mOrigin;
205 const PxVec3& mDir;
206 PxGeomRaycastHit* mLocalHits;
207 const PxU32 mMaxLocalHits;
208 const PxHitFlags mHitFlags;
209 PxGeomRaycastHit mClosestHit;
210 PrunerPayload mClosestPayload;
211 bool mFoundHit;
212 const bool mAnyHit;
213
214 DefaultPrunerRaycastCallback(PrunerFilterCallback& filterCB, const GeomRaycastTable& funcs, const PxVec3& origin, const PxVec3& dir, float distance, PxU32 maxLocalHits, PxGeomRaycastHit* localHits, PxHitFlags hitFlags, bool anyHit, PxRaycastThreadContext* context=NULL) :
215 mContext (context ? context : this),
216 mFilterCB (filterCB),
217 mCachedRaycastFuncs (funcs),
218 mOrigin (origin),
219 mDir (dir),
220 mLocalHits (localHits),
221 mMaxLocalHits (maxLocalHits),
222 mHitFlags (hitFlags),
223 mFoundHit (false),
224 mAnyHit (anyHit)
225 {
226 mClosestHit.distance = distance;
227 }
228
229 virtual bool reportHits(const PrunerPayload& /*payload*/, PxU32 /*nbHits*/, PxGeomRaycastHit* /*hits*/)
230 {
231 return true;
232 }
233
234 virtual bool invoke(PxReal& aDist, PxU32 primIndex, const PrunerPayload* payloads, const PxTransform* transforms)
235 {
236 PX_ASSERT(payloads && transforms);
237
238 const PrunerPayload& payload = payloads[primIndex];
239
240 PxHitFlags filteredHitFlags = mHitFlags;
241 const PxGeometry* shapeGeom = mFilterCB.validatePayload(payload, filteredHitFlags);
242 if(!shapeGeom)
243 return true;
244
245 const RaycastFunc func = mCachedRaycastFuncs[shapeGeom->getType()];
246 const PxU32 nbHits = func(*shapeGeom, transforms[primIndex], mOrigin, mDir, aDist, filteredHitFlags, mMaxLocalHits, mLocalHits, sizeof(PxGeomRaycastHit), mContext);
247 if(!nbHits || !reportHits(payload, nbHits, mLocalHits))
248 return true;
249
250 const PxGeomRaycastHit& localHit = mLocalHits[0];
251 if(localHit.distance < mClosestHit.distance)
252 {
253 mFoundHit = true;
254 if(mAnyHit)
255 return false;
256
257 aDist = localHit.distance;
258 mClosestHit = localHit;
259 mClosestPayload = payload;
260 }
261 return true;
262 }
263
265 };
266
268 {
269 PxGeomRaycastHit mLocalHit;
270
271 DefaultPrunerRaycastAnyCallback(PrunerFilterCallback& filterCB, const GeomRaycastTable& funcs, const PxVec3& origin, const PxVec3& dir, float distance) :
272 DefaultPrunerRaycastCallback (filterCB, funcs, origin, dir, distance, 1, &mLocalHit, PxHitFlag::eANY_HIT, true) {}
273 };
274
276 {
277 PxGeomRaycastHit mLocalHit;
278
279 DefaultPrunerRaycastClosestCallback(PrunerFilterCallback& filterCB, const GeomRaycastTable& funcs, const PxVec3& origin, const PxVec3& dir, float distance, PxHitFlags hitFlags) :
280 DefaultPrunerRaycastCallback (filterCB, funcs, origin, dir, distance, 1, &mLocalHit, hitFlags, false) {}
281 };
282
284 {
285 PxOverlapThreadContext* mContext;
286 PrunerFilterCallback& mFilterCB;
287 const GeomOverlapTable* mCachedFuncs;
288 const PxGeometry& mGeometry;
289 const PxTransform& mPose;
290 PxHitFlags mUnused;
291
292 DefaultPrunerOverlapCallback(PrunerFilterCallback& filterCB, const GeomOverlapTable* funcs, const PxGeometry& geometry, const PxTransform& pose, PxOverlapThreadContext* context=NULL) :
293 mContext (context ? context : this),
294 mFilterCB (filterCB),
295 mCachedFuncs (funcs),
296 mGeometry (geometry),
297 mPose (pose)
298 {
299 }
300
301 virtual bool reportHit(const PrunerPayload& /*payload*/)
302 {
303 return true;
304 }
305
306 virtual bool invoke(PxU32 primIndex, const PrunerPayload* payloads, const PxTransform* transforms)
307 {
308 PX_ASSERT(payloads && transforms);
309
310 const PrunerPayload& payload = payloads[primIndex];
311
312 const PxGeometry* shapeGeom = mFilterCB.validatePayload(payload, mUnused);
313 if(!shapeGeom || !Gu::overlap(mGeometry, mPose, *shapeGeom, transforms[primIndex], mCachedFuncs, mContext))
314 return true;
315
316 return reportHit(payload);
317 }
318
320 };
321
323 {
324 static PX_FORCE_INLINE PxU32 sweep( const GeomSweepFuncs& sf, const PxGeometry& geom, const PxTransform& pose,
325 const PxGeometry& queryGeom, const PxTransform& queryPose, const ShapeData& queryVolume,
326 const PxVec3& unitDir, PxReal distance, PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation, PxSweepThreadContext* context)
327 {
328 PX_ASSERT(queryGeom.getType()==PxGeometryType::eBOX);
329 const bool precise = hitFlags & PxHitFlag::ePRECISE_SWEEP;
330 const SweepBoxFunc func = precise ? sf.preciseBoxMap[geom.getType()] : sf.boxMap[geom.getType()];
331 return PxU32(func(geom, pose, static_cast<const PxBoxGeometry&>(queryGeom), queryPose, queryVolume.getGuBox(), unitDir, distance, sweepHit, hitFlags, inflation, context));
332 }
333 };
334
336 {
337 static PX_FORCE_INLINE PxU32 sweep( const GeomSweepFuncs& sf, const PxGeometry& geom, const PxTransform& pose,
338 const PxGeometry& queryGeom, const PxTransform& queryPose, const ShapeData& /*queryVolume*/,
339 const PxVec3& unitDir, PxReal distance, PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation, PxSweepThreadContext* context)
340 {
341 PX_ASSERT(queryGeom.getType()==PxGeometryType::eSPHERE);
342 // PT: we don't use sd.getGuSphere() here because PhysX doesn't expose a set of 'SweepSphereFunc' functions,
343 // we have to go through a capsule (which is then seen as a sphere internally when the half-length is zero).
344 const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(queryGeom);
345 const PxCapsuleGeometry capsuleGeom(sphereGeom.radius, 0.0f);
346 const Capsule worldCapsule(queryPose.p, queryPose.p, sphereGeom.radius); // AP: precompute?
347 const bool precise = hitFlags & PxHitFlag::ePRECISE_SWEEP;
348 const SweepCapsuleFunc func = precise ? sf.preciseCapsuleMap[geom.getType()] : sf.capsuleMap[geom.getType()];
349 return PxU32(func(geom, pose, capsuleGeom, queryPose, worldCapsule, unitDir, distance, sweepHit, hitFlags, inflation, context));
350 }
351 };
352
354 {
355 static PX_FORCE_INLINE PxU32 sweep( const GeomSweepFuncs& sf, const PxGeometry& geom, const PxTransform& pose,
356 const PxGeometry& queryGeom, const PxTransform& queryPose, const ShapeData& queryVolume,
357 const PxVec3& unitDir, PxReal distance, PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation, PxSweepThreadContext* context)
358 {
359 PX_ASSERT(queryGeom.getType()==PxGeometryType::eCAPSULE);
360 const bool precise = hitFlags & PxHitFlag::ePRECISE_SWEEP;
361 const SweepCapsuleFunc func = precise ? sf.preciseCapsuleMap[geom.getType()] : sf.capsuleMap[geom.getType()];
362 return PxU32(func(geom, pose, static_cast<const PxCapsuleGeometry&>(queryGeom), queryPose, queryVolume.getGuCapsule(), unitDir, distance, sweepHit, hitFlags, inflation, context));
363 }
364 };
365
367 {
368 static PX_FORCE_INLINE PxU32 sweep( const GeomSweepFuncs& sf, const PxGeometry& geom, const PxTransform& pose,
369 const PxGeometry& queryGeom, const PxTransform& queryPose, const ShapeData& /*queryVolume*/,
370 const PxVec3& unitDir, PxReal distance, PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation, PxSweepThreadContext* context)
371 {
372 PX_ASSERT(queryGeom.getType()==PxGeometryType::eCONVEXMESH);
373 const SweepConvexFunc func = sf.convexMap[geom.getType()];
374 return PxU32(func(geom, pose, static_cast<const PxConvexMeshGeometry&>(queryGeom), queryPose, unitDir, distance, sweepHit, hitFlags, inflation, context));
375 }
376 };
377
379 {
380 virtual bool reportHit(const PrunerPayload& /*payload*/, PxGeomSweepHit& /*hit*/)
381 {
382 return true;
383 }
384 };
385
386 template<class ShapeCast>
388 {
389 PxSweepThreadContext* mContext;
390 PrunerFilterCallback& mFilterCB;
391 const GeomSweepFuncs& mCachedFuncs;
392 const PxGeometry& mGeometry;
393 const PxTransform& mPose;
394 const ShapeData& mQueryVolume;
395 const PxVec3& mDir;
396 PxGeomSweepHit mLocalHit;
397 const PxHitFlags mHitFlags;
398 PxGeomSweepHit mClosestHit;
399 PrunerPayload mClosestPayload;
400 bool mFoundHit;
401 const bool mAnyHit;
402
404 const PxGeometry& geometry, const PxTransform& pose, const ShapeData& queryVolume,
405 const PxVec3& dir, float distance, PxHitFlags hitFlags, bool anyHit, PxSweepThreadContext* context=NULL) :
406 mContext (context ? context : this),
407 mFilterCB (filterCB),
408 mCachedFuncs (funcs),
409 mGeometry (geometry),
410 mPose (pose),
411 mQueryVolume (queryVolume),
412 mDir (dir),
413 mHitFlags (hitFlags),
414 mFoundHit (false),
415 mAnyHit (anyHit)
416 {
417 mClosestHit.distance = distance;
418 }
419
420 virtual bool invoke(PxReal& aDist, PxU32 primIndex, const PrunerPayload* payloads, const PxTransform* transforms)
421 {
422 PX_ASSERT(payloads && transforms);
423
424 const PrunerPayload& payload = payloads[primIndex];
425
426 PxHitFlags filteredHitFlags = mHitFlags;
427 const PxGeometry* shapeGeom = mFilterCB.validatePayload(payload, filteredHitFlags);
428 if(!shapeGeom)
429 return true;
430
431 // PT: ### TODO: missing bit from PhysX version here
432
433 const float inflation = 0.0f; // ####
434 const PxU32 retVal = ShapeCast::sweep(mCachedFuncs, *shapeGeom, transforms[primIndex], mGeometry, mPose, mQueryVolume, mDir, aDist, mLocalHit, filteredHitFlags, inflation, mContext);
435
436 if(!retVal || !reportHit(payload, mLocalHit))
437 return true;
438
439 if(mLocalHit.distance < mClosestHit.distance)
440 {
441 mFoundHit = true;
442 if(mAnyHit)
443 return false;
444
445 aDist = mLocalHit.distance;
446 mClosestHit = mLocalHit;
447 mClosestPayload = payload;
448 }
449 return true;
450 }
451
453 };
454
459
460}
461}
462
463#endif
Definition base.h:1940
Definition GuQuerySystem.h:49
Represents a capsule.
Definition GuCapsule.h:47
Definition GuQuerySystem.h:58
Definition GuPruner.h:76
Definition GuQuerySystem.h:78
Definition GuBounds.h:115
Definition PxArray.h:53
Definition PxBitMap.h:52
Class representing 3D range or axis aligned bounding box.
Definition PxBounds3.h:58
Class representing the geometry of a box.
Definition PxBoxGeometry.h:49
Class representing the geometry of a capsule.
Definition PxCapsuleGeometry.h:54
Convex mesh geometry class.
Definition PxConvexMeshGeometry.h:79
A geometry object.
Definition PxGeometry.h:79
PX_CUDA_CALLABLE PX_FORCE_INLINE PxGeometryType::Enum getType() const
Returns the type of the geometry.
Definition PxGeometry.h:85
A class representing the geometry of a sphere.
Definition PxSphereGeometry.h:48
PxReal radius
The radius of the sphere.
Definition PxSphereGeometry.h:88
class representing a rigid euclidean transform as a quaternion and a vector
Definition PxTransform.h:49
Definition PxUserAllocated.h:43
3 Element vector class.
Definition PxVec3.h:50
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
Definition GuQuerySystem.h:323
Definition GuQuerySystem.h:354
Definition GuQuerySystem.h:367
Definition GuQuerySystem.h:284
Definition GuQuerySystem.h:268
Definition GuQuerySystem.h:200
Definition GuQuerySystem.h:388
Definition GuQuerySystem.h:379
Definition GuSweepTests.h:101
Definition GuQuerySystem.h:192
Definition GuPruner.h:55
Definition GuPrunerPayload.h:43
Definition GuPruner.h:47
Definition GuQuerySystem.h:99
Definition GuQuerySystem.h:81
Definition GuQuerySystem.h:336
Stores results of raycast queries.
Definition PxGeometryHit.h:151
Stores results of sweep queries.
Definition PxGeometryHit.h:175
@ eANY_HIT
Definition PxGeometryHit.h:65
@ ePRECISE_SWEEP
Definition PxGeometryHit.h:72
PxF32 distance
Distance to hit.
Definition PxGeometryHit.h:136
A per-thread context passed to low-level query functions.
Definition PxGeometryQueryContext.h:52