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 | |
13 | namespace 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 | } |