1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsPhysXPrerequisites.h"
6#include "Physics/BsPhysics.h"
7#include "Physics/BsPhysicsCommon.h"
8#include "PxPhysics.h"
9#include "foundation/Px.h"
10#include "characterkinematic/PxControllerManager.h"
11#include "cooking/PxCooking.h"
12
13namespace bs
14{
15 /** @addtogroup PhysX
16 * @{
17 */
18
19 class PhysXScene;
20
21 /** NVIDIA PhysX implementation of Physics. */
22 class PhysX : public Physics
23 {
24 /** Type of contacts reported by PhysX simulation. */
25 enum class ContactEventType
26 {
27 ContactBegin,
28 ContactStay,
29 ContactEnd
30 };
31
32 /** Event reported when a physics object interacts with a collider. */
33 struct TriggerEvent
34 {
35 Collider* trigger; /** Trigger that was interacted with. */
36 Collider* other; /** Collider that was interacted with. */
37 ContactEventType type; /** Exact type of the event. */
38 };
39
40 /** Event reported when two colliders interact. */
41 struct ContactEvent
42 {
43 Collider* colliderA; /** First collider. */
44 Collider* colliderB; /** Second collider. */
45 ContactEventType type; /** Exact type of the event. */
46 // Note: Not too happy this is heap allocated, use static allocator?
47 Vector<ContactPoint> points; /** Information about all contact points between the colliders. */
48 };
49
50 /** Event reported when a joint breaks. */
51 struct JointBreakEvent
52 {
53 Joint* joint; /** Broken joint. */
54 };
55
56 public:
57 PhysX(const PHYSICS_INIT_DESC& input);
58 ~PhysX();
59
60 /** @copydoc Physics::fixedUpdate */
61 void fixedUpdate(float step) override;
62
63 /** @copydoc Physics::update */
64 void update() override;
65
66 /** @copydoc Physics::createMaterial */
67 SPtr<PhysicsMaterial> createMaterial(float staticFriction, float dynamicFriction, float restitution) override;
68
69 /** @copydoc Physics::createMesh */
70 SPtr<PhysicsMesh> createMesh(const SPtr<MeshData>& meshData, PhysicsMeshType type) override;
71
72 /** @copydoc Physics::createPhysicsScene */
73 SPtr<PhysicsScene> createPhysicsScene() override;
74
75 /** @copydoc Physics::setPaused */
76 void setPaused(bool paused) override;
77
78 /** Triggered by the PhysX simulation when an interaction between two colliders is found. */
79 void _reportContactEvent(const ContactEvent& event);
80
81 /** Triggered by the PhysX simulation when an interaction between two trigger and a collider is found. */
82 void _reportTriggerEvent(const TriggerEvent& event);
83
84 /** Triggered by the PhysX simulation when a joint breaks. */
85 void _reportJointBreakEvent(const JointBreakEvent& event);
86
87 /** @copydoc Physics::_rayCast */
88 bool _rayCast(const Vector3& origin, const Vector3& unitDir, const Collider& collider, PhysicsQueryHit& hit,
89 float maxDist = FLT_MAX) const override;
90
91 /** Notifies the system that at physics scene is about to be destroyed. */
92 void _notifySceneDestroyed(PhysXScene* scene);
93
94 /** Returns the default PhysX material. */
95 physx::PxMaterial* getDefaultMaterial() const { return mDefaultMaterial; }
96
97 /** Returns the main PhysX object. */
98 physx::PxPhysics* getPhysX() const { return mPhysics; }
99
100 /** Returns the PhysX object used for mesh cooking. */
101 physx::PxCooking* getCooking() const { return mCooking; }
102
103 /** Returns default scale used in the PhysX scene. */
104 physx::PxTolerancesScale getScale() const { return mScale; }
105
106 private:
107 friend class PhysXEventCallback;
108
109 /** Sends out all events recorded during simulation to the necessary physics objects. */
110 void triggerEvents();
111
112 PHYSICS_INIT_DESC mInitDesc;
113 bool mPaused = false;
114
115 Vector<TriggerEvent> mTriggerEvents;
116 Vector<ContactEvent> mContactEvents;
117 Vector<JointBreakEvent> mJointBreakEvents;
118 Vector<PhysXScene*> mScenes;
119 UnorderedMap<UINT32, UINT32> mBroadPhaseRegionHandles;
120
121 physx::PxFoundation* mFoundation = nullptr;
122 physx::PxPhysics* mPhysics = nullptr;
123 physx::PxCooking* mCooking = nullptr;
124 physx::PxMaterial* mDefaultMaterial = nullptr;
125 physx::PxTolerancesScale mScale;
126
127 static const UINT32 SCRATCH_BUFFER_SIZE;
128 };
129
130 /** Contains information about a single PhysX scene. */
131 class PhysXScene : public PhysicsScene
132 {
133 public:
134 PhysXScene(physx::PxPhysics* physics, const PHYSICS_INIT_DESC& input, const physx::PxTolerancesScale& scale);
135 ~PhysXScene();
136
137 /** @copydoc PhysicsScene::createRigidbody */
138 SPtr<Rigidbody> createRigidbody(const HSceneObject& linkedSO) override;
139
140 /** @copydoc PhysicsScene::createBoxCollider */
141 SPtr<BoxCollider> createBoxCollider(const Vector3& extents, const Vector3& position,
142 const Quaternion& rotation) override;
143
144 /** @copydoc PhysicsScene::createSphereCollider */
145 SPtr<SphereCollider> createSphereCollider(float radius, const Vector3& position, const Quaternion& rotation) override;
146
147 /** @copydoc PhysicsScene::createPlaneCollider */
148 SPtr<PlaneCollider> createPlaneCollider(const Vector3& position, const Quaternion& rotation) override;
149
150 /** @copydoc PhysicsScene::createCapsuleCollider */
151 SPtr<CapsuleCollider> createCapsuleCollider(float radius, float halfHeight, const Vector3& position,
152 const Quaternion& rotation) override;
153
154 /** @copydoc PhysicsScene::createMeshCollider */
155 SPtr<MeshCollider> createMeshCollider(const Vector3& position, const Quaternion& rotation) override;
156
157 /** @copydoc PhysicsScene::createFixedJoint */
158 SPtr<FixedJoint> createFixedJoint(const FIXED_JOINT_DESC& desc) override;
159
160 /** @copydoc PhysicsScene::createDistanceJoint */
161 SPtr<DistanceJoint> createDistanceJoint(const DISTANCE_JOINT_DESC& desc) override;
162
163 /** @copydoc PhysicsScene::createHingeJoint */
164 SPtr<HingeJoint> createHingeJoint(const HINGE_JOINT_DESC& desc) override;
165
166 /** @copydoc PhysicsScene::createSphericalJoint */
167 SPtr<SphericalJoint> createSphericalJoint(const SPHERICAL_JOINT_DESC& desc) override;
168
169 /** @copydoc PhysicsScene::createSliderJoint */
170 SPtr<SliderJoint> createSliderJoint(const SLIDER_JOINT_DESC& desc) override;
171
172 /** @copydoc PhysicsScene::createD6Joint */
173 SPtr<D6Joint> createD6Joint(const D6_JOINT_DESC& desc) override;
174
175 /** @copydoc PhysicsScene::createCharacterController*/
176 SPtr<CharacterController> createCharacterController(const CHAR_CONTROLLER_DESC& desc) override;
177
178 /** @copydoc PhysicsScene::rayCast(const Vector3&, const Vector3&, PhysicsQueryHit&, UINT64, float) const */
179 bool rayCast(const Vector3& origin, const Vector3& unitDir, PhysicsQueryHit& hit,
180 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
181
182 /** @copydoc PhysicsScene::boxCast */
183 bool boxCast(const AABox& box, const Quaternion& rotation, const Vector3& unitDir, PhysicsQueryHit& hit,
184 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
185
186 /** @copydoc PhysicsScene::sphereCast */
187 bool sphereCast(const Sphere& sphere, const Vector3& unitDir, PhysicsQueryHit& hit,
188 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
189
190 /** @copydoc PhysicsScene::capsuleCast */
191 bool capsuleCast(const Capsule& capsule, const Quaternion& rotation, const Vector3& unitDir,
192 PhysicsQueryHit& hit, UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
193
194 /** @copydoc PhysicsScene::convexCast */
195 bool convexCast(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
196 const Vector3& unitDir, PhysicsQueryHit& hit, UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
197
198 /** @copydoc PhysicsScene::rayCastAll(const Vector3&, const Vector3&, UINT64, float) const */
199 Vector<PhysicsQueryHit> rayCastAll(const Vector3& origin, const Vector3& unitDir,
200 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
201
202 /** @copydoc PhysicsScene::boxCastAll */
203 Vector<PhysicsQueryHit> boxCastAll(const AABox& box, const Quaternion& rotation,
204 const Vector3& unitDir, UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
205
206 /** @copydoc PhysicsScene::sphereCastAll */
207 Vector<PhysicsQueryHit> sphereCastAll(const Sphere& sphere, const Vector3& unitDir,
208 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
209
210 /** @copydoc PhysicsScene::capsuleCastAll */
211 Vector<PhysicsQueryHit> capsuleCastAll(const Capsule& capsule, const Quaternion& rotation,
212 const Vector3& unitDir, UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
213
214 /** @copydoc PhysicsScene::convexCastAll */
215 Vector<PhysicsQueryHit> convexCastAll(const HPhysicsMesh& mesh, const Vector3& position,
216 const Quaternion& rotation, const Vector3& unitDir, UINT64 layer = BS_ALL_LAYERS,
217 float max = FLT_MAX) const override;
218
219 /** @copydoc PhysicsScene::rayCastAny(const Vector3&, const Vector3&, UINT64, float) const */
220 bool rayCastAny(const Vector3& origin, const Vector3& unitDir,
221 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
222
223 /** @copydoc PhysicsScene::boxCastAny */
224 bool boxCastAny(const AABox& box, const Quaternion& rotation, const Vector3& unitDir,
225 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
226
227 /** @copydoc PhysicsScene::sphereCastAny */
228 bool sphereCastAny(const Sphere& sphere, const Vector3& unitDir,
229 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
230
231 /** @copydoc PhysicsScene::capsuleCastAny */
232 bool capsuleCastAny(const Capsule& capsule, const Quaternion& rotation, const Vector3& unitDir,
233 UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
234
235 /** @copydoc PhysicsScene::convexCastAny */
236 bool convexCastAny(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
237 const Vector3& unitDir, UINT64 layer = BS_ALL_LAYERS, float max = FLT_MAX) const override;
238
239 /** @copydoc PhysicsScene::boxOverlapAny */
240 bool boxOverlapAny(const AABox& box, const Quaternion& rotation, UINT64 layer = BS_ALL_LAYERS) const override;
241
242 /** @copydoc PhysicsScene::sphereOverlapAny */
243 bool sphereOverlapAny(const Sphere& sphere, UINT64 layer = BS_ALL_LAYERS) const override;
244
245 /** @copydoc PhysicsScene::capsuleOverlapAny */
246 bool capsuleOverlapAny(const Capsule& capsule, const Quaternion& rotation,
247 UINT64 layer = BS_ALL_LAYERS) const override;
248
249 /** @copydoc PhysicsScene::convexOverlapAny */
250 bool convexOverlapAny(const HPhysicsMesh& mesh, const Vector3& position, const Quaternion& rotation,
251 UINT64 layer = BS_ALL_LAYERS) const override;
252
253 /** @copydoc PhysicsScene::getGravity */
254 Vector3 getGravity() const override;
255
256 /** @copydoc PhysicsScene::setGravity */
257 void setGravity(const Vector3& gravity) override;
258
259 /** @copydoc PhysicsScene::addBroadPhaseRegion */
260 UINT32 addBroadPhaseRegion(const AABox& region) override;
261
262 /** @copydoc PhysicsScene::removeBroadPhaseRegion */
263 void removeBroadPhaseRegion(UINT32 regionId) override;
264
265 /** @copydoc PhysicsScene::clearBroadPhaseRegions */
266 void clearBroadPhaseRegions() override;
267
268 /** @copydoc PhysicsScene::setFlag */
269 void setFlag(PhysicsFlags flags, bool enabled) override;
270
271 /** @copydoc PhysicsScene::getMaxTesselationEdgeLength */
272 float getMaxTesselationEdgeLength() const override { return mTesselationLength; }
273
274 /** @copydoc PhysicsScene::setMaxTesselationEdgeLength */
275 void setMaxTesselationEdgeLength(float length) override;
276
277 /** @copydoc PhysicsScene::_boxOverlap */
278 Vector<Collider*> _boxOverlap(const AABox& box, const Quaternion& rotation,
279 UINT64 layer = BS_ALL_LAYERS) const override;
280
281 /** @copydoc PhysicsScene::_sphereOverlap */
282 Vector<Collider*> _sphereOverlap(const Sphere& sphere, UINT64 layer = BS_ALL_LAYERS) const override;
283
284 /** @copydoc PhysicsScene::_capsuleOverlap */
285 Vector<Collider*> _capsuleOverlap(const Capsule& capsule, const Quaternion& rotation,
286 UINT64 layer = BS_ALL_LAYERS) const override;
287
288 /** @copydoc PhysicsScene::_convexOverlap */
289 Vector<Collider*> _convexOverlap(const HPhysicsMesh& mesh, const Vector3& position,
290 const Quaternion& rotation, UINT64 layer = BS_ALL_LAYERS) const override;
291
292 private:
293 /**
294 * Helper method that performs a sweep query by checking if the provided geometry hits any physics objects
295 * when moved along the specified direction. Returns information about the first hit.
296 */
297 inline bool sweep(const physx::PxGeometry& geometry, const physx::PxTransform& tfrm, const Vector3& unitDir,
298 PhysicsQueryHit& hit, UINT64 layer, float maxDist) const;
299
300 /**
301 * Helper method that performs a sweep query by checking if the provided geometry hits any physics objects
302 * when moved along the specified direction. Returns information about all hit.
303 */
304 inline Vector<PhysicsQueryHit> sweepAll(const physx::PxGeometry& geometry, const physx::PxTransform& tfrm,
305 const Vector3& unitDir, UINT64 layer, float maxDist) const;
306
307 /**
308 * Helper method that performs a sweep query by checking if the provided geometry hits any physics objects
309 * when moved along the specified direction. Returns no information about the hit, but rather just if it happened or
310 * not.
311 */
312 inline bool sweepAny(const physx::PxGeometry& geometry, const physx::PxTransform& tfrm, const Vector3& unitDir,
313 UINT64 layer, float maxDist) const;
314
315 /** Helper method that returns all colliders that are overlapping the provided geometry. */
316 inline Vector<Collider*> overlap(const physx::PxGeometry& geometry, const physx::PxTransform& tfrm,
317 UINT64 layer) const;
318
319 /** Helper method that checks if the provided geometry overlaps any physics object. */
320 inline bool overlapAny(const physx::PxGeometry& geometry, const physx::PxTransform& tfrm, UINT64 layer) const;
321
322 private:
323 friend class PhysX;
324
325 float mTesselationLength = 3.0f;
326
327 UnorderedMap<UINT32, UINT32> mBroadPhaseRegionHandles;
328 UINT32 mNextRegionIdx = 1;
329
330 physx::PxPhysics* mPhysics = nullptr;
331 physx::PxScene* mScene = nullptr;
332 physx::PxControllerManager* mCharManager = nullptr;
333 };
334
335 /** Provides easier access to PhysX. */
336 PhysX& gPhysX();
337
338 /** @} */
339}