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 "BsCorePrerequisites.h"
6#include "Physics/BsPhysicsCommon.h"
7
8namespace bs
9{
10 /** @addtogroup Physics
11 * @{
12 */
13
14 /** Type of force or torque that can be applied to a rigidbody. */
15 enum class BS_SCRIPT_EXPORT(m:Physics) ForceMode
16 {
17 Force, /**< Value applied is a force. */
18 Impulse, /**< Value applied is an impulse (a direct change in its linear or angular momentum). */
19 Velocity, /**< Value applied is velocity. */
20 Acceleration /**< Value applied is accelearation. */
21 };
22
23 /** Type of force that can be applied to a rigidbody at an arbitrary point. */
24 enum class BS_SCRIPT_EXPORT(m:Physics) PointForceMode
25 {
26 Force, /**< Value applied is a force. */
27 Impulse, /**< Value applied is an impulse (a direct change in its linear or angular momentum). */
28 };
29
30 /** Flags that control options of a Rigidbody object. */
31 enum class BS_SCRIPT_EXPORT(m:Physics) RigidbodyFlag
32 {
33 /** No options. */
34 None = 0x00,
35 /** Automatically calculate center of mass transform and inertia tensors from child shapes (colliders). */
36 AutoTensors = 0x01,
37 /** Calculate mass distribution from child shapes (colliders). Only relevant when auto-tensors is on. */
38 AutoMass = 0x02,
39 /**
40 * Enables continous collision detection. This can prevent fast moving bodies from tunneling through each other.
41 * This must also be enabled globally in Physics otherwise the flag will be ignored.
42 */
43 CCD = 0x04
44 };
45
46 /**
47 * Rigidbody is a dynamic physics object that can be moved using forces (or directly). It will interact with other
48 * static and dynamic physics objects in the scene accordingly (it will push other non-kinematic rigidbodies,
49 * and collide with static objects).
50 *
51 * The shape and mass of a rigidbody is governed by its colliders. You must attach at least one collider for the
52 * rigidbody to be valid.
53 */
54 class BS_CORE_EXPORT Rigidbody
55 {
56 public:
57 /**
58 * Constructs a new rigidbody.
59 *
60 * @param[in] linkedSO Scene object that owns this rigidbody. All physics updates applied to this object
61 * will be transfered to this scene object (the movement/rotation resulting from
62 * those updates).
63 */
64 Rigidbody(const HSceneObject& linkedSO);
65 virtual ~Rigidbody() = default;
66
67 /**
68 * Moves the rigidbody to a specific position. This method will ensure physically correct movement, meaning the body
69 * will collide with other objects along the way.
70 */
71 virtual void move(const Vector3& position) = 0;
72
73 /**
74 * Rotates the rigidbody. This method will ensure physically correct rotation, meaning the body will collide with
75 * other objects along the way.
76 */
77 virtual void rotate(const Quaternion& rotation) = 0;
78
79 /** Returns the current position of the rigidbody. */
80 virtual Vector3 getPosition() const = 0;
81
82 /** Returns the current rotation of the rigidbody. */
83 virtual Quaternion getRotation() const = 0;
84
85 /**
86 * Moves and rotates the rigidbody to a specific position. Unlike move() and rotate() this will not transform the
87 * body in a physically correct manner, but will instead "teleport" it immediately to the specified position and
88 * rotation.
89 */
90 virtual void setTransform(const Vector3& pos, const Quaternion& rot) = 0;
91
92 /**
93 * Determines the mass of the object and all of its collider shapes. Only relevant if RigidbodyFlag::AutoMass or
94 * RigidbodyFlag::AutoTensors is turned off. Value of zero means the object is immovable (but can be rotated).
95 */
96 virtual void setMass(float mass) = 0;
97
98 /** @copydoc setMass() */
99 virtual float getMass() const = 0;
100
101 /**
102 * Determines if the body is kinematic. Kinematic body will not move in response to external forces (for example
103 * gravity, or another object pushing it), essentially behaving like collider. Unlike a collider though, you can
104 * still move the object and have other dynamic objects respond correctly (meaning it will push other objects).
105 */
106 virtual void setIsKinematic(bool kinematic) = 0;
107
108 /** @copydoc setIsKinematic() */
109 virtual bool getIsKinematic() const = 0;
110
111 /**
112 * Checks if the body is sleeping. Objects that aren't moved/rotated for a while are put to sleep to reduce load
113 * on the physics system.
114 */
115 virtual bool isSleeping() const = 0;
116
117 /** Forces the object to sleep. Useful if you know the object will not move in any significant way for a while. */
118 virtual void sleep() = 0;
119
120 /**
121 * Wakes an object up. Useful if you modified properties of this object, and potentially surrounding objects which
122 * might result in the object being moved by physics (although the physics system will automatically wake the
123 * object up for majority of such cases).
124 */
125 virtual void wakeUp() = 0;
126
127 /** Determines a threshold of force and torque under which the object will be considered to be put to sleep. */
128 virtual void setSleepThreshold(float threshold) = 0;
129
130 /** @copydoc setSleepThreshold() */
131 virtual float getSleepThreshold() const = 0;
132
133 /** Determines whether or not the rigidbody will have the global gravity force applied to it. */
134 virtual void setUseGravity(bool gravity) = 0;
135
136 /** @copydoc setUseGravity() */
137 virtual bool getUseGravity() const = 0;
138
139 /** Determines the linear velocity of the body. */
140 virtual void setVelocity(const Vector3& velocity) = 0;
141
142 /** @copydoc setVelocity() */
143 virtual Vector3 getVelocity() const = 0;
144
145 /** Determines the angular velocity of the body. */
146 virtual void setAngularVelocity(const Vector3& velocity) = 0;
147
148 /** @copydoc setAngularVelocity() */
149 virtual Vector3 getAngularVelocity() const = 0;
150
151 /** Determines the linear drag of the body. Higher drag values means the object resists linear movement more. */
152 virtual void setDrag(float drag) = 0;
153
154 /** @copydoc setDrag() */
155 virtual float getDrag() const = 0;
156
157 /** Determines the angular drag of the body. Higher drag values means the object resists angular movement more. */
158 virtual void setAngularDrag(float drag) = 0;
159
160 /** @copydoc setAngularDrag() */
161 virtual float getAngularDrag() const = 0;
162
163 /**
164 * Determines the inertia tensor in local mass space. Inertia tensor determines how difficult is to rotate the
165 * object. Values of zero in the inertia tensor mean the object will be unable to rotate around a specific axis.
166 * Only relevant if RigidbodyFlag::AutoTensors is turned off.
167 */
168 virtual void setInertiaTensor(const Vector3& tensor) = 0;
169
170 /** @copydoc setInertiaTensor() */
171 virtual Vector3 getInertiaTensor() const = 0;
172
173 /** Determines the maximum angular velocity of the rigidbody. Velocity will be clamped to this value. */
174 virtual void setMaxAngularVelocity(float maxVelocity) = 0;
175
176 /** @copydoc setMaxAngularVelocity() */
177 virtual float getMaxAngularVelocity() const = 0;
178
179 /**
180 * Sets the rigidbody's center of mass transform. Only relevant if RigibodyFlag::AutoTensors is turned off.
181 *
182 * @param[in] position Position of the center of mass.
183 * @param[in] rotation Rotation that determines orientation of the inertia tensor (rotation of the center of
184 * mass frame).
185 */
186 virtual void setCenterOfMass(const Vector3& position, const Quaternion& rotation) = 0;
187
188 /** Returns the position of the center of mass. */
189 virtual Vector3 getCenterOfMassPosition() const = 0;
190
191 /** Returns the rotation of the inertia tensor. */
192 virtual Quaternion getCenterOfMassRotation() const = 0;
193
194 /**
195 * Determines the number of iterations to use when solving for position. Higher values can improve precision and
196 * numerical stability of the simulation.
197 */
198 virtual void setPositionSolverCount(UINT32 count) = 0;
199
200 /** @copydoc setPositionSolverCount() */
201 virtual UINT32 getPositionSolverCount() const = 0;
202
203 /**
204 * Determines the number of iterations to use when solving for velocity. Higher values can improve precision and
205 * numerical stability of the simulation.
206 */
207 virtual void setVelocitySolverCount(UINT32 count) = 0;
208
209 /** @copydoc setVelocitySolverCount() */
210 virtual UINT32 getVelocitySolverCount() const = 0;
211
212 /** Flags that control the behaviour of the rigidbody. */
213 virtual void setFlags(RigidbodyFlag flags) { mFlags = flags; }
214
215 /** @copydoc setFlags() */
216 virtual RigidbodyFlag getFlags() const { return mFlags; }
217
218 /**
219 * Applies a force to the center of the mass of the rigidbody. This will produce linear momentum.
220 *
221 * @param[in] force Force to apply.
222 * @param[in] mode Determines what is the type of @p force.
223 */
224 virtual void addForce(const Vector3& force, ForceMode mode = ForceMode::Force) = 0;
225
226 /**
227 * Applies a torque to the rigidbody. This will produce angular momentum.
228 *
229 * @param[in] torque Torque to apply.
230 * @param[in] mode Determines what is the type of @p torque.
231 */
232 virtual void addTorque(const Vector3& torque, ForceMode mode = ForceMode::Force) = 0;
233
234 /**
235 * Applies a force to a specific point on the rigidbody. This will in most cases produce both linear and angular
236 * momentum.
237 *
238 * @param[in] force Force to apply.
239 * @param[in] position World position to apply the force at.
240 * @param[in] mode Determines what is the type of @p force.
241 */
242 virtual void addForceAtPoint(const Vector3& force, const Vector3& position,
243 PointForceMode mode = PointForceMode::Force) = 0;
244
245 /**
246 * Returns the total (linear + angular) velocity at a specific point.
247 *
248 * @param[in] point Point in world space.
249 * @return Total velocity of the point.
250 */
251 virtual Vector3 getVelocityAtPoint(const Vector3& point) const = 0;
252
253 /** Registers a new collider as a child of this rigidbody. */
254 virtual void addCollider(Collider* collider) = 0;
255
256 /** Removes a collider from the child list of this rigidbody. */
257 virtual void removeCollider(Collider* collider) = 0;
258
259 /** Removes all colliders from the child list of this rigidbody. */
260 virtual void removeColliders() = 0;
261
262 /**
263 * Recalculates rigidbody's mass, inertia tensors and center of mass depending on the currently set child colliders.
264 * This should be called whenever relevant child collider properties change (like mass or shape).
265 *
266 * If automatic tensor calculation is turned off then this will do nothing. If automatic mass calculation is turned
267 * off then this will use the mass set directly on the body using setMass().
268 */
269 virtual void updateMassDistribution() { }
270
271 /**
272 * Creates a new rigidbody.
273 *
274 * @param[in] linkedSO Scene object that owns this rigidbody. All physics updates applied to this object
275 * will be transfered to this scene object (the movement/rotation resulting from
276 * those updates).
277 */
278 static SPtr<Rigidbody> create(const HSceneObject& linkedSO);
279
280 /** Triggered when one of the colliders owned by the rigidbody starts colliding with another object. */
281 Event<void(const CollisionDataRaw&)> onCollisionBegin;
282
283 /** Triggered when a previously colliding collider stays in collision. Triggered once per frame. */
284 Event<void(const CollisionDataRaw&)> onCollisionStay;
285
286 /** Triggered when one of the colliders owned by the rigidbody stops colliding with another object. */
287 Event<void(const CollisionDataRaw&)> onCollisionEnd;
288
289 /** @name Internal
290 * @{
291 */
292
293 /**
294 * Sets the priority of the physics update. Bodies with a higher priority will be updated before the bodies with
295 * lower priority. This allows you to control the order of updated in case rigidbodies are in some way dependant.
296 */
297 void _setPriority(UINT32 priority);
298
299 /** Sets a unique ID of the rigidbody, so it can be recognized by the physics system. */
300 void _setPhysicsId(UINT32 id) { mPhysicsId = id; }
301
302 /**
303 * Applies new transform values retrieved from the most recent physics update (values resulting from physics
304 * simulation).
305 */
306 void _setTransform(const Vector3& position, const Quaternion& rotation);
307
308 /**
309 * Sets the object that owns this physics object, if any. Used for high level systems so they can easily map their
310 * high level physics objects from the low level ones returned by various queries and events.
311 */
312 void _setOwner(PhysicsOwnerType type, void* owner) { mOwner.type = type; mOwner.ownerData = owner; }
313
314 /**
315 * Gets the object that owns this physics object, if any. Used for high level systems so they can easily map their
316 * high level physics objects from the low level ones returned by various queries and events.
317 */
318 void* _getOwner(PhysicsOwnerType type) const { return mOwner.type == type ? mOwner.ownerData : nullptr; }
319
320 /** @} */
321
322 protected:
323 RigidbodyFlag mFlags = RigidbodyFlag::None;
324 PhysicsObjectOwner mOwner;
325 UINT32 mPhysicsId = 0;
326 HSceneObject mLinkedSO;
327 };
328
329 /** @} */
330}