Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Character/CharacterVirtual.h
21798 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/Physics/Character/CharacterBase.h>
8
#include <Jolt/Physics/Character/CharacterID.h>
9
#include <Jolt/Physics/Body/MotionType.h>
10
#include <Jolt/Physics/Body/BodyFilter.h>
11
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
12
#include <Jolt/Physics/Collision/ObjectLayer.h>
13
#include <Jolt/Physics/Collision/TransformedShape.h>
14
#include <Jolt/Core/STLTempAllocator.h>
15
16
JPH_NAMESPACE_BEGIN
17
18
class CharacterVirtual;
19
class CollideShapeSettings;
20
21
/// Contains the configuration of a character
22
class JPH_EXPORT CharacterVirtualSettings : public CharacterBaseSettings
23
{
24
public:
25
JPH_OVERRIDE_NEW_DELETE
26
27
/// Constructor
28
CharacterVirtualSettings() = default;
29
CharacterVirtualSettings(const CharacterVirtualSettings &) = default;
30
CharacterVirtualSettings & operator = (const CharacterVirtualSettings &) = default;
31
32
/// ID to give to this character. This is used for deterministically sorting and as an identifier to represent the character in the contact removal callback.
33
CharacterID mID = CharacterID::sNextCharacterID();
34
35
/// Character mass (kg). Used to push down objects with gravity when the character is standing on top.
36
float mMass = 70.0f;
37
38
/// Maximum force with which the character can push other bodies (N).
39
float mMaxStrength = 100.0f;
40
41
/// An extra offset applied to the shape in local space. This allows applying an extra offset to the shape in local space.
42
Vec3 mShapeOffset = Vec3::sZero();
43
44
///@name Movement settings
45
EBackFaceMode mBackFaceMode = EBackFaceMode::CollideWithBackFaces; ///< When colliding with back faces, the character will not be able to move through back facing triangles. Use this if you have triangles that need to collide on both sides.
46
float mPredictiveContactDistance = 0.1f; ///< How far to scan outside of the shape for predictive contacts. A value of 0 will most likely cause the character to get stuck as it cannot properly calculate a sliding direction anymore. A value that's too high will cause ghost collisions.
47
uint mMaxCollisionIterations = 5; ///< Max amount of collision loops
48
uint mMaxConstraintIterations = 15; ///< How often to try stepping in the constraint solving
49
float mMinTimeRemaining = 1.0e-4f; ///< Early out condition: If this much time is left to simulate we are done
50
float mCollisionTolerance = 1.0e-3f; ///< How far we're willing to penetrate geometry
51
float mCharacterPadding = 0.02f; ///< How far we try to stay away from the geometry, this ensures that the sweep will hit as little as possible lowering the collision cost and reducing the risk of getting stuck
52
uint mMaxNumHits = 256; ///< Max num hits to collect in order to avoid excess of contact points collection
53
float mHitReductionCosMaxAngle = 0.999f; ///< Cos(angle) where angle is the maximum angle between two hits contact normals that are allowed to be merged during hit reduction. Default is around 2.5 degrees. Set to -1 to turn off.
54
float mPenetrationRecoverySpeed = 1.0f; ///< This value governs how fast a penetration will be resolved, 0 = nothing is resolved, 1 = everything in one update
55
56
/// This character can optionally have an inner rigid body. This rigid body can be used to give the character presence in the world. When set it means that:
57
/// - Regular collision checks (e.g. NarrowPhaseQuery::CastRay) will collide with the rigid body (they cannot collide with CharacterVirtual since it is not added to the broad phase)
58
/// - Regular contact callbacks will be called through the ContactListener (next to the ones that will be passed to the CharacterContactListener)
59
/// - Fast moving objects of motion quality LinearCast will not be able to pass through the CharacterVirtual in 1 time step
60
RefConst<Shape> mInnerBodyShape;
61
62
/// For a deterministic simulation, it is important to have a deterministic body ID. When set and when mInnerBodyShape is specified,
63
/// the inner body will be created with this specified ID instead of a generated ID.
64
BodyID mInnerBodyIDOverride;
65
66
/// Layer that the inner rigid body will be added to
67
ObjectLayer mInnerBodyLayer = 0;
68
};
69
70
/// This class contains settings that allow you to override the behavior of a character's collision response
71
class CharacterContactSettings
72
{
73
public:
74
/// True when the object can push the virtual character.
75
bool mCanPushCharacter = true;
76
77
/// True when the virtual character can apply impulses (push) the body.
78
/// Note that this only works against rigid bodies. Other CharacterVirtual objects can only be moved in their own update,
79
/// so you must ensure that in their OnCharacterContactAdded mCanPushCharacter is true.
80
bool mCanReceiveImpulses = true;
81
};
82
83
/// This class receives callbacks when a virtual character hits something.
84
class JPH_EXPORT CharacterContactListener
85
{
86
public:
87
/// Destructor
88
virtual ~CharacterContactListener() = default;
89
90
/// Callback to adjust the velocity of a body as seen by the character. Can be adjusted to e.g. implement a conveyor belt or an inertial dampener system of a sci-fi space ship.
91
/// Note that inBody2 is locked during the callback so you can read its properties freely.
92
virtual void OnAdjustBodyVelocity(const CharacterVirtual *inCharacter, const Body &inBody2, Vec3 &ioLinearVelocity, Vec3 &ioAngularVelocity) { /* Do nothing, the linear and angular velocity are already filled in */ }
93
94
/// Checks if a character can collide with specified body. Return true if the contact is valid.
95
virtual bool OnContactValidate(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2) { return true; }
96
97
/// Same as OnContactValidate but when colliding with a CharacterVirtual
98
virtual bool OnCharacterContactValidate(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2) { return true; }
99
100
/// Called whenever the character collides with a body for the first time.
101
/// @param inCharacter Character that is being solved
102
/// @param inBodyID2 Body ID of body that is being hit
103
/// @param inSubShapeID2 Sub shape ID of shape that is being hit
104
/// @param inContactPosition World space contact position
105
/// @param inContactNormal World space contact normal
106
/// @param ioSettings Settings returned by the contact callback to indicate how the character should behave
107
virtual void OnContactAdded(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ }
108
109
/// Called whenever the character persists colliding with a body.
110
/// @param inCharacter Character that is being solved
111
/// @param inBodyID2 Body ID of body that is being hit
112
/// @param inSubShapeID2 Sub shape ID of shape that is being hit
113
/// @param inContactPosition World space contact position
114
/// @param inContactNormal World space contact normal
115
/// @param ioSettings Settings returned by the contact callback to indicate how the character should behave
116
virtual void OnContactPersisted(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ }
117
118
/// Called whenever the character loses contact with a body.
119
/// Note that there is no guarantee that the body or its sub shape still exists at this point. The body may have been deleted since the last update.
120
/// @param inCharacter Character that is being solved
121
/// @param inBodyID2 Body ID of body that is being hit
122
/// @param inSubShapeID2 Sub shape ID of shape that is being hit
123
virtual void OnContactRemoved(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2) { /* Default do nothing */ }
124
125
/// Same as OnContactAdded but when colliding with a CharacterVirtual
126
virtual void OnCharacterContactAdded(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ }
127
128
/// Same as OnContactPersisted but when colliding with a CharacterVirtual
129
virtual void OnCharacterContactPersisted(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ }
130
131
/// Same as OnContactRemoved but when colliding with a CharacterVirtual
132
/// Note that inOtherCharacterID can be the ID of a character that has been deleted. This happens if the character was in contact with this character during the last update, but has been deleted since.
133
virtual void OnCharacterContactRemoved(const CharacterVirtual *inCharacter, const CharacterID &inOtherCharacterID, const SubShapeID &inSubShapeID2) { /* Default do nothing */ }
134
135
/// Called whenever a contact is being used by the solver. Allows the listener to override the resulting character velocity (e.g. by preventing sliding along certain surfaces).
136
/// @param inCharacter Character that is being solved
137
/// @param inBodyID2 Body ID of body that is being hit
138
/// @param inSubShapeID2 Sub shape ID of shape that is being hit
139
/// @param inContactPosition World space contact position
140
/// @param inContactNormal World space contact normal
141
/// @param inContactVelocity World space velocity of contact point (e.g. for a moving platform)
142
/// @param inContactMaterial Material of contact point
143
/// @param inCharacterVelocity World space velocity of the character prior to hitting this contact
144
/// @param ioNewCharacterVelocity Contains the calculated world space velocity of the character after hitting this contact, this velocity slides along the surface of the contact. Can be modified by the listener to provide an alternative velocity.
145
virtual void OnContactSolve(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, Vec3Arg inContactVelocity, const PhysicsMaterial *inContactMaterial, Vec3Arg inCharacterVelocity, Vec3 &ioNewCharacterVelocity) { /* Default do nothing */ }
146
147
/// Same as OnContactSolve but when colliding with a CharacterVirtual
148
virtual void OnCharacterContactSolve(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, Vec3Arg inContactVelocity, const PhysicsMaterial *inContactMaterial, Vec3Arg inCharacterVelocity, Vec3 &ioNewCharacterVelocity) { /* Default do nothing */ }
149
};
150
151
/// Interface class that allows a CharacterVirtual to check collision with other CharacterVirtual instances.
152
/// Since CharacterVirtual instances are not registered anywhere, it is up to the application to test collision against relevant characters.
153
/// The characters could be stored in a tree structure to make this more efficient.
154
class JPH_EXPORT CharacterVsCharacterCollision : public NonCopyable
155
{
156
public:
157
virtual ~CharacterVsCharacterCollision() = default;
158
159
/// Collide a character against other CharacterVirtuals.
160
/// @param inCharacter The character to collide.
161
/// @param inCenterOfMassTransform Center of mass transform for this character.
162
/// @param inCollideShapeSettings Settings for the collision check.
163
/// @param inBaseOffset All hit results will be returned relative to this offset, can be zero to get results in world position, but when you're testing far from the origin you get better precision by picking a position that's closer e.g. GetPosition() since floats are most accurate near the origin
164
/// @param ioCollector Collision collector that receives the collision results.
165
virtual void CollideCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector) const = 0;
166
167
/// Cast a character against other CharacterVirtuals.
168
/// @param inCharacter The character to cast.
169
/// @param inCenterOfMassTransform Center of mass transform for this character.
170
/// @param inDirection Direction and length to cast in.
171
/// @param inShapeCastSettings Settings for the shape cast.
172
/// @param inBaseOffset All hit results will be returned relative to this offset, can be zero to get results in world position, but when you're testing far from the origin you get better precision by picking a position that's closer e.g. GetPosition() since floats are most accurate near the origin
173
/// @param ioCollector Collision collector that receives the collision results.
174
virtual void CastCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, Vec3Arg inDirection, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector) const = 0;
175
};
176
177
/// Simple collision checker that loops over all registered characters.
178
/// This is a brute force checking algorithm. If you have a lot of characters you may want to store your characters
179
/// in a hierarchical structure to make this more efficient.
180
/// Note that this is not thread safe, so make sure that only one CharacterVirtual is checking collision at a time.
181
class JPH_EXPORT CharacterVsCharacterCollisionSimple : public CharacterVsCharacterCollision
182
{
183
public:
184
/// Add a character to the list of characters to check collision against.
185
void Add(CharacterVirtual *inCharacter) { mCharacters.push_back(inCharacter); }
186
187
/// Remove a character from the list of characters to check collision against.
188
void Remove(const CharacterVirtual *inCharacter);
189
190
// See: CharacterVsCharacterCollision
191
virtual void CollideCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector) const override;
192
virtual void CastCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, Vec3Arg inDirection, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector) const override;
193
194
Array<CharacterVirtual *> mCharacters; ///< The list of characters to check collision against
195
};
196
197
/// Runtime character object.
198
/// This object usually represents the player. Contrary to the Character class it doesn't use a rigid body but moves doing collision checks only (hence the name virtual).
199
/// The advantage of this is that you can determine when the character moves in the frame (usually this has to happen at a very particular point in the frame)
200
/// but the downside is that other objects don't see this virtual character. To make a CharacterVirtual visible to the simulation, you can optionally create an inner
201
/// rigid body through CharacterVirtualSettings::mInnerBodyShape. A CharacterVirtual is not tracked by the PhysicsSystem so you need to update it yourself. This also means
202
/// that a call to PhysicsSystem::SaveState will not save its state, you need to call CharacterVirtual::SaveState yourself.
203
class JPH_EXPORT CharacterVirtual : public CharacterBase
204
{
205
public:
206
JPH_OVERRIDE_NEW_DELETE
207
208
/// Constructor
209
/// @param inSettings The settings for the character
210
/// @param inPosition Initial position for the character
211
/// @param inRotation Initial rotation for the character (usually only around the up-axis)
212
/// @param inUserData Application specific value
213
/// @param inSystem Physics system that this character will be added to
214
CharacterVirtual(const CharacterVirtualSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, uint64 inUserData, PhysicsSystem *inSystem);
215
216
/// Constructor without user data
217
CharacterVirtual(const CharacterVirtualSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, PhysicsSystem *inSystem) : CharacterVirtual(inSettings, inPosition, inRotation, 0, inSystem) { }
218
219
/// Destructor
220
virtual ~CharacterVirtual() override;
221
222
/// The ID of this character
223
inline const CharacterID & GetID() const { return mID; }
224
225
/// Set the contact listener
226
void SetListener(CharacterContactListener *inListener) { mListener = inListener; }
227
228
/// Get the current contact listener
229
CharacterContactListener * GetListener() const { return mListener; }
230
231
/// Set the character vs character collision interface
232
void SetCharacterVsCharacterCollision(CharacterVsCharacterCollision *inCharacterVsCharacterCollision) { mCharacterVsCharacterCollision = inCharacterVsCharacterCollision; }
233
234
/// Get the linear velocity of the character (m / s)
235
Vec3 GetLinearVelocity() const { return mLinearVelocity; }
236
237
/// Set the linear velocity of the character (m / s)
238
void SetLinearVelocity(Vec3Arg inLinearVelocity) { mLinearVelocity = inLinearVelocity; }
239
240
/// Get the position of the character
241
RVec3 GetPosition() const { return mPosition; }
242
243
/// Set the position of the character
244
void SetPosition(RVec3Arg inPosition) { mPosition = inPosition; UpdateInnerBodyTransform(); }
245
246
/// Get the rotation of the character
247
Quat GetRotation() const { return mRotation; }
248
249
/// Set the rotation of the character
250
void SetRotation(QuatArg inRotation) { mRotation = inRotation; UpdateInnerBodyTransform(); }
251
252
// Get the center of mass position of the shape
253
inline RVec3 GetCenterOfMassPosition() const { return mPosition + (mRotation * (mShapeOffset + mShape->GetCenterOfMass()) + mCharacterPadding * mUp); }
254
255
/// Calculate the world transform of the character
256
RMat44 GetWorldTransform() const { return RMat44::sRotationTranslation(mRotation, mPosition); }
257
258
/// Calculates the transform for this character's center of mass
259
RMat44 GetCenterOfMassTransform() const { return GetCenterOfMassTransform(mPosition, mRotation, mShape); }
260
261
/// Character mass (kg)
262
float GetMass() const { return mMass; }
263
void SetMass(float inMass) { mMass = inMass; }
264
265
/// Maximum force with which the character can push other bodies (N)
266
float GetMaxStrength() const { return mMaxStrength; }
267
void SetMaxStrength(float inMaxStrength) { mMaxStrength = inMaxStrength; }
268
269
/// This value governs how fast a penetration will be resolved, 0 = nothing is resolved, 1 = everything in one update
270
float GetPenetrationRecoverySpeed() const { return mPenetrationRecoverySpeed; }
271
void SetPenetrationRecoverySpeed(float inSpeed) { mPenetrationRecoverySpeed = inSpeed; }
272
273
/// 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.
274
bool GetEnhancedInternalEdgeRemoval() const { return mEnhancedInternalEdgeRemoval; }
275
void SetEnhancedInternalEdgeRemoval(bool inApply) { mEnhancedInternalEdgeRemoval = inApply; }
276
277
/// Character padding
278
float GetCharacterPadding() const { return mCharacterPadding; }
279
280
/// Max num hits to collect in order to avoid excess of contact points collection
281
uint GetMaxNumHits() const { return mMaxNumHits; }
282
void SetMaxNumHits(uint inMaxHits) { mMaxNumHits = inMaxHits; }
283
284
/// Cos(angle) where angle is the maximum angle between two hits contact normals that are allowed to be merged during hit reduction. Default is around 2.5 degrees. Set to -1 to turn off.
285
float GetHitReductionCosMaxAngle() const { return mHitReductionCosMaxAngle; }
286
void SetHitReductionCosMaxAngle(float inCosMaxAngle) { mHitReductionCosMaxAngle = inCosMaxAngle; }
287
288
/// Returns if we exceeded the maximum number of hits during the last collision check and had to discard hits based on distance.
289
/// This can be used to find areas that have too complex geometry for the character to navigate properly.
290
/// To solve you can either increase the max number of hits or simplify the geometry. Note that the character simulation will
291
/// try to do its best to select the most relevant contacts to avoid the character from getting stuck.
292
bool GetMaxHitsExceeded() const { return mMaxHitsExceeded; }
293
294
/// An extra offset applied to the shape in local space. This allows applying an extra offset to the shape in local space. Note that setting it on the fly can cause the shape to teleport into collision.
295
Vec3 GetShapeOffset() const { return mShapeOffset; }
296
void SetShapeOffset(Vec3Arg inShapeOffset) { mShapeOffset = inShapeOffset; UpdateInnerBodyTransform(); }
297
298
/// Access to the user data, can be used for anything by the application
299
uint64 GetUserData() const { return mUserData; }
300
void SetUserData(uint64 inUserData);
301
302
/// Optional inner rigid body that proxies the character in the world. Can be used to update body properties.
303
BodyID GetInnerBodyID() const { return mInnerBodyID; }
304
305
/// This function can be called prior to calling Update() to convert a desired velocity into a velocity that won't make the character move further onto steep slopes.
306
/// This velocity can then be set on the character using SetLinearVelocity()
307
/// @param inDesiredVelocity Velocity to clamp against steep walls
308
/// @return A new velocity vector that won't make the character move up steep slopes
309
Vec3 CancelVelocityTowardsSteepSlopes(Vec3Arg inDesiredVelocity) const;
310
311
/// This function is internally called by Update, WalkStairs, StickToFloor and ExtendedUpdate and is responsible for tracking if contacts are added, persisted or removed.
312
/// If you want to do multiple operations on a character (e.g. first Update then WalkStairs), you can surround the code with a StartTrackingContactChanges and FinishTrackingContactChanges pair
313
/// to only receive a single callback per contact on the CharacterContactListener. If you don't do this then you could for example receive a contact added callback during the Update and a
314
/// contact persisted callback during WalkStairs.
315
void StartTrackingContactChanges();
316
317
/// This call triggers contact removal callbacks and is used in conjunction with StartTrackingContactChanges.
318
void FinishTrackingContactChanges();
319
320
/// This is the main update function. It moves the character according to its current velocity (the character is similar to a kinematic body in the sense
321
/// that you set the velocity and the character will follow unless collision is blocking the way). Note it's your own responsibility to apply gravity to the character velocity!
322
/// Different surface materials (like ice) can be emulated by getting the ground material and adjusting the velocity and/or the max slope angle accordingly every frame.
323
/// @param inDeltaTime Time step to simulate.
324
/// @param inGravity Gravity vector (m/s^2). This gravity vector is only used when the character is standing on top of another object to apply downward force.
325
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
326
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
327
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
328
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
329
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
330
void Update(float inDeltaTime, Vec3Arg inGravity, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
331
332
/// This function will return true if the character has moved into a slope that is too steep (e.g. a vertical wall).
333
/// You would call WalkStairs to attempt to step up stairs.
334
/// @param inLinearVelocity The linear velocity that the player desired. This is used to determine if we're pushing into a step.
335
bool CanWalkStairs(Vec3Arg inLinearVelocity) const;
336
337
/// When stair walking is needed, you can call the WalkStairs function to cast up, forward and down again to try to find a valid position
338
/// @param inDeltaTime Time step to simulate.
339
/// @param inStepUp The direction and distance to step up (this corresponds to the max step height)
340
/// @param inStepForward The direction and distance to step forward after the step up
341
/// @param inStepForwardTest When running at a high frequency, inStepForward can be very small and it's likely that you hit the side of the stairs on the way down. This could produce a normal that violates the max slope angle. If this happens, we test again using this distance from the up position to see if we find a valid slope.
342
/// @param inStepDownExtra An additional translation that is added when stepping down at the end. Allows you to step further down than up. Set to zero if you don't want this. Should be in the opposite direction of up.
343
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
344
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
345
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
346
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
347
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
348
/// @return true if the stair walk was successful
349
bool WalkStairs(float inDeltaTime, Vec3Arg inStepUp, Vec3Arg inStepForward, Vec3Arg inStepForwardTest, Vec3Arg inStepDownExtra, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
350
351
/// This function can be used to artificially keep the character to the floor. Normally when a character is on a small step and starts moving horizontally, the character will
352
/// lose contact with the floor because the initial vertical velocity is zero while the horizontal velocity is quite high. To prevent the character from losing contact with the floor,
353
/// we do an additional collision check downwards and if we find the floor within a certain distance, we project the character onto the floor.
354
/// @param inStepDown Max amount to project the character downwards (if no floor is found within this distance, the function will return false)
355
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
356
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
357
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
358
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
359
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
360
/// @return True if the character was successfully projected onto the floor.
361
bool StickToFloor(Vec3Arg inStepDown, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
362
363
/// Settings struct with settings for ExtendedUpdate
364
struct ExtendedUpdateSettings
365
{
366
Vec3 mStickToFloorStepDown { 0, -0.5f, 0 }; ///< See StickToFloor inStepDown parameter. Can be zero to turn off.
367
Vec3 mWalkStairsStepUp { 0, 0.4f, 0 }; ///< See WalkStairs inStepUp parameter. Can be zero to turn off.
368
float mWalkStairsMinStepForward { 0.02f }; ///< See WalkStairs inStepForward parameter. Note that the parameter only indicates a magnitude, direction is taken from current velocity.
369
float mWalkStairsStepForwardTest { 0.15f }; ///< See WalkStairs inStepForwardTest parameter. Note that the parameter only indicates a magnitude, direction is taken from current velocity.
370
float mWalkStairsCosAngleForwardContact { Cos(DegreesToRadians(75.0f)) }; ///< Cos(angle) where angle is the maximum angle between the ground normal in the horizontal plane and the character forward vector where we're willing to adjust the step forward test towards the contact normal.
371
Vec3 mWalkStairsStepDownExtra { Vec3::sZero() }; ///< See WalkStairs inStepDownExtra
372
};
373
374
/// This function combines Update, StickToFloor and WalkStairs. This function serves as an example of how these functions could be combined.
375
/// Before calling, call SetLinearVelocity to update the horizontal/vertical speed of the character, typically this is:
376
/// - When on OnGround and not moving away from ground: velocity = GetGroundVelocity() + horizontal speed as input by player + optional vertical jump velocity + delta time * gravity
377
/// - Else: velocity = current vertical velocity + horizontal speed as input by player + delta time * gravity
378
/// @param inDeltaTime Time step to simulate.
379
/// @param inGravity Gravity vector (m/s^2). This gravity vector is only used when the character is standing on top of another object to apply downward force.
380
/// @param inSettings A structure containing settings for the algorithm.
381
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
382
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
383
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
384
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
385
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
386
void ExtendedUpdate(float inDeltaTime, Vec3Arg inGravity, const ExtendedUpdateSettings &inSettings, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
387
388
/// This function can be used after a character has teleported to determine the new contacts with the world.
389
void RefreshContacts(const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
390
391
/// Use the ground body ID to get an updated estimate of the ground velocity. This function can be used if the ground body has moved / changed velocity and you want a new estimate of the ground velocity.
392
/// It will not perform collision detection, so is less accurate than RefreshContacts but a lot faster.
393
void UpdateGroundVelocity();
394
395
/// Switch the shape of the character (e.g. for stance).
396
/// @param inShape The shape to switch to.
397
/// @param inMaxPenetrationDepth When inMaxPenetrationDepth is not FLT_MAX, it checks if the new shape collides before switching shape. This is the max penetration we're willing to accept after the switch.
398
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
399
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
400
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
401
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
402
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
403
/// @return Returns true if the switch succeeded.
404
bool SetShape(const Shape *inShape, float inMaxPenetrationDepth, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
405
406
/// Updates the shape of the inner rigid body. Should be called after a successful call to SetShape.
407
void SetInnerBodyShape(const Shape *inShape);
408
409
/// Get the transformed shape that represents the volume of the character, can be used for collision checks.
410
TransformedShape GetTransformedShape() const { return TransformedShape(GetCenterOfMassPosition(), mRotation, mShape, mInnerBodyID); }
411
412
/// @brief Get all contacts for the character at a particular location.
413
/// When colliding with another character virtual, this pointer will be provided through CollideShapeCollector::SetUserContext before adding a hit.
414
/// @param inPosition Position to test, note that this position will be corrected for the character padding.
415
/// @param inRotation Rotation at which to test the shape.
416
/// @param inMovementDirection A hint in which direction the character is moving, will be used to calculate a proper normal.
417
/// @param inMaxSeparationDistance How much distance around the character you want to report contacts in (can be 0 to match the character exactly).
418
/// @param inShape Shape to test collision with.
419
/// @param inBaseOffset All hit results will be returned relative to this offset, can be zero to get results in world position, but when you're testing far from the origin you get better precision by picking a position that's closer e.g. GetPosition() since floats are most accurate near the origin
420
/// @param ioCollector Collision collector that receives the collision results.
421
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
422
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
423
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
424
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
425
void CheckCollision(RVec3Arg inPosition, QuatArg inRotation, Vec3Arg inMovementDirection, float inMaxSeparationDistance, const Shape *inShape, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const;
426
427
/// Get the character settings that can recreate this character
428
CharacterVirtualSettings GetCharacterVirtualSettings() const;
429
430
// Saving / restoring state for replay
431
virtual void SaveState(StateRecorder &inStream) const override;
432
virtual void RestoreState(StateRecorder &inStream) override;
433
434
#ifdef JPH_DEBUG_RENDERER
435
static inline bool sDrawConstraints = false; ///< Draw the current state of the constraints for iteration 0 when creating them
436
static inline bool sDrawWalkStairs = false; ///< Draw the state of the walk stairs algorithm
437
static inline bool sDrawStickToFloor = false; ///< Draw the state of the stick to floor algorithm
438
#endif
439
440
/// Uniquely identifies a contact between a character and another body or character
441
class ContactKey
442
{
443
public:
444
/// Constructor
445
ContactKey() = default;
446
ContactKey(const ContactKey &inContact) = default;
447
ContactKey(const BodyID &inBodyB, const SubShapeID &inSubShapeID) : mBodyB(inBodyB), mSubShapeIDB(inSubShapeID) { }
448
ContactKey(const CharacterID &inCharacterIDB, const SubShapeID &inSubShapeID) : mCharacterIDB(inCharacterIDB), mSubShapeIDB(inSubShapeID) { }
449
ContactKey & operator = (const ContactKey &inContact) = default;
450
451
/// Checks if two contacts refer to the same body (or virtual character)
452
inline bool IsSameBody(const ContactKey &inOther) const { return mBodyB == inOther.mBodyB && mCharacterIDB == inOther.mCharacterIDB; }
453
454
/// Equality operator
455
bool operator == (const ContactKey &inRHS) const
456
{
457
return mBodyB == inRHS.mBodyB && mCharacterIDB == inRHS.mCharacterIDB && mSubShapeIDB == inRHS.mSubShapeIDB;
458
}
459
460
bool operator != (const ContactKey &inRHS) const
461
{
462
return !(*this == inRHS);
463
}
464
465
/// Hash of this structure
466
uint64 GetHash() const
467
{
468
static_assert(sizeof(BodyID) + sizeof(CharacterID) + sizeof(SubShapeID) == sizeof(ContactKey), "No padding expected");
469
return HashBytes(this, sizeof(ContactKey));
470
}
471
472
// Saving / restoring state for replay
473
void SaveState(StateRecorder &inStream) const;
474
void RestoreState(StateRecorder &inStream);
475
476
BodyID mBodyB; ///< ID of body we're colliding with (if not invalid)
477
CharacterID mCharacterIDB; ///< Character we're colliding with (if not invalid)
478
SubShapeID mSubShapeIDB; ///< Sub shape ID of body or character we're colliding with
479
};
480
481
/// Encapsulates a collision contact
482
struct Contact : public ContactKey
483
{
484
// Saving / restoring state for replay
485
void SaveState(StateRecorder &inStream) const;
486
void RestoreState(StateRecorder &inStream);
487
488
RVec3 mPosition; ///< Position where the character makes contact
489
Vec3 mLinearVelocity; ///< Velocity of the contact point
490
Vec3 mContactNormal; ///< Contact normal, pointing towards the character
491
Vec3 mSurfaceNormal; ///< Surface normal of the contact
492
float mDistance; ///< Distance to the contact <= 0 means that it is an actual contact, > 0 means predictive
493
float mFraction; ///< Fraction along the path where this contact takes place
494
EMotionType mMotionTypeB; ///< Motion type of B, used to determine the priority of the contact
495
bool mIsSensorB; ///< If B is a sensor
496
const CharacterVirtual * mCharacterB = nullptr; ///< Character we're colliding with (if not nullptr). Note that this may be a dangling pointer when accessed through GetActiveContacts(), use mCharacterIDB instead.
497
uint64 mUserData; ///< User data of B
498
const PhysicsMaterial * mMaterial; ///< Material of B
499
bool mHadCollision = false; ///< If the character actually collided with the contact (can be false if a predictive contact never becomes a real one)
500
bool mWasDiscarded = false; ///< If the contact validate callback chose to discard this contact or when the body is a sensor
501
bool mCanPushCharacter = true; ///< When true, the velocity of the contact point can push the character
502
};
503
504
using TempContactList = Array<Contact, STLTempAllocator<Contact>>;
505
using ContactList = Array<Contact>;
506
507
/// Access to the internal list of contacts that the character has found.
508
/// Note that only contacts that have their mHadCollision flag set are actual contacts.
509
const ContactList & GetActiveContacts() const { return mActiveContacts; }
510
511
/// Check if the character is currently in contact with or has collided with another body in the last operation (e.g. Update or WalkStairs)
512
bool HasCollidedWith(const BodyID &inBody) const
513
{
514
for (const CharacterVirtual::Contact &c : mActiveContacts)
515
if (c.mHadCollision && c.mBodyB == inBody)
516
return true;
517
return false;
518
}
519
520
/// Check if the character is currently in contact with or has collided with another character in the last time step (e.g. Update or WalkStairs)
521
bool HasCollidedWith(const CharacterID &inCharacterID) const
522
{
523
for (const CharacterVirtual::Contact &c : mActiveContacts)
524
if (c.mHadCollision && c.mCharacterIDB == inCharacterID)
525
return true;
526
return false;
527
}
528
529
/// Check if the character is currently in contact with or has collided with another character in the last time step (e.g. Update or WalkStairs)
530
bool HasCollidedWith(const CharacterVirtual *inCharacter) const
531
{
532
return HasCollidedWith(inCharacter->GetID());
533
}
534
535
private:
536
// Sorting predicate for making contact order deterministic
537
struct ContactOrderingPredicate
538
{
539
inline bool operator () (const Contact &inLHS, const Contact &inRHS) const
540
{
541
if (inLHS.mBodyB != inRHS.mBodyB)
542
return inLHS.mBodyB < inRHS.mBodyB;
543
544
if (inLHS.mCharacterIDB != inRHS.mCharacterIDB)
545
return inLHS.mCharacterIDB < inRHS.mCharacterIDB;
546
547
return inLHS.mSubShapeIDB.GetValue() < inRHS.mSubShapeIDB.GetValue();
548
}
549
};
550
551
using IgnoredContactList = Array<ContactKey, STLTempAllocator<ContactKey>>;
552
553
// A constraint that limits the movement of the character
554
struct Constraint
555
{
556
Contact * mContact; ///< Contact that this constraint was generated from
557
float mTOI; ///< Calculated time of impact (can be negative if penetrating)
558
float mProjectedVelocity; ///< Velocity of the contact projected on the contact normal (negative if separating)
559
Vec3 mLinearVelocity; ///< Velocity of the contact (can contain a corrective velocity to resolve penetration)
560
Plane mPlane; ///< Plane around the origin that describes how far we can displace (from the origin)
561
bool mIsSteepSlope = false; ///< If this constraint belongs to a steep slope
562
};
563
564
using ConstraintList = Array<Constraint, STLTempAllocator<Constraint>>;
565
566
// Collision collector that collects hits for CollideShape
567
class ContactCollector : public CollideShapeCollector
568
{
569
public:
570
ContactCollector(PhysicsSystem *inSystem, const CharacterVirtual *inCharacter, uint inMaxHits, float inHitReductionCosMaxAngle, Vec3Arg inUp, RVec3Arg inBaseOffset, TempContactList &outContacts) : mBaseOffset(inBaseOffset), mUp(inUp), mSystem(inSystem), mCharacter(inCharacter), mContacts(outContacts), mMaxHits(inMaxHits), mHitReductionCosMaxAngle(inHitReductionCosMaxAngle) { }
571
572
virtual void SetUserData(uint64 inUserData) override { mOtherCharacter = reinterpret_cast<CharacterVirtual *>(inUserData); }
573
574
virtual void AddHit(const CollideShapeResult &inResult) override;
575
576
RVec3 mBaseOffset;
577
Vec3 mUp;
578
PhysicsSystem * mSystem;
579
const CharacterVirtual * mCharacter;
580
CharacterVirtual * mOtherCharacter = nullptr;
581
TempContactList & mContacts;
582
uint mMaxHits;
583
float mHitReductionCosMaxAngle;
584
bool mMaxHitsExceeded = false;
585
};
586
587
// A collision collector that collects hits for CastShape
588
class ContactCastCollector : public CastShapeCollector
589
{
590
public:
591
ContactCastCollector(PhysicsSystem *inSystem, const CharacterVirtual *inCharacter, Vec3Arg inDisplacement, Vec3Arg inUp, const IgnoredContactList &inIgnoredContacts, RVec3Arg inBaseOffset, Contact &outContact) : mBaseOffset(inBaseOffset), mDisplacement(inDisplacement), mUp(inUp), mSystem(inSystem), mCharacter(inCharacter), mIgnoredContacts(inIgnoredContacts), mContact(outContact) { }
592
593
virtual void SetUserData(uint64 inUserData) override { mOtherCharacter = reinterpret_cast<CharacterVirtual *>(inUserData); }
594
595
virtual void AddHit(const ShapeCastResult &inResult) override;
596
597
RVec3 mBaseOffset;
598
Vec3 mDisplacement;
599
Vec3 mUp;
600
PhysicsSystem * mSystem;
601
const CharacterVirtual * mCharacter;
602
CharacterVirtual * mOtherCharacter = nullptr;
603
const IgnoredContactList & mIgnoredContacts;
604
Contact & mContact;
605
};
606
607
// Helper function to convert a Jolt collision result into a contact
608
template <class taCollector>
609
inline static void sFillContactProperties(const CharacterVirtual *inCharacter, Contact &outContact, const Body &inBody, Vec3Arg inUp, RVec3Arg inBaseOffset, const taCollector &inCollector, const CollideShapeResult &inResult);
610
inline static void sFillCharacterContactProperties(Contact &outContact, const CharacterVirtual *inOtherCharacter, RVec3Arg inBaseOffset, const CollideShapeResult &inResult);
611
612
// Move the shape from ioPosition and try to displace it by inVelocity * inDeltaTime, this will try to slide the shape along the world geometry
613
void MoveShape(RVec3 &ioPosition, Vec3Arg inVelocity, float inDeltaTime, ContactList *outActiveContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator
614
#ifdef JPH_DEBUG_RENDERER
615
, bool inDrawConstraints = false
616
#endif // JPH_DEBUG_RENDERER
617
);
618
619
// Ask the callback if inContact is a valid contact point
620
bool ValidateContact(const Contact &inContact) const;
621
622
// Trigger the contact callback for inContact and get the contact settings
623
void ContactAdded(const Contact &inContact, CharacterContactSettings &ioSettings);
624
625
// Tests the shape for collision around inPosition
626
void GetContactsAtPosition(RVec3Arg inPosition, Vec3Arg inMovementDirection, const Shape *inShape, TempContactList &outContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const;
627
628
// Remove penetrating contacts with the same body that have conflicting normals, leaving these will make the character mover get stuck
629
void RemoveConflictingContacts(TempContactList &ioContacts, IgnoredContactList &outIgnoredContacts) const;
630
631
// Convert contacts into constraints. The character is assumed to start at the origin and the constraints are planes around the origin that confine the movement of the character.
632
void DetermineConstraints(TempContactList &inContacts, float inDeltaTime, ConstraintList &outConstraints) const;
633
634
// Use the constraints to solve the displacement of the character. This will slide the character on the planes around the origin for as far as possible.
635
void SolveConstraints(Vec3Arg inVelocity, float inDeltaTime, float inTimeRemaining, ConstraintList &ioConstraints, IgnoredContactList &ioIgnoredContacts, float &outTimeSimulated, Vec3 &outDisplacement, TempAllocator &inAllocator
636
#ifdef JPH_DEBUG_RENDERER
637
, bool inDrawConstraints = false
638
#endif // JPH_DEBUG_RENDERER
639
);
640
641
// Get the velocity of a body adjusted by the contact listener
642
void GetAdjustedBodyVelocity(const Body& inBody, Vec3 &outLinearVelocity, Vec3 &outAngularVelocity) const;
643
644
// Calculate the ground velocity of the character assuming it's standing on an object with specified linear and angular velocity and with specified center of mass.
645
// Note that we don't just take the point velocity because a point on an object with angular velocity traces an arc,
646
// so if you just take point velocity * delta time you get an error that accumulates over time
647
Vec3 CalculateCharacterGroundVelocity(RVec3Arg inCenterOfMass, Vec3Arg inLinearVelocity, Vec3Arg inAngularVelocity, float inDeltaTime) const;
648
649
// Handle contact with physics object that we're colliding against
650
bool HandleContact(Vec3Arg inVelocity, Constraint &ioConstraint, float inDeltaTime);
651
652
// Does a swept test of the shape from inPosition with displacement inDisplacement, returns true if there was a collision
653
bool GetFirstContactForSweep(RVec3Arg inPosition, Vec3Arg inDisplacement, Contact &outContact, const IgnoredContactList &inIgnoredContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const;
654
655
// Store contacts so that we have proper ground information
656
void StoreActiveContacts(const TempContactList &inContacts, TempAllocator &inAllocator);
657
658
// This function will determine which contacts are touching the character and will calculate the one that is supporting us
659
void UpdateSupportingContact(bool inSkipContactVelocityCheck, TempAllocator &inAllocator);
660
661
/// This function can be called after moving the character to a new colliding position
662
void MoveToContact(RVec3Arg inPosition, const Contact &inContact, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
663
664
// This function returns the actual center of mass of the shape, not corrected for the character padding
665
inline RMat44 GetCenterOfMassTransform(RVec3Arg inPosition, QuatArg inRotation, const Shape *inShape) const
666
{
667
return RMat44::sRotationTranslation(inRotation, inPosition).PreTranslated(mShapeOffset + inShape->GetCenterOfMass()).PostTranslated(mCharacterPadding * mUp);
668
}
669
670
// This function returns the position of the inner rigid body
671
inline RVec3 GetInnerBodyPosition() const
672
{
673
return mPosition + (mRotation * mShapeOffset + mCharacterPadding * mUp);
674
}
675
676
// Move the inner rigid body to the current position
677
void UpdateInnerBodyTransform();
678
679
// ID
680
CharacterID mID;
681
682
// Our main listener for contacts
683
CharacterContactListener * mListener = nullptr;
684
685
// Interface to detect collision between characters
686
CharacterVsCharacterCollision * mCharacterVsCharacterCollision = nullptr;
687
688
// Movement settings
689
EBackFaceMode mBackFaceMode; // When colliding with back faces, the character will not be able to move through back facing triangles. Use this if you have triangles that need to collide on both sides.
690
float mPredictiveContactDistance; // How far to scan outside of the shape for predictive contacts. A value of 0 will most likely cause the character to get stuck as it cannot properly calculate a sliding direction anymore. A value that's too high will cause ghost collisions.
691
uint mMaxCollisionIterations; // Max amount of collision loops
692
uint mMaxConstraintIterations; // How often to try stepping in the constraint solving
693
float mMinTimeRemaining; // Early out condition: If this much time is left to simulate we are done
694
float mCollisionTolerance; // How far we're willing to penetrate geometry
695
float mCharacterPadding; // How far we try to stay away from the geometry, this ensures that the sweep will hit as little as possible lowering the collision cost and reducing the risk of getting stuck
696
uint mMaxNumHits; // Max num hits to collect in order to avoid excess of contact points collection
697
float mHitReductionCosMaxAngle; // Cos(angle) where angle is the maximum angle between two hits contact normals that are allowed to be merged during hit reduction. Default is around 2.5 degrees. Set to -1 to turn off.
698
float mPenetrationRecoverySpeed; // This value governs how fast a penetration will be resolved, 0 = nothing is resolved, 1 = everything in one update
699
bool mEnhancedInternalEdgeRemoval; // 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.
700
701
// Character mass (kg)
702
float mMass;
703
704
// Maximum force with which the character can push other bodies (N)
705
float mMaxStrength;
706
707
// An extra offset applied to the shape in local space. This allows applying an extra offset to the shape in local space.
708
Vec3 mShapeOffset = Vec3::sZero();
709
710
// Current position (of the base, not the center of mass)
711
RVec3 mPosition = RVec3::sZero();
712
713
// Current rotation (of the base, not of the center of mass)
714
Quat mRotation = Quat::sIdentity();
715
716
// Current linear velocity
717
Vec3 mLinearVelocity = Vec3::sZero();
718
719
// List of contacts that were active in the last frame
720
ContactList mActiveContacts;
721
722
// Remembers how often we called StartTrackingContactChanges
723
int mTrackingContactChanges = 0;
724
725
// View from a contact listener perspective on which contacts have been added/removed
726
struct ListenerContactValue
727
{
728
ListenerContactValue() = default;
729
explicit ListenerContactValue(const CharacterContactSettings &inSettings) : mSettings(inSettings) { }
730
731
CharacterContactSettings mSettings;
732
int mCount = 0;
733
};
734
735
using ListenerContacts = UnorderedMap<ContactKey, ListenerContactValue>;
736
ListenerContacts mListenerContacts;
737
738
// Remembers the delta time of the last update
739
float mLastDeltaTime = 1.0f / 60.0f;
740
741
// Remember if we exceeded the maximum number of hits and had to remove similar contacts
742
mutable bool mMaxHitsExceeded = false;
743
744
// User data, can be used for anything by the application
745
uint64 mUserData = 0;
746
747
// The inner rigid body that proxies the character in the world
748
BodyID mInnerBodyID;
749
};
750
751
JPH_NAMESPACE_END
752
753