aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/PhysXCharacterKinematic/src/CctCharacterController.h
blob: d15965e76f1f4782960ec951cd8531d72a36ba5a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of NVIDIA CORPORATION nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2018 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.  

#ifndef CCT_CHARACTER_CONTROLLER
#define CCT_CHARACTER_CONTROLLER

//#define USE_CONTACT_NORMAL_FOR_SLOPE_TEST

#include "PxController.h"
#include "PxControllerObstacles.h"
#include "CctCharacterControllerManager.h"
#include "CctUtils.h"
#include "PxTriangle.h"
#include "PsArray.h"
#include "PsHashSet.h"
#include "CmPhysXCommon.h"

namespace physx
{

struct PxFilterData;
class PxQueryFilterCallback;
class PxObstacle;

namespace Cm
{
	class RenderBuffer;
}

namespace Cct
{	    
	struct CCTParams
	{
											CCTParams();

		PxControllerNonWalkableMode::Enum	mNonWalkableMode;
		PxQuat								mQuatFromUp;
		PxVec3								mUpDirection;
		PxF32								mSlopeLimit;
		PxF32								mContactOffset;
		PxF32								mStepOffset;
		PxF32								mInvisibleWallHeight;
		PxF32								mMaxJumpHeight;
		PxF32								mMaxEdgeLength2;
		bool								mTessellation;
		bool								mHandleSlope;		// True to handle walkable parts according to slope
		bool								mOverlapRecovery;
		bool								mPreciseSweeps;
		bool								mPreventVerticalSlidingAgainstCeiling;
	};

//	typedef Ps::Array<PxTriangle>	TriArray;
	typedef Ps::Array<PxU32>		IntArray;

	// PT: using private inheritance to control access, and make sure allocations are SIMD friendly
	class TriArray : private Ps::Array<PxTriangle>
	{
		public:

		PX_FORCE_INLINE PxTriangle* reserve(PxU32 nbTris)
		{
			// PT: customized version of "reserveContainerMemory"

			const PxU32 maxNbEntries = Ps::Array<PxTriangle>::capacity();
			const PxU32 realRequiredSize = Ps::Array<PxTriangle>::size() + nbTris;
			// PT: allocate one more tri to make sure we can safely V4Load the last one...
			const PxU32 requiredSize = realRequiredSize + 1;

			if(requiredSize>maxNbEntries)
			{
				// PT: ok so the commented out growing policy was introduced by PX-837 but it produces
				// large memory usage regressions (see PX-881) while not actually making things run
				// faster. Our benchmarks show no performance difference, but up to +38% more memory
				// used with this "standard" growing policy. So for now we just go back to the initial
				// growing policy. It should be fine since PX-837 was not actually reported by a customer,
				// it was just a concern that appeared while looking at the code. Ideally we'd use a pool
				// with fixed-size slabs to get the best of both worlds but it would make iterating over
				// triangles more complicated and would need more refactoring. So for now we don't bother,
				// but we'll keep this note here for the next time this problem shows up.
				// PT: new August 2018: turns out PX-837 was correct. Not doing this produces very large
				// performance problems (like: the app freezes!) in SampleCCT. We didn't see it because
				// it's an internal sample that it rarely used these days...
				const PxU32 naturalGrowthSize = maxNbEntries ? maxNbEntries*2 : 2;
				const PxU32 newSize = PxMax(requiredSize, naturalGrowthSize);
//				const PxU32 newSize = requiredSize;

				Ps::Array<PxTriangle>::reserve(newSize);
			}

			PxTriangle* buf = Ps::Array<PxTriangle>::end();
			// ...but we still want the size to reflect the correct number
			Ps::Array<PxTriangle>::forceSize_Unsafe(realRequiredSize);
			return buf;
		}

		PX_FORCE_INLINE void pushBack(const PxTriangle& tri)
		{
			PxTriangle* memory = reserve(1);
			memory->verts[0] = tri.verts[0];
			memory->verts[1] = tri.verts[1];
			memory->verts[2] = tri.verts[2];
		}

		PX_FORCE_INLINE PxU32 size()	const
		{
			return Ps::Array<PxTriangle>::size();
		}

		PX_FORCE_INLINE const PxTriangle* begin()	const
		{
			return Ps::Array<PxTriangle>::begin();
		}

		PX_FORCE_INLINE void clear()
		{
			Ps::Array<PxTriangle>::clear();
		}

