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