Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Body/Body.h
9912 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#include <Jolt/Core/NonCopyable.h>
8
#include <Jolt/Geometry/AABox.h>
9
#include <Jolt/Physics/Collision/Shape/Shape.h>
10
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
11
#include <Jolt/Physics/Collision/ObjectLayer.h>
12
#include <Jolt/Physics/Collision/CollisionGroup.h>
13
#include <Jolt/Physics/Collision/TransformedShape.h>
14
#include <Jolt/Physics/Body/MotionProperties.h>
15
#include <Jolt/Physics/Body/BodyID.h>
16
#include <Jolt/Physics/Body/BodyAccess.h>
17
#include <Jolt/Physics/Body/BodyType.h>
18
#include <Jolt/Core/StringTools.h>
19
20
JPH_NAMESPACE_BEGIN
21
22
class StateRecorder;
23
class BodyCreationSettings;
24
class SoftBodyCreationSettings;
25
26
/// A rigid body that can be simulated using the physics system
27
///
28
/// Note that internally all properties (position, velocity etc.) are tracked relative to the center of mass of the object to simplify the simulation of the object.
29
///
30
/// The offset between the position of the body and the center of mass position of the body is GetShape()->GetCenterOfMass().
31
/// The functions that get/set the position of the body all indicate if they are relative to the center of mass or to the original position in which the shape was created.
32
///
33
/// The linear velocity is also velocity of the center of mass, to correct for this: \f$VelocityCOM = Velocity - AngularVelocity \times ShapeCOM\f$.
34
class
35
#ifndef JPH_PLATFORM_DOXYGEN // Doxygen gets confused here
36
JPH_EXPORT_GCC_BUG_WORKAROUND alignas(JPH_RVECTOR_ALIGNMENT)
37
#endif
38
Body : public NonCopyable
39
{
40
public:
41
JPH_OVERRIDE_NEW_DELETE
42
43
/// Get the id of this body
44
inline const BodyID & GetID() const { return mID; }
45
46
/// Get the type of body (rigid or soft)
47
inline EBodyType GetBodyType() const { return mBodyType; }
48
49
/// Check if this body is a rigid body
50
inline bool IsRigidBody() const { return mBodyType == EBodyType::RigidBody; }
51
52
/// Check if this body is a soft body
53
inline bool IsSoftBody() const { return mBodyType == EBodyType::SoftBody; }
54
55
// See comment at GetIndexInActiveBodiesInternal for reasoning why TSAN is disabled here
56
JPH_TSAN_NO_SANITIZE
57
/// If this body is currently actively simulating (true) or sleeping (false)
58
inline bool IsActive() const { return mMotionProperties != nullptr && mMotionProperties->mIndexInActiveBodies != cInactiveIndex; }
59
60
/// Check if this body is static (not movable)
61
inline bool IsStatic() const { return mMotionType == EMotionType::Static; }
62
63
/// Check if this body is kinematic (keyframed), which means that it will move according to its current velocity, but forces don't affect it
64
inline bool IsKinematic() const { return mMotionType == EMotionType::Kinematic; }
65
66
/// Check if this body is dynamic, which means that it moves and forces can act on it
67
inline bool IsDynamic() const { return mMotionType == EMotionType::Dynamic; }
68
69
/// Check if a body could be made kinematic or dynamic (if it was created dynamic or with mAllowDynamicOrKinematic set to true)
70
inline bool CanBeKinematicOrDynamic() const { return mMotionProperties != nullptr; }
71
72
/// Change the body to a sensor. A sensor will receive collision callbacks, but will not cause any collision responses and can be used as a trigger volume.
73
/// The cheapest sensor (in terms of CPU usage) is a sensor with motion type Static (they can be moved around using BodyInterface::SetPosition/SetPositionAndRotation).
74
/// These sensors will only detect collisions with active Dynamic or Kinematic bodies. As soon as a body go to sleep, the contact point with the sensor will be lost.
75
/// If you make a sensor Dynamic or Kinematic and activate them, the sensor will be able to detect collisions with sleeping bodies too. An active sensor will never go to sleep automatically.
76
/// When you make a Dynamic or Kinematic sensor, make sure it is in an ObjectLayer that does not collide with Static bodies or other sensors to avoid extra overhead in the broad phase.
77
inline void SetIsSensor(bool inIsSensor) { JPH_ASSERT(IsRigidBody()); if (inIsSensor) mFlags.fetch_or(uint8(EFlags::IsSensor), memory_order_relaxed); else mFlags.fetch_and(uint8(~uint8(EFlags::IsSensor)), memory_order_relaxed); }
78
79
/// Check if this body is a sensor.
80
inline bool IsSensor() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::IsSensor)) != 0; }
81
82
/// If kinematic objects can generate contact points against other kinematic or static objects.
83
/// Note that turning this on can be CPU intensive as much more collision detection work will be done without any effect on the simulation (kinematic objects are not affected by other kinematic/static objects).
84
/// This can be used to make sensors detect static objects. Note that the sensor must be kinematic and active for it to detect static objects.
85
inline void SetCollideKinematicVsNonDynamic(bool inCollide) { JPH_ASSERT(IsRigidBody()); if (inCollide) mFlags.fetch_or(uint8(EFlags::CollideKinematicVsNonDynamic), memory_order_relaxed); else mFlags.fetch_and(uint8(~uint8(EFlags::CollideKinematicVsNonDynamic)), memory_order_relaxed); }
86
87
/// Check if kinematic objects can generate contact points against other kinematic or static objects.
88
inline bool GetCollideKinematicVsNonDynamic() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::CollideKinematicVsNonDynamic)) != 0; }
89
90
/// If PhysicsSettings::mUseManifoldReduction is true, this allows turning off manifold reduction for this specific body.
91
/// Manifold reduction by default will combine contacts with similar normals that come from different SubShapeIDs (e.g. different triangles in a mesh shape or different compound shapes).
92
/// If the application requires tracking exactly which SubShapeIDs are in contact, you can turn off manifold reduction. Note that this comes at a performance cost.
93
/// Consider using BodyInterface::SetUseManifoldReduction if the body could already be in contact with other bodies to ensure that the contact cache is invalidated and you get the correct contact callbacks.
94
inline void SetUseManifoldReduction(bool inUseReduction) { JPH_ASSERT(IsRigidBody()); if (inUseReduction) mFlags.fetch_or(uint8(EFlags::UseManifoldReduction), memory_order_relaxed); else mFlags.fetch_and(uint8(~uint8(EFlags::UseManifoldReduction)), memory_order_relaxed); }
95
96
/// Check if this body can use manifold reduction.
97
inline bool GetUseManifoldReduction() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::UseManifoldReduction)) != 0; }
98
99
/// Checks if the combination of this body and inBody2 should use manifold reduction
100
inline bool GetUseManifoldReductionWithBody(const Body &inBody2) const { return ((mFlags.load(memory_order_relaxed) & inBody2.mFlags.load(memory_order_relaxed)) & uint8(EFlags::UseManifoldReduction)) != 0; }
101
102
/// Set to indicate that the gyroscopic force should be applied to this body (aka Dzhanibekov effect, see https://en.wikipedia.org/wiki/Tennis_racket_theorem)
103
inline void SetApplyGyroscopicForce(bool inApply) { JPH_ASSERT(IsRigidBody()); if (inApply) mFlags.fetch_or(uint8(EFlags::ApplyGyroscopicForce), memory_order_relaxed); else mFlags.fetch_and(uint8(~uint8(EFlags::ApplyGyroscopicForce)), memory_order_relaxed); }
104
105
/// Check if the gyroscopic force is being applied for this body
106
inline bool GetApplyGyroscopicForce() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::ApplyGyroscopicForce)) != 0; }
107
108
/// Set to indicate that extra effort should be made to try to remove ghost contacts (collisions with internal edges of a mesh). This is more expensive but makes bodies move smoother over a mesh with convex edges.
109
inline void SetEnhancedInternalEdgeRemoval(bool inApply) { JPH_ASSERT(IsRigidBody()); if (inApply) mFlags.fetch_or(uint8(EFlags::EnhancedInternalEdgeRemoval), memory_order_relaxed); else mFlags.fetch_and(uint8(~uint8(EFlags::EnhancedInternalEdgeRemoval)), memory_order_relaxed); }
110
111
/// Check if enhanced internal edge removal is turned on
112
inline bool GetEnhancedInternalEdgeRemoval() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::EnhancedInternalEdgeRemoval)) != 0; }
113
114
/// Checks if the combination of this body and inBody2 should use enhanced internal edge removal
115
inline bool GetEnhancedInternalEdgeRemovalWithBody(const Body &inBody2) const { return ((mFlags.load(memory_order_relaxed) | inBody2.mFlags.load(memory_order_relaxed)) & uint8(EFlags::EnhancedInternalEdgeRemoval)) != 0; }
116
117
/// Get the bodies motion type.
118
inline EMotionType GetMotionType() const { return mMotionType; }
119
120
/// Set the motion type of this body. Consider using BodyInterface::SetMotionType instead of this function if the body may be active or if it needs to be activated.
121
void SetMotionType(EMotionType inMotionType);
122
123
/// Get broadphase layer, this determines in which broad phase sub-tree the object is placed
124
inline BroadPhaseLayer GetBroadPhaseLayer() const { return mBroadPhaseLayer; }
125
126
/// Get object layer, this determines which other objects it collides with
127
inline ObjectLayer GetObjectLayer() const { return mObjectLayer; }
128
129
/// Collision group and sub-group ID, determines which other objects it collides with
130
const CollisionGroup & GetCollisionGroup() const { return mCollisionGroup; }
131
CollisionGroup & GetCollisionGroup() { return mCollisionGroup; }
132
void SetCollisionGroup(const CollisionGroup &inGroup) { mCollisionGroup = inGroup; }
133
134
/// If this body can go to sleep. Note that disabling sleeping on a sleeping object will not wake it up.
135
bool GetAllowSleeping() const { return mMotionProperties->mAllowSleeping; }
136
void SetAllowSleeping(bool inAllow);
137
138
/// Resets the sleep timer. This does not wake up the body if it is sleeping, but allows resetting the system that detects when a body is sleeping.
139
inline void ResetSleepTimer();
140
141
/// Friction (dimensionless number, usually between 0 and 1, 0 = no friction, 1 = friction force equals force that presses the two bodies together). Note that bodies can have negative friction but the combined friction (see PhysicsSystem::SetCombineFriction) should never go below zero.
142
inline float GetFriction() const { return mFriction; }
143
void SetFriction(float inFriction) { mFriction = inFriction; }
144
145
/// Restitution (dimensionless number, usually between 0 and 1, 0 = completely inelastic collision response, 1 = completely elastic collision response). Note that bodies can have negative restitution but the combined restitution (see PhysicsSystem::SetCombineRestitution) should never go below zero.
146
inline float GetRestitution() const { return mRestitution; }
147
void SetRestitution(float inRestitution) { mRestitution = inRestitution; }
148
149
/// Get world space linear velocity of the center of mass (unit: m/s)
150
inline Vec3 GetLinearVelocity() const { return !IsStatic()? mMotionProperties->GetLinearVelocity() : Vec3::sZero(); }
151
152
/// Set world space linear velocity of the center of mass (unit: m/s).
153
/// If you want the body to wake up when it is sleeping, use BodyInterface::SetLinearVelocity instead.
154
void SetLinearVelocity(Vec3Arg inLinearVelocity) { JPH_ASSERT(!IsStatic()); mMotionProperties->SetLinearVelocity(inLinearVelocity); }
155
156
/// Set world space linear velocity of the center of mass, will make sure the value is clamped against the maximum linear velocity.
157
/// If you want the body to wake up when it is sleeping, use BodyInterface::SetLinearVelocity instead.
158
void SetLinearVelocityClamped(Vec3Arg inLinearVelocity) { JPH_ASSERT(!IsStatic()); mMotionProperties->SetLinearVelocityClamped(inLinearVelocity); }
159
160
/// Get world space angular velocity of the center of mass (unit: rad/s)
161
inline Vec3 GetAngularVelocity() const { return !IsStatic()? mMotionProperties->GetAngularVelocity() : Vec3::sZero(); }
162
163
/// Set world space angular velocity of the center of mass (unit: rad/s).
164
/// If you want the body to wake up when it is sleeping, use BodyInterface::SetAngularVelocity instead.
165
void SetAngularVelocity(Vec3Arg inAngularVelocity) { JPH_ASSERT(!IsStatic()); mMotionProperties->SetAngularVelocity(inAngularVelocity); }
166
167
/// Set world space angular velocity of the center of mass, will make sure the value is clamped against the maximum angular velocity.
168
/// If you want the body to wake up when it is sleeping, use BodyInterface::SetAngularVelocity instead.
169
void SetAngularVelocityClamped(Vec3Arg inAngularVelocity) { JPH_ASSERT(!IsStatic()); mMotionProperties->SetAngularVelocityClamped(inAngularVelocity); }
170
171
/// Velocity of point inPoint (in center of mass space, e.g. on the surface of the body) of the body (unit: m/s)
172
inline Vec3 GetPointVelocityCOM(Vec3Arg inPointRelativeToCOM) const { return !IsStatic()? mMotionProperties->GetPointVelocityCOM(inPointRelativeToCOM) : Vec3::sZero(); }
173
174
/// Velocity of point inPoint (in world space, e.g. on the surface of the body) of the body (unit: m/s)
175
inline Vec3 GetPointVelocity(RVec3Arg inPoint) const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess(), BodyAccess::EAccess::Read)); return GetPointVelocityCOM(Vec3(inPoint - mPosition)); }
176
177
/// Add force (unit: N) at center of mass for the next time step, will be reset after the next call to PhysicsSystem::Update.
178
/// If you want the body to wake up when it is sleeping, use BodyInterface::AddForce instead.
179
inline void AddForce(Vec3Arg inForce) { JPH_ASSERT(IsDynamic()); (Vec3::sLoadFloat3Unsafe(mMotionProperties->mForce) + inForce).StoreFloat3(&mMotionProperties->mForce); }
180
181
/// Add force (unit: N) at inPosition for the next time step, will be reset after the next call to PhysicsSystem::Update.
182
/// If you want the body to wake up when it is sleeping, use BodyInterface::AddForce instead.
183
inline void AddForce(Vec3Arg inForce, RVec3Arg inPosition);
184
185
/// Add torque (unit: N m) for the next time step, will be reset after the next call to PhysicsSystem::Update.
186
/// If you want the body to wake up when it is sleeping, use BodyInterface::AddTorque instead.
187
inline void AddTorque(Vec3Arg inTorque) { JPH_ASSERT(IsDynamic()); (Vec3::sLoadFloat3Unsafe(mMotionProperties->mTorque) + inTorque).StoreFloat3(&mMotionProperties->mTorque); }
188
189
// Get the total amount of force applied to the center of mass this time step (through AddForce calls). Note that it will reset to zero after PhysicsSystem::Update.
190
inline Vec3 GetAccumulatedForce() const { JPH_ASSERT(IsDynamic()); return mMotionProperties->GetAccumulatedForce(); }
191
192
// Get the total amount of torque applied to the center of mass this time step (through AddForce/AddTorque calls). Note that it will reset to zero after PhysicsSystem::Update.
193
inline Vec3 GetAccumulatedTorque() const { JPH_ASSERT(IsDynamic()); return mMotionProperties->GetAccumulatedTorque(); }
194
195
// Reset the total accumulated force, not that this will be done automatically after every time step.
196
JPH_INLINE void ResetForce() { JPH_ASSERT(IsDynamic()); return mMotionProperties->ResetForce(); }
197
198
// Reset the total accumulated torque, not that this will be done automatically after every time step.
199
JPH_INLINE void ResetTorque() { JPH_ASSERT(IsDynamic()); return mMotionProperties->ResetTorque(); }
200
201
// Reset the current velocity and accumulated force and torque.
202
JPH_INLINE void ResetMotion() { JPH_ASSERT(!IsStatic()); return mMotionProperties->ResetMotion(); }
203
204
/// Get inverse inertia tensor in world space
205
inline Mat44 GetInverseInertia() const;
206
207
/// Add impulse to center of mass (unit: kg m/s).
208
/// If you want the body to wake up when it is sleeping, use BodyInterface::AddImpulse instead.
209
inline void AddImpulse(Vec3Arg inImpulse);
210
211
/// Add impulse to point in world space (unit: kg m/s).
212
/// If you want the body to wake up when it is sleeping, use BodyInterface::AddImpulse instead.
213
inline void AddImpulse(Vec3Arg inImpulse, RVec3Arg inPosition);
214
215
/// Add angular impulse in world space (unit: N m s).
216
/// If you want the body to wake up when it is sleeping, use BodyInterface::AddAngularImpulse instead.
217
inline void AddAngularImpulse(Vec3Arg inAngularImpulse);
218
219
/// Set velocity of body such that it will be positioned at inTargetPosition/Rotation in inDeltaTime seconds.
220
/// If you want the body to wake up when it is sleeping, use BodyInterface::MoveKinematic instead.
221
void MoveKinematic(RVec3Arg inTargetPosition, QuatArg inTargetRotation, float inDeltaTime);
222
223
/// Gets the properties needed to do buoyancy calculations
224
/// @param inSurfacePosition Position of the fluid surface in world space
225
/// @param inSurfaceNormal Normal of the fluid surface (should point up)
226
/// @param outTotalVolume On return this contains the total volume of the shape
227
/// @param outSubmergedVolume On return this contains the submerged volume of the shape
228
/// @param outRelativeCenterOfBuoyancy On return this contains the center of mass of the submerged volume relative to the center of mass of the body
229
void GetSubmergedVolume(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNormal, float &outTotalVolume, float &outSubmergedVolume, Vec3 &outRelativeCenterOfBuoyancy) const;
230
231
/// Applies an impulse to the body that simulates fluid buoyancy and drag.
232
/// If you want the body to wake up when it is sleeping, use BodyInterface::ApplyBuoyancyImpulse instead.
233
/// @param inSurfacePosition Position of the fluid surface in world space
234
/// @param inSurfaceNormal Normal of the fluid surface (should point up)
235
/// @param inBuoyancy The buoyancy factor for the body. 1 = neutral body, < 1 sinks, > 1 floats. Note that we don't use the fluid density since it is harder to configure than a simple number between [0, 2]
236
/// @param inLinearDrag Linear drag factor that slows down the body when in the fluid (approx. 0.5)
237
/// @param inAngularDrag Angular drag factor that slows down rotation when the body is in the fluid (approx. 0.01)
238
/// @param inFluidVelocity The average velocity of the fluid (in m/s) in which the body resides
239
/// @param inGravity The gravity vector (pointing down)
240
/// @param inDeltaTime Delta time of the next simulation step (in s)
241
/// @return true if an impulse was applied, false if the body was not in the fluid
242
bool ApplyBuoyancyImpulse(RVec3Arg inSurfacePosition, Vec3Arg inSurfaceNormal, float inBuoyancy, float inLinearDrag, float inAngularDrag, Vec3Arg inFluidVelocity, Vec3Arg inGravity, float inDeltaTime);
243
244
/// Applies an impulse to the body that simulates fluid buoyancy and drag.
245
/// If you want the body to wake up when it is sleeping, use BodyInterface::ApplyBuoyancyImpulse instead.
246
/// @param inTotalVolume Total volume of the shape of this body (m^3)
247
/// @param inSubmergedVolume Submerged volume of the shape of this body (m^3)
248
/// @param inRelativeCenterOfBuoyancy The center of mass of the submerged volume relative to the center of mass of the body
249
/// @param inBuoyancy The buoyancy factor for the body. 1 = neutral body, < 1 sinks, > 1 floats. Note that we don't use the fluid density since it is harder to configure than a simple number between [0, 2]
250
/// @param inLinearDrag Linear drag factor that slows down the body when in the fluid (approx. 0.5)
251
/// @param inAngularDrag Angular drag factor that slows down rotation when the body is in the fluid (approx. 0.01)
252
/// @param inFluidVelocity The average velocity of the fluid (in m/s) in which the body resides
253
/// @param inGravity The gravity vector (pointing down)
254
/// @param inDeltaTime Delta time of the next simulation step (in s)
255
/// @return true if an impulse was applied, false if the body was not in the fluid
256
bool ApplyBuoyancyImpulse(float inTotalVolume, float inSubmergedVolume, Vec3Arg inRelativeCenterOfBuoyancy, float inBuoyancy, float inLinearDrag, float inAngularDrag, Vec3Arg inFluidVelocity, Vec3Arg inGravity, float inDeltaTime);
257
258
/// Check if this body has been added to the physics system
259
inline bool IsInBroadPhase() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::IsInBroadPhase)) != 0; }
260
261
/// Check if this body has been changed in such a way that the collision cache should be considered invalid for any body interacting with this body
262
inline bool IsCollisionCacheInvalid() const { return (mFlags.load(memory_order_relaxed) & uint8(EFlags::InvalidateContactCache)) != 0; }
263
264
/// Get the shape of this body
265
inline const Shape * GetShape() const { return mShape; }
266
267
/// World space position of the body
268
inline RVec3 GetPosition() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess(), BodyAccess::EAccess::Read)); return mPosition - mRotation * mShape->GetCenterOfMass(); }
269
270
/// World space rotation of the body
271
inline Quat GetRotation() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess(), BodyAccess::EAccess::Read)); return mRotation; }
272
273
/// Calculates the transform of this body
274
inline RMat44 GetWorldTransform() const;
275
276
/// Gets the world space position of this body's center of mass
277
inline RVec3 GetCenterOfMassPosition() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess(), BodyAccess::EAccess::Read)); return mPosition; }
278
279
/// Calculates the transform for this body's center of mass
280
inline RMat44 GetCenterOfMassTransform() const;
281
282
/// Calculates the inverse of the transform for this body's center of mass
283
inline RMat44 GetInverseCenterOfMassTransform() const;
284
285
/// Get world space bounding box
286
inline const AABox & GetWorldSpaceBounds() const { return mBounds; }
287
288
#ifdef JPH_ENABLE_ASSERTS
289
/// Validate that the cached bounding box of the body matches the actual bounding box of the body.
290
/// If this check fails then there are a number of possible causes:
291
/// 1. Shape is being modified without notifying the system of the change. E.g. if you modify a MutableCompoundShape
292
/// without calling BodyInterface::NotifyShapeChanged then there will be a mismatch between the cached bounding box
293
/// in the broad phase and the bounding box of the Shape.
294
/// 2. You are calling functions postfixed with 'Internal' which are not meant to be called by the application.
295
/// 3. If the actual bounds and cached bounds are very close, it could mean that you have a mismatch in floating
296
/// point unit state between threads. E.g. one thread has flush to zero (FTZ) or denormals are zero (DAZ) set and
297
/// the other thread does not. Or if the rounding mode differs between threads. This can cause small differences
298
/// in floating point calculations. If you are using JobSystemThreadPool you can use JobSystemThreadPool::SetThreadInitFunction
299
/// to initialize the floating point unit state.
300
inline void ValidateCachedBounds() const
301
{
302
AABox actual_body_bounds = mShape->GetWorldSpaceBounds(GetCenterOfMassTransform(), Vec3::sOne());
303
JPH_ASSERT(actual_body_bounds == mBounds, "Mismatch between cached bounding box and actual bounding box");
304
}
305
#endif // JPH_ENABLE_ASSERTS
306
307
/// Access to the motion properties
308
const MotionProperties *GetMotionProperties() const { JPH_ASSERT(!IsStatic()); return mMotionProperties; }
309
MotionProperties * GetMotionProperties() { JPH_ASSERT(!IsStatic()); return mMotionProperties; }
310
311
/// Access to the motion properties (version that does not check if the object is kinematic or dynamic)
312
const MotionProperties *GetMotionPropertiesUnchecked() const { return mMotionProperties; }
313
MotionProperties * GetMotionPropertiesUnchecked() { return mMotionProperties; }
314
315
/// Access to the user data, can be used for anything by the application
316
uint64 GetUserData() const { return mUserData; }
317
void SetUserData(uint64 inUserData) { mUserData = inUserData; }
318
319
/// Get surface normal of a particular sub shape and its world space surface position on this body
320
inline Vec3 GetWorldSpaceSurfaceNormal(const SubShapeID &inSubShapeID, RVec3Arg inPosition) const;
321
322
/// Get the transformed shape of this body, which can be used to do collision detection outside of a body lock
323
inline TransformedShape GetTransformedShape() const { JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess(), BodyAccess::EAccess::Read)); return TransformedShape(mPosition, mRotation, mShape, mID); }
324
325
/// Debug function to convert a body back to a body creation settings object to be able to save/recreate the body later
326
BodyCreationSettings GetBodyCreationSettings() const;
327
328
/// Debug function to convert a soft body back to a soft body creation settings object to be able to save/recreate the body later
329
SoftBodyCreationSettings GetSoftBodyCreationSettings() const;
330
331
/// A dummy body that can be used by constraints to attach a constraint to the world instead of another body
332
static Body sFixedToWorld;
333
334
///@name THESE FUNCTIONS ARE FOR INTERNAL USE ONLY AND SHOULD NOT BE CALLED BY THE APPLICATION
335
///@{
336
337
/// Helper function for BroadPhase::FindCollidingPairs that returns true when two bodies can collide
338
/// It assumes that body 1 is dynamic and active and guarantees that it body 1 collides with body 2 that body 2 will not collide with body 1 in order to avoid finding duplicate collision pairs
339
static inline bool sFindCollidingPairsCanCollide(const Body &inBody1, const Body &inBody2);
340
341
/// Update position using an Euler step (used during position integrate & constraint solving)
342
inline void AddPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime) { JPH_ASSERT(IsRigidBody()); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess(), BodyAccess::EAccess::ReadWrite)); mPosition += mMotionProperties->LockTranslation(inLinearVelocityTimesDeltaTime); JPH_ASSERT(!mPosition.IsNaN()); }
343
inline void SubPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime) { JPH_ASSERT(IsRigidBody()); JPH_ASSERT(BodyAccess::sCheckRights(BodyAccess::sPositionAccess(), BodyAccess::EAccess::ReadWrite)); mPosition -= mMotionProperties->LockTranslation(inLinearVelocityTimesDeltaTime); JPH_ASSERT(!mPosition.IsNaN()); }
344
345
/// Update rotation using an Euler step (used during position integrate & constraint solving)
346
inline void AddRotationStep(Vec3Arg inAngularVelocityTimesDeltaTime);
347
inline void SubRotationStep(Vec3Arg inAngularVelocityTimesDeltaTime);
348
349
/// Flag if body is in the broadphase (should only be called by the BroadPhase)
350
inline void SetInBroadPhaseInternal(bool inInBroadPhase) { if (inInBroadPhase) mFlags.fetch_or(uint8(EFlags::IsInBroadPhase), memory_order_relaxed); else mFlags.fetch_and(uint8(~uint8(EFlags::IsInBroadPhase)), memory_order_relaxed); }
351
352
/// Invalidate the contact cache (should only be called by the BodyManager), will be reset the next simulation step. Returns true if the contact cache was still valid.
353
inline bool InvalidateContactCacheInternal() { return (mFlags.fetch_or(uint8(EFlags::InvalidateContactCache), memory_order_relaxed) & uint8(EFlags::InvalidateContactCache)) == 0; }
354
355
/// Reset the collision cache invalid flag (should only be called by the BodyManager).
356
inline void ValidateContactCacheInternal() { JPH_IF_ENABLE_ASSERTS(uint8 old_val = ) mFlags.fetch_and(uint8(~uint8(EFlags::InvalidateContactCache)), memory_order_relaxed); JPH_ASSERT((old_val & uint8(EFlags::InvalidateContactCache)) != 0); }
357
358
/// Updates world space bounding box (should only be called by the PhysicsSystem)
359
void CalculateWorldSpaceBoundsInternal();
360
361
/// Function to update body's position (should only be called by the BodyInterface since it also requires updating the broadphase)
362
void SetPositionAndRotationInternal(RVec3Arg inPosition, QuatArg inRotation, bool inResetSleepTimer = true);
363
364
/// Updates the center of mass and optionally mass properties after shifting the center of mass or changes to the shape (should only be called by the BodyInterface since it also requires updating the broadphase)
365
/// @param inPreviousCenterOfMass Center of mass of the shape before the alterations
366
/// @param inUpdateMassProperties When true, the mass and inertia tensor is recalculated
367
void UpdateCenterOfMassInternal(Vec3Arg inPreviousCenterOfMass, bool inUpdateMassProperties);
368
369
/// Function to update a body's shape (should only be called by the BodyInterface since it also requires updating the broadphase)
370
/// @param inShape The new shape for this body
371
/// @param inUpdateMassProperties When true, the mass and inertia tensor is recalculated
372
void SetShapeInternal(const Shape *inShape, bool inUpdateMassProperties);
373
374
// TSAN detects a race between BodyManager::AddBodyToActiveBodies coming from PhysicsSystem::ProcessBodyPair and Body::GetIndexInActiveBodiesInternal coming from PhysicsSystem::ProcessBodyPair.
375
// When PhysicsSystem::ProcessBodyPair activates a body, it updates mIndexInActiveBodies and then updates BodyManager::mNumActiveBodies with release semantics. PhysicsSystem::ProcessBodyPair will
376
// then finish its loop of active bodies and at the end of the loop it will read BodyManager::mNumActiveBodies with acquire semantics to see if any bodies were activated during the loop.
377
// This means that changes to mIndexInActiveBodies must be visible to the thread, so TSANs report must be a false positive. We suppress the warning here.
378
JPH_TSAN_NO_SANITIZE
379
/// Access to the index in the BodyManager::mActiveBodies list
380
uint32 GetIndexInActiveBodiesInternal() const { return mMotionProperties != nullptr? mMotionProperties->mIndexInActiveBodies : cInactiveIndex; }
381
382
/// Update eligibility for sleeping
383
ECanSleep UpdateSleepStateInternal(float inDeltaTime, float inMaxMovement, float inTimeBeforeSleep);
384
385
/// Saving state for replay
386
void SaveState(StateRecorder &inStream) const;
387
388
/// Restoring state for replay
389
void RestoreState(StateRecorder &inStream);
390
391
///@}
392
393
static constexpr uint32 cInactiveIndex = MotionProperties::cInactiveIndex; ///< Constant indicating that body is not active
394
395
private:
396
friend class BodyManager;
397
friend class BodyWithMotionProperties;
398
friend class SoftBodyWithMotionPropertiesAndShape;
399
400
Body() = default; ///< Bodies must be created through BodyInterface::CreateBody
401
402
explicit Body(bool); ///< Alternative constructor that initializes all members
403
404
~Body() { JPH_ASSERT(mMotionProperties == nullptr); } ///< Bodies must be destroyed through BodyInterface::DestroyBody
405
406
inline void GetSleepTestPoints(RVec3 *outPoints) const; ///< Determine points to test for checking if body is sleeping: COM, COM + largest bounding box axis, COM + second largest bounding box axis
407
408
enum class EFlags : uint8
409
{
410
IsSensor = 1 << 0, ///< If this object is a sensor. A sensor will receive collision callbacks, but will not cause any collision responses and can be used as a trigger volume.
411
CollideKinematicVsNonDynamic = 1 << 1, ///< If kinematic objects can generate contact points against other kinematic or static objects.
412
IsInBroadPhase = 1 << 2, ///< Set this bit to indicate that the body is in the broadphase
413
InvalidateContactCache = 1 << 3, ///< Set this bit to indicate that all collision caches for this body are invalid, will be reset the next simulation step.
414
UseManifoldReduction = 1 << 4, ///< Set this bit to indicate that this body can use manifold reduction (if PhysicsSettings::mUseManifoldReduction is true)
415
ApplyGyroscopicForce = 1 << 5, ///< Set this bit to indicate that the gyroscopic force should be applied to this body (aka Dzhanibekov effect, see https://en.wikipedia.org/wiki/Tennis_racket_theorem)
416
EnhancedInternalEdgeRemoval = 1 << 6, ///< Set this bit to indicate that enhanced internal edge removal should be used for this body (see BodyCreationSettings::mEnhancedInternalEdgeRemoval)
417
};
418
419
// 16 byte aligned
420
RVec3 mPosition; ///< World space position of center of mass
421
Quat mRotation; ///< World space rotation of center of mass
422
AABox mBounds; ///< World space bounding box of the body
423
424
// 8 byte aligned
425
RefConst<Shape> mShape; ///< Shape representing the volume of this body
426
MotionProperties * mMotionProperties = nullptr; ///< If this is a keyframed or dynamic object, this object holds all information about the movement
427
uint64 mUserData = 0; ///< User data, can be used for anything by the application
428
CollisionGroup mCollisionGroup; ///< The collision group this body belongs to (determines if two objects can collide)
429
430
// 4 byte aligned
431
float mFriction; ///< Friction of the body (dimensionless number, usually between 0 and 1, 0 = no friction, 1 = friction force equals force that presses the two bodies together). Note that bodies can have negative friction but the combined friction (see PhysicsSystem::SetCombineFriction) should never go below zero.
432
float mRestitution; ///< Restitution of body (dimensionless number, usually between 0 and 1, 0 = completely inelastic collision response, 1 = completely elastic collision response). Note that bodies can have negative restitution but the combined restitution (see PhysicsSystem::SetCombineRestitution) should never go below zero.
433
BodyID mID; ///< ID of the body (index in the bodies array)
434
435
// 2 or 4 bytes aligned
436
ObjectLayer mObjectLayer; ///< The collision layer this body belongs to (determines if two objects can collide)
437
438
// 1 byte aligned
439
EBodyType mBodyType; ///< Type of body (rigid or soft)
440
BroadPhaseLayer mBroadPhaseLayer; ///< The broad phase layer this body belongs to
441
EMotionType mMotionType; ///< Type of motion (static, dynamic or kinematic)
442
atomic<uint8> mFlags = 0; ///< See EFlags for possible flags
443
444
// 122 bytes up to here (64-bit mode, single precision, 16-bit ObjectLayer)
445
};
446
447
static_assert(JPH_CPU_ADDRESS_BITS != 64 || sizeof(Body) == JPH_IF_SINGLE_PRECISION_ELSE(128, 160), "Body size is incorrect");
448
static_assert(alignof(Body) == JPH_RVECTOR_ALIGNMENT, "Body should properly align");
449
450
JPH_NAMESPACE_END
451
452
#include "Body.inl"
453
454