		PX_FORCE_INLINE void forceSize_Unsafe(PxU32 size)
		{
			Ps::Array<PxTriangle>::forceSize_Unsafe(size);
		}

		PX_FORCE_INLINE	const PxTriangle&	getTriangle(PxU32 index)	const
		{
			return (*this)[index];
		}

	};

	/* Exclude from documentation */
	/** \cond */

	struct TouchedGeomType
	{
		enum Enum
		{
			eUSER_BOX,
			eUSER_CAPSULE,
			eMESH,
			eBOX,
			eSPHERE,
			eCAPSULE,

			eLAST,

			eFORCE_DWORD	= 0x7fffffff
		};
	};

	class SweptVolume;

	// PT: apparently .Net aligns some of them on 8-bytes boundaries for no good reason. This is bad.
	// Whenever a variable points to a field of a specially aligned struct, it has to be declared with __packed (see GHS docu, Structure Packing, page 111).
	// Every reference to such a field needs the __packed declaration: all function parameters and assignment operators etc.
#pragma pack(push,4)

	struct TouchedGeom
	{
		TouchedGeomType::Enum	mType;
		const void*				mTGUserData;	// PxController or PxShape pointer
		const PxRigidActor*		mActor;			// PxActor for PxShape pointers (mandatory with shared shapes)
		PxExtendedVec3			mOffset;		// Local origin, typically the center of the world bounds around the character. We translate both
												// touched shapes & the character so that they are nearby this PxVec3, then add the offset back to
												// computed "world" impacts.
	protected:
		~TouchedGeom(){}
	};

	struct TouchedUserBox : public TouchedGeom
	{
		PxExtendedBox			mBox;
	};
	PX_COMPILE_TIME_ASSERT(sizeof(TouchedUserBox)==sizeof(TouchedGeom)+sizeof(PxExtendedBox));

	struct TouchedUserCapsule : public TouchedGeom
	{
		PxExtendedCapsule		mCapsule;
	};
	PX_COMPILE_TIME_ASSERT(sizeof(TouchedUserCapsule)==sizeof(TouchedGeom)+sizeof(PxExtendedCapsule));

	struct TouchedMesh : public TouchedGeom
	{
		PxU32			mNbTris;
		PxU32			mIndexWorldTriangles;
	};

	struct TouchedBox : public TouchedGeom
	{
		PxVec3			mCenter;
		PxVec3			mExtents;
		PxQuat			mRot;
	};

	struct TouchedSphere : public TouchedGeom
	{
		PxVec3			mCenter;		//!< Sphere's center
		PxF32			mRadius;		//!< Sphere's radius
	};

	struct TouchedCapsule : public TouchedGeom
	{
		PxVec3			mP0;		//!< Start of segment
		PxVec3			mP1;		//!< End of segment
		PxF32			mRadius;	//!< Capsule's radius
	};

#pragma pack(pop)

	struct SweptContact
	{
		PxExtendedVec3		mWorldPos;		// Contact position in world space
		PxVec3				mWorldNormal;	// Contact normal in world space
		PxF32				mDistance;		// Contact distance
		PxU32				mInternalIndex;	// Reserved for internal usage
		PxU32				mTriangleIndex;	// Triangle index for meshes/heightfields
		TouchedGeom*		mGeom;

		PX_FORCE_INLINE		void	setWorldPos(const PxVec3& localImpact, const PxExtendedVec3& offset)
		{
			mWorldPos.x = PxExtended(localImpact.x) + offset.x;
			mWorldPos.y = PxExtended(localImpact.y) + offset.y;
			mWorldPos.z = PxExtended(localImpact.z) + offset.z;
		}
	};

	// PT: user-defined obstacles. Note that "user" is from the SweepTest class' point of view,
	// i.e. the PhysX CCT module is the user in this case. This is to limit coupling between the
	// core CCT module and the PhysX classes.
	struct UserObstacles// : PxObstacleContext
	{
		PxU32						mNbBoxes;
		const PxExtendedBox*		mBoxes;
		const void**				mBoxUserData;

		PxU32						mNbCapsules;
		const PxExtendedCapsule*	mCapsules;
		const void**				mCapsuleUserData;
	};

	struct InternalCBData_OnHit{};
	struct InternalCBData_FindTouchedGeom{};

