Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Constraints/ConstraintPart/SpringPart.h
9913 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
JPH_NAMESPACE_BEGIN
8
#ifndef JPH_PLATFORM_DOXYGEN // Somehow Doxygen gets confused and thinks the parameters to CalculateSpringProperties belong to this macro
9
JPH_MSVC_SUPPRESS_WARNING(4723) // potential divide by 0 - caused by line: outEffectiveMass = 1.0f / inInvEffectiveMass, note that JPH_NAMESPACE_BEGIN already pushes the warning state
10
#endif // !JPH_PLATFORM_DOXYGEN
11
12
/// Class used in other constraint parts to calculate the required bias factor in the lagrange multiplier for creating springs
13
class SpringPart
14
{
15
private:
16
JPH_INLINE void CalculateSpringPropertiesHelper(float inDeltaTime, float inInvEffectiveMass, float inBias, float inC, float inStiffness, float inDamping, float &outEffectiveMass)
17
{
18
// Soft constraints as per: Soft Constraints: Reinventing The Spring - Erin Catto - GDC 2011
19
20
// Note that the calculation of beta and gamma below are based on the solution of an implicit Euler integration scheme
21
// This scheme is unconditionally stable but has built in damping, so even when you set the damping ratio to 0 there will still
22
// be damping. See page 16 and 32.
23
24
// Calculate softness (gamma in the slides)
25
// See page 34 and note that the gamma needs to be divided by delta time since we're working with impulses rather than forces:
26
// softness = 1 / (dt * (c + dt * k))
27
// Note that the spring stiffness is k and the spring damping is c
28
mSoftness = 1.0f / (inDeltaTime * (inDamping + inDeltaTime * inStiffness));
29
30
// Calculate bias factor (baumgarte stabilization):
31
// beta = dt * k / (c + dt * k) = dt * k^2 * softness
32
// b = beta / dt * C = dt * k * softness * C
33
mBias = inBias + inDeltaTime * inStiffness * mSoftness * inC;
34
35
// Update the effective mass, see post by Erin Catto: http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=4&t=1354
36
//
37
// Newton's Law:
38
// M * (v2 - v1) = J^T * lambda
39
//
40
// Velocity constraint with softness and Baumgarte:
41
// J * v2 + softness * lambda + b = 0
42
//
43
// where b = beta * C / dt
44
//
45
// We know everything except v2 and lambda.
46
//
47
// First solve Newton's law for v2 in terms of lambda:
48
//
49
// v2 = v1 + M^-1 * J^T * lambda
50
//
51
// Substitute this expression into the velocity constraint:
52
//
53
// J * (v1 + M^-1 * J^T * lambda) + softness * lambda + b = 0
54
//
55
// Now collect coefficients of lambda:
56
//
57
// (J * M^-1 * J^T + softness) * lambda = - J * v1 - b
58
//
59
// Now we define:
60
//
61
// K = J * M^-1 * J^T + softness
62
//
63
// So our new effective mass is K^-1
64
outEffectiveMass = 1.0f / (inInvEffectiveMass + mSoftness);
65
}
66
67
public:
68
/// Turn off the spring and set a bias only
69
///
70
/// @param inBias Bias term (b) for the constraint impulse: lambda = J v + b
71
inline void CalculateSpringPropertiesWithBias(float inBias)
72
{
73
mSoftness = 0.0f;
74
mBias = inBias;
75
}
76
77
/// Calculate spring properties based on frequency and damping ratio
78
///
79
/// @param inDeltaTime Time step
80
/// @param inInvEffectiveMass Inverse effective mass K
81
/// @param inBias Bias term (b) for the constraint impulse: lambda = J v + b
82
/// @param inC Value of the constraint equation (C). Set to zero if you don't want to drive the constraint to zero with a spring.
83
/// @param inFrequency Oscillation frequency (Hz). Set to zero if you don't want to drive the constraint to zero with a spring.
84
/// @param inDamping Damping factor (0 = no damping, 1 = critical damping). Set to zero if you don't want to drive the constraint to zero with a spring.
85
/// @param outEffectiveMass On return, this contains the new effective mass K^-1
86
inline void CalculateSpringPropertiesWithFrequencyAndDamping(float inDeltaTime, float inInvEffectiveMass, float inBias, float inC, float inFrequency, float inDamping, float &outEffectiveMass)
87
{
88
outEffectiveMass = 1.0f / inInvEffectiveMass;
89
90
if (inFrequency > 0.0f)
91
{
92
// Calculate angular frequency
93
float omega = 2.0f * JPH_PI * inFrequency;
94
95
// Calculate spring stiffness k and damping constant c (page 45)
96
float k = outEffectiveMass * Square(omega);
97
float c = 2.0f * outEffectiveMass * inDamping * omega;
98
99
CalculateSpringPropertiesHelper(inDeltaTime, inInvEffectiveMass, inBias, inC, k, c, outEffectiveMass);
100
}
101
else
102
{
103
CalculateSpringPropertiesWithBias(inBias);
104
}
105
}
106
107
/// Calculate spring properties with spring Stiffness (k) and damping (c), this is based on the spring equation: F = -k * x - c * v
108
///
109
/// @param inDeltaTime Time step
110
/// @param inInvEffectiveMass Inverse effective mass K
111
/// @param inBias Bias term (b) for the constraint impulse: lambda = J v + b
112
/// @param inC Value of the constraint equation (C). Set to zero if you don't want to drive the constraint to zero with a spring.
113
/// @param inStiffness Spring stiffness k. Set to zero if you don't want to drive the constraint to zero with a spring.
114
/// @param inDamping Spring damping coefficient c. Set to zero if you don't want to drive the constraint to zero with a spring.
115
/// @param outEffectiveMass On return, this contains the new effective mass K^-1
116
inline void CalculateSpringPropertiesWithStiffnessAndDamping(float inDeltaTime, float inInvEffectiveMass, float inBias, float inC, float inStiffness, float inDamping, float &outEffectiveMass)
117
{
118
if (inStiffness > 0.0f)
119
{
120
CalculateSpringPropertiesHelper(inDeltaTime, inInvEffectiveMass, inBias, inC, inStiffness, inDamping, outEffectiveMass);
121
}
122
else
123
{
124
outEffectiveMass = 1.0f / inInvEffectiveMass;
125
126
CalculateSpringPropertiesWithBias(inBias);
127
}
128
}
129
130
/// Returns if this spring is active
131
inline bool IsActive() const
132
{
133
return mSoftness != 0.0f;
134
}
135
136
/// Get total bias b, including supplied bias and bias for spring: lambda = J v + b
137
inline float GetBias(float inTotalLambda) const
138
{
139
// Remainder of post by Erin Catto: http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=4&t=1354
140
//
141
// Each iteration we are not computing the whole impulse, we are computing an increment to the impulse and we are updating the velocity.
142
// Also, as we solve each constraint we get a perfect v2, but then some other constraint will come along and mess it up.
143
// So we want to patch up the constraint while acknowledging the accumulated impulse and the damaged velocity.
144
// To help with that we use P for the accumulated impulse and lambda as the update. Mathematically we have:
145
//
146
// M * (v2new - v2damaged) = J^T * lambda
147
// J * v2new + softness * (total_lambda + lambda) + b = 0
148
//
149
// If we solve this we get:
150
//
151
// v2new = v2damaged + M^-1 * J^T * lambda
152
// J * (v2damaged + M^-1 * J^T * lambda) + softness * total_lambda + softness * lambda + b = 0
153
//
154
// (J * M^-1 * J^T + softness) * lambda = -(J * v2damaged + softness * total_lambda + b)
155
//
156
// So our lagrange multiplier becomes:
157
//
158
// lambda = -K^-1 (J v + softness * total_lambda + b)
159
//
160
// So we return the bias: softness * total_lambda + b
161
return mSoftness * inTotalLambda + mBias;
162
}
163
164
private:
165
float mBias = 0.0f;
166
float mSoftness = 0.0f;
167
};
168
169
JPH_NAMESPACE_END
170
171