	enum SweepTestFlag
	{
		STF_HIT_NON_WALKABLE		= (1<<0),
		STF_WALK_EXPERIMENT			= (1<<1),
		STF_VALIDATE_TRIANGLE_DOWN	= (1<<2),	// Validate touched triangle data (down pass)
		STF_VALIDATE_TRIANGLE_SIDE	= (1<<3),	// Validate touched triangle data (side pass)
		STF_TOUCH_OTHER_CCT			= (1<<4),	// Are we standing on another CCT or not? (only updated for down pass)
		STF_TOUCH_OBSTACLE			= (1<<5),	// Are we standing on an obstacle or not? (only updated for down pass)
		STF_NORMALIZE_RESPONSE		= (1<<6),
		STF_FIRST_UPDATE			= (1<<7),
		STF_IS_MOVING_UP			= (1<<8)
	};	

	enum SweepPass
	{
		SWEEP_PASS_UP,
		SWEEP_PASS_SIDE,
		SWEEP_PASS_DOWN,
		SWEEP_PASS_SENSOR
	};
	
	class Controller;

	template<class T>
	struct TouchedObject
	{
		TouchedObject(bool regDl)
			: mTouchedObject(NULL), mRegisterDeletionListener(regDl), mCctManager(NULL)
		{
		}

		PX_FORCE_INLINE const T*	operator->() const { return mTouchedObject; }
		PX_FORCE_INLINE bool		operator==(const TouchedObject& otherObject) { return mTouchedObject == otherObject.mTouchedObject; }
		PX_FORCE_INLINE bool		operator==(const T* otherObject) { return mTouchedObject == otherObject; }
		PX_FORCE_INLINE bool		operator==(const PxBase* otherObject) { return mTouchedObject == otherObject; }
		PX_FORCE_INLINE				operator bool() const { return mTouchedObject != NULL; }
		PX_FORCE_INLINE TouchedObject&	operator=(const T* assignedObject)
		{
			if(mRegisterDeletionListener && (mTouchedObject != assignedObject))
			{
				if(mTouchedObject)
					mCctManager->unregisterObservedObject(mTouchedObject);

				if(assignedObject)
					mCctManager->registerObservedObject(assignedObject);
			}
			mTouchedObject = assignedObject;
			return *this;
		}

		const T*			get() const { return mTouchedObject; }

		void				setCctManager(CharacterControllerManager* cm) { mCctManager = cm; }

	private:
		TouchedObject& operator=(const TouchedObject&);

		const T*					mTouchedObject;
		bool						mRegisterDeletionListener;
		CharacterControllerManager*	mCctManager;
	};

	class SweepTest
	{		
	public:
										SweepTest(bool registerDeletionListener);
										~SweepTest();

		PxControllerCollisionFlags		moveCharacter(	const InternalCBData_FindTouchedGeom* userData,
														InternalCBData_OnHit* user_data2,
														SweptVolume& volume,
														const PxVec3& direction,
														const UserObstacles& userObstacles,
														PxF32 min_dist,
														const PxControllerFilters& filters,
														bool constrainedClimbingMode,
														bool standingOnMoving,
														const PxRigidActor*& touchedActor,
														const PxShape*& touchedShape,
														PxU64 contextID);

					bool				doSweepTest(const InternalCBData_FindTouchedGeom* userDataTouchedGeom,
													InternalCBData_OnHit* userDataOnHit,
													const UserObstacles& userObstacles,
													SweptVolume& swept_volume,
													const PxVec3& direction, const PxVec3& sideVector, PxU32 max_iter,
													PxU32* nb_collisions, PxF32 min_dist, const PxControllerFilters& filters, SweepPass sweepPass,
													const PxRigidActor*& touchedActor, const PxShape*& touchedShape, PxU64 contextID);

					void				findTouchedObstacles(const UserObstacles& userObstacles, const PxExtendedBounds3& world_box);

					void				voidTestCache();
					void				onRelease(const PxBase& observed);
					void				updateCachedShapesRegistration(PxU32 startIndex, bool unregister);

		// observer notifications
					void				onObstacleRemoved(ObstacleHandle index);
					void				onObstacleUpdated(ObstacleHandle index, const PxObstacleContext* context, const PxVec3& origin, const PxVec3& unitDir, const PxReal distance);
					void				onObstacleAdded(ObstacleHandle index, const PxObstacleContext* context, const PxVec3& origin, const PxVec3& unitDir, const PxReal distance);

					void				onOriginShift(const PxVec3& shift);

					Cm::RenderBuffer*	mRenderBuffer;
					PxU32				mRenderFlags;
					TriArray			mWorldTriangles;
					IntArray			mTriangleIndices;
					IntArray			mGeomStream;
					PxExtendedBounds3	mCacheBounds;
					PxU32				mCachedTriIndexIndex;
					mutable	PxU32		mCachedTriIndex[3];
					PxU32				mNbCachedStatic;
					PxU32				mNbCachedT;
	public:
#ifdef USE_CONTACT_NORMAL_FOR_SLOPE_TEST
					PxVec3				mContactNormalDownPass;
#else
					PxVec3				mContactNormalDownPass;
					PxVec3				mContactNormalSidePass;
					float				mTouchedTriMin;
					float				mTouchedTriMax;
					//PxTriangle		mTouchedTriangle;
#endif
					//
					TouchedObject<PxShape>		mTouchedShape;		// Shape on which the CCT is standing
					TouchedObject<PxRigidActor>	mTouchedActor;		// Actor from touched shape
					ObstacleHandle		mTouchedObstacleHandle;	// Obstacle on which the CCT is standing
					PxVec3				mTouchedPos;		// Last known position of mTouchedShape/mTouchedObstacle
					// PT: TODO: union those
					PxVec3				mTouchedPosShape_Local;
					PxVec3				mTouchedPosShape_World;
					PxVec3				mTouchedPosObstacle_Local;
					PxVec3				mTouchedPosObstacle_World;
					//
					CCTParams			mUserParams;
					PxF32				mVolumeGrowth;		// Must be >1.0f and not too big
					PxF32				mContactPointHeight;	// UBI
					PxU32				mSQTimeStamp;
					PxU16				mNbFullUpdates;
					PxU16				mNbPartialUpdates;
					PxU16				mNbTessellation;
					PxU16				mNbIterations;
					PxU32				mFlags;
					bool				mRegisterDeletionListener;

	PX_FORCE_INLINE	void				resetStats()
										{
											mNbFullUpdates		= 0;
											mNbPartialUpdates	= 0;
											mNbTessellation		= 0;
											mNbIterations		= 0;
										}

					void				setCctManager(CharacterControllerManager* cm) 
					{ 
						mCctManager = cm;
						mTouchedActor.setCctManager(cm); 
						mTouchedShape.setCctManager(cm); 
					}

	private:
				void					updateTouchedGeoms(	const InternalCBData_FindTouchedGeom* userData, const UserObstacles& userObstacles,
															const PxExtendedBounds3& worldBox, const PxControllerFilters& filters, const PxVec3& sideVector);				

				CharacterControllerManager*	mCctManager;
				SweepTest(const SweepTest&);
				SweepTest& operator=(const SweepTest& );
	};

	class CCTFilter	// PT: internal filter data, could be replaced with PxControllerFilters eventually
	{
		public:
		PX_FORCE_INLINE	CCTFilter() :
			mFilterData		(NULL),
			mFilterCallback	(NULL),
			mStaticShapes	(false),
			mDynamicShapes	(false),
			mPreFilter		(false),
			mPostFilter		(false),
			mCCTShapes		(NULL)
		{
		}
		const PxFilterData*		mFilterData;
		PxQueryFilterCallback*	mFilterCallback;
		bool					mStaticShapes;
		bool					mDynamicShapes;
		bool					mPreFilter;
		bool					mPostFilter;
		Ps::HashSet<PxShape>*	mCCTShapes;
	};

	PxU32 getSceneTimestamp(const InternalCBData_FindTouchedGeom* userData);

	void findTouchedGeometry(const InternalCBData_FindTouchedGeom* userData,
		const PxExtendedBounds3& world_aabb,

		TriArray& world_triangles,
		IntArray& triIndicesArray,
		IntArray& geomStream,

		const CCTFilter& filter,
		const CCTParams& params,
		PxU16& nbTessellation);

	PxU32 shapeHitCallback(const InternalCBData_OnHit* userData, const SweptContact& contact, const PxVec3& dir, PxF32 length);
	PxU32 userHitCallback(const InternalCBData_OnHit* userData, const SweptContact& contact, const PxVec3& dir, PxF32 length);

} // namespace Cct

}

/** \endcond */
#endif