Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
SwingTwistConstraintPart.h
Go to the documentation of this file.
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
10
12
26{
27public:
29 void SetLimits(float inTwistMinAngle, float inTwistMaxAngle, float inSwingYHalfAngle, float inSwingZHalfAngle)
30 {
31 constexpr float cLockedAngle = DegreesToRadians(0.5f);
32 constexpr float cFreeAngle = DegreesToRadians(179.5f);
33
34 // Assume sane input
35 JPH_ASSERT(inTwistMinAngle <= 0.0f && inTwistMinAngle >= -JPH_PI);
36 JPH_ASSERT(inTwistMaxAngle >= 0.0f && inTwistMaxAngle <= JPH_PI);
37 JPH_ASSERT(inSwingYHalfAngle >= 0.0f && inSwingYHalfAngle <= JPH_PI);
38 JPH_ASSERT(inSwingZHalfAngle >= 0.0f && inSwingZHalfAngle <= JPH_PI);
39
40 // Calculate the sine and cosine of the half angles
41 Vec4 s, c;
42 (0.5f * Vec4(inTwistMinAngle, inTwistMaxAngle, inSwingYHalfAngle, inSwingZHalfAngle)).SinCos(s, c);
43
44 // Store axis flags which are used at runtime to quickly decided which contraints to apply
45 mRotationFlags = 0;
46 if (inTwistMinAngle > -cLockedAngle && inTwistMaxAngle < cLockedAngle)
47 {
48 mRotationFlags |= TwistXLocked;
49 mSinTwistHalfMinAngle = 0.0f;
50 mSinTwistHalfMaxAngle = 0.0f;
51 mCosTwistHalfMinAngle = 1.0f;
52 mCosTwistHalfMaxAngle = 1.0f;
53 }
54 else if (inTwistMinAngle < -cFreeAngle && inTwistMaxAngle > cFreeAngle)
55 {
56 mRotationFlags |= TwistXFree;
57 mSinTwistHalfMinAngle = -1.0f;
58 mSinTwistHalfMaxAngle = 1.0f;
59 mCosTwistHalfMinAngle = 0.0f;
60 mCosTwistHalfMaxAngle = 0.0f;
61 }
62 else
63 {
64 mSinTwistHalfMinAngle = s.GetX();
65 mSinTwistHalfMaxAngle = s.GetY();
66 mCosTwistHalfMinAngle = c.GetX();
67 mCosTwistHalfMaxAngle = c.GetY();
68 }
69
70 if (inSwingYHalfAngle < cLockedAngle)
71 {
72 mRotationFlags |= SwingYLocked;
73 mSinSwingYQuarterAngle = 0.0f;
74 }
75 else if (inSwingYHalfAngle > cFreeAngle)
76 {
77 mRotationFlags |= SwingYFree;
78 mSinSwingYQuarterAngle = 1.0f;
79 }
80 else
81 {
82 mSinSwingYQuarterAngle = s.GetZ();
83 }
84
85 if (inSwingZHalfAngle < cLockedAngle)
86 {
87 mRotationFlags |= SwingZLocked;
88 mSinSwingZQuarterAngle = 0.0f;
89 }
90 else if (inSwingZHalfAngle > cFreeAngle)
91 {
92 mRotationFlags |= SwingZFree;
93 mSinSwingZQuarterAngle = 1.0f;
94 }
95 else
96 {
97 mSinSwingZQuarterAngle = s.GetW();
98 }
99 }
100
102 inline void ClampSwingTwist(Quat &ioSwing, bool &outSwingYClamped, bool &outSwingZClamped, Quat &ioTwist, bool &outTwistClamped) const
103 {
104 // Start with not clamped
105 outTwistClamped = false;
106 outSwingYClamped = false;
107 outSwingZClamped = false;
108
109 // Check that swing and twist quaternions don't contain rotations around the wrong axis
110 JPH_ASSERT(ioSwing.GetX() == 0.0f);
111 JPH_ASSERT(ioTwist.GetY() == 0.0f);
112 JPH_ASSERT(ioTwist.GetZ() == 0.0f);
113
114 // Ensure quaternions have w > 0
115 bool negate_swing = ioSwing.GetW() < 0.0f;
116 if (negate_swing)
117 ioSwing = -ioSwing;
118 bool negate_twist = ioTwist.GetW() < 0.0f;
119 if (negate_twist)
120 ioTwist = -ioTwist;
121
122 if (mRotationFlags & TwistXLocked)
123 {
124 // Twist axis is locked, clamp whenever twist is not identity
125 if (ioTwist.GetX() != 0.0f)
126 {
127 ioTwist = Quat::sIdentity();
128 outTwistClamped = true;
129 }
130 }
131 else if ((mRotationFlags & TwistXFree) == 0)
132 {
133 // Twist axis has limit, clamp whenever out of range
134 float delta_min = mSinTwistHalfMinAngle - ioTwist.GetX();
135 float delta_max = ioTwist.GetX() - mSinTwistHalfMaxAngle;
136 if (delta_min > 0.0f || delta_max > 0.0f)
137 {
138 // We're outside of the limits, get actual delta to min/max range
139 // Note that a twist of -1 and 1 represent the same angle, so if the difference is bigger than 1, the shortest angle is the other way around (2 - difference)
140 // We should actually be working with angles rather than sin(angle / 2). When the difference is small the approximation is accurate, but
141 // when working with extreme values the calculation is off and e.g. when the limit is between 0 and 180 a value of approx -60 will clamp
142 // to 180 rather than 0 (you'd expect anything > -90 to go to 0).
143 delta_min = abs(delta_min);
144 if (delta_min > 1.0f) delta_min = 2.0f - delta_min;
145 delta_max = abs(delta_max);
146 if (delta_max > 1.0f) delta_max = 2.0f - delta_max;
147
148 // Pick the twist that corresponds to the smallest delta
149 if (delta_min < delta_max)
150 ioTwist = Quat(mSinTwistHalfMinAngle, 0, 0, mCosTwistHalfMinAngle);
151 else
152 ioTwist = Quat(mSinTwistHalfMaxAngle, 0, 0, mCosTwistHalfMaxAngle);
153 outTwistClamped = true;
154 }
155 }
156
157 // Clamp swing
158 if (mRotationFlags & SwingYLocked)
159 {
160 if (mRotationFlags & SwingZLocked)
161 {
162 // Both swing Y and Z are disabled, no degrees of freedom in swing
163 outSwingYClamped = ioSwing.GetY() != 0.0f;
164 outSwingZClamped = ioSwing.GetZ() != 0.0f;
165 if (outSwingYClamped || outSwingZClamped)
166 ioSwing = Quat::sIdentity();
167 }
168 else
169 {
170 // Swing Y angle disabled, only 1 degree of freedom in swing
171 float z = Clamp(ioSwing.GetZ(), -mSinSwingZQuarterAngle, mSinSwingZQuarterAngle);
172 outSwingYClamped = ioSwing.GetY() != 0.0f;
173 outSwingZClamped = z != ioSwing.GetZ();
174 if (outSwingYClamped || outSwingZClamped)
175 ioSwing = Quat(0, 0, z, sqrt(1.0f - Square(z)));
176 }
177 }
178 else if (mRotationFlags & SwingZLocked)
179 {
180 // Swing Z angle disabled, only 1 degree of freedom in swing
181 float y = Clamp(ioSwing.GetY(), -mSinSwingYQuarterAngle, mSinSwingYQuarterAngle);
182 outSwingYClamped = y != ioSwing.GetY();
183 outSwingZClamped = ioSwing.GetZ() != 0.0f;
184 if (outSwingYClamped || outSwingZClamped)
185 ioSwing = Quat(0, y, 0, sqrt(1.0f - Square(y)));
186 }
187 else
188 {
189 // Two degrees of freedom, use ellipse to solve limits
190 Ellipse ellipse(mSinSwingYQuarterAngle, mSinSwingZQuarterAngle);
191 Float2 point(ioSwing.GetY(), ioSwing.GetZ());
192 if (!ellipse.IsInside(point))
193 {
194 Float2 closest = ellipse.GetClosestPoint(point);
195 ioSwing = Quat(0, closest.x, closest.y, sqrt(max(0.0f, 1.0f - Square(closest.x) - Square(closest.y))));
196 outSwingYClamped = true;
197 outSwingZClamped = true;
198 }
199 }
200
201 // Flip sign back
202 if (negate_swing)
203 ioSwing = -ioSwing;
204 if (negate_twist)
205 ioTwist = -ioTwist;
206
207 JPH_ASSERT(ioSwing.IsNormalized());
208 JPH_ASSERT(ioTwist.IsNormalized());
209 }
210
217 inline void CalculateConstraintProperties(float inDeltaTime, const Body &inBody1, const Body &inBody2, QuatArg inConstraintRotation, QuatArg inConstraintToWorld)
218 {
219 // Decompose into swing and twist
220 Quat q_swing, q_twist;
221 inConstraintRotation.GetSwingTwist(q_swing, q_twist);
222
223 // Clamp against joint limits
224 Quat q_clamped_swing = q_swing, q_clamped_twist = q_twist;
225 bool swing_y_clamped, swing_z_clamped, twist_clamped;
226 ClampSwingTwist(q_clamped_swing, swing_y_clamped, swing_z_clamped, q_clamped_twist, twist_clamped);
227
228 if (mRotationFlags & SwingYLocked)
229 {
230 Quat twist_to_world = inConstraintToWorld * q_swing;
231 mWorldSpaceSwingLimitYRotationAxis = twist_to_world.RotateAxisY();
232 mWorldSpaceSwingLimitZRotationAxis = twist_to_world.RotateAxisZ();
233
234 if (mRotationFlags & SwingZLocked)
235 {
236 // Swing fully locked
237 mSwingLimitYConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceSwingLimitYRotationAxis);
238 mSwingLimitZConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceSwingLimitZRotationAxis);
239 }
240 else
241 {
242 // Swing only locked around Y
243 mSwingLimitYConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceSwingLimitYRotationAxis);
244 if (swing_z_clamped)
245 {
246 if (Sign(q_swing.GetW()) * q_swing.GetZ() < 0.0f)
247 mWorldSpaceSwingLimitZRotationAxis = -mWorldSpaceSwingLimitZRotationAxis; // Flip axis if angle is negative because the impulse limit is going to be between [-FLT_MAX, 0]
248 mSwingLimitZConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceSwingLimitZRotationAxis);
249 }
250 else
251 mSwingLimitZConstraintPart.Deactivate();
252 }
253 }
254 else if (mRotationFlags & SwingZLocked)
255 {
256 // Swing only locked around Z
257 Quat twist_to_world = inConstraintToWorld * q_swing;
258 mWorldSpaceSwingLimitYRotationAxis = twist_to_world.RotateAxisY();
259 mWorldSpaceSwingLimitZRotationAxis = twist_to_world.RotateAxisZ();
260
261 if (swing_y_clamped)
262 {
263 if (Sign(q_swing.GetW()) * q_swing.GetY() < 0.0f)
264 mWorldSpaceSwingLimitYRotationAxis = -mWorldSpaceSwingLimitYRotationAxis; // Flip axis if angle is negative because the impulse limit is going to be between [-FLT_MAX, 0]
265 mSwingLimitYConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceSwingLimitYRotationAxis);
266 }
267 else
268 mSwingLimitYConstraintPart.Deactivate();
269 mSwingLimitZConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceSwingLimitZRotationAxis);
270 }
271 else if ((mRotationFlags & SwingYZFree) != SwingYZFree)
272 {
273 // Swing has limits around Y and Z
274 if (swing_y_clamped || swing_z_clamped)
275 {
276 // Calculate axis of rotation from clamped swing to swing
277 Vec3 current = (inConstraintToWorld * q_swing).RotateAxisX();
278 Vec3 desired = (inConstraintToWorld * q_clamped_swing).RotateAxisX();
279 mWorldSpaceSwingLimitYRotationAxis = desired.Cross(current);
280 float len = mWorldSpaceSwingLimitYRotationAxis.Length();
281 if (len != 0.0f)
282 {
283 mWorldSpaceSwingLimitYRotationAxis /= len;
284 mSwingLimitYConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceSwingLimitYRotationAxis);
285 }
286 else
287 mSwingLimitYConstraintPart.Deactivate();
288 }
289 else
290 mSwingLimitYConstraintPart.Deactivate();
291 mSwingLimitZConstraintPart.Deactivate();
292 }
293 else
294 {
295 // No swing limits
296 mSwingLimitYConstraintPart.Deactivate();
297 mSwingLimitZConstraintPart.Deactivate();
298 }
299
300 if (mRotationFlags & TwistXLocked)
301 {
302 // Twist locked, always activate constraint
303 mWorldSpaceTwistLimitRotationAxis = (inConstraintToWorld * q_swing).RotateAxisX();
304 mTwistLimitConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceTwistLimitRotationAxis);
305 }
306 else if ((mRotationFlags & TwistXFree) == 0)
307 {
308 // Twist has limits
309 if (twist_clamped)
310 {
311 mWorldSpaceTwistLimitRotationAxis = (inConstraintToWorld * q_swing).RotateAxisX();
312 if (Sign(q_twist.GetW()) * q_twist.GetX() < 0.0f)
313 mWorldSpaceTwistLimitRotationAxis = -mWorldSpaceTwistLimitRotationAxis; // Flip axis if angle is negative because the impulse limit is going to be between [-FLT_MAX, 0]
314 mTwistLimitConstraintPart.CalculateConstraintProperties(inDeltaTime, inBody1, inBody2, mWorldSpaceTwistLimitRotationAxis);
315 }
316 else
317 mTwistLimitConstraintPart.Deactivate();
318 }
319 else
320 {
321 // No twist limits
322 mTwistLimitConstraintPart.Deactivate();
323 }
324 }
325
328 {
329 mSwingLimitYConstraintPart.Deactivate();
330 mSwingLimitZConstraintPart.Deactivate();
331 mTwistLimitConstraintPart.Deactivate();
332 }
333
335 inline bool IsActive() const
336 {
337 return mSwingLimitYConstraintPart.IsActive() || mSwingLimitZConstraintPart.IsActive() || mTwistLimitConstraintPart.IsActive();
338 }
339
341 inline void WarmStart(Body &ioBody1, Body &ioBody2, float inWarmStartImpulseRatio)
342 {
343 mSwingLimitYConstraintPart.WarmStart(ioBody1, ioBody2, inWarmStartImpulseRatio);
344 mSwingLimitZConstraintPart.WarmStart(ioBody1, ioBody2, inWarmStartImpulseRatio);
345 mTwistLimitConstraintPart.WarmStart(ioBody1, ioBody2, inWarmStartImpulseRatio);
346 }
347
349 inline bool SolveVelocityConstraint(Body &ioBody1, Body &ioBody2)
350 {
351 bool impulse = false;
352
353 // Solve swing constraint
354 if (mSwingLimitYConstraintPart.IsActive())
355 impulse |= mSwingLimitYConstraintPart.SolveVelocityConstraint(ioBody1, ioBody2, mWorldSpaceSwingLimitYRotationAxis, -FLT_MAX, (mRotationFlags & SwingYLocked)? FLT_MAX : 0.0f);
356
357 if (mSwingLimitZConstraintPart.IsActive())
358 impulse |= mSwingLimitZConstraintPart.SolveVelocityConstraint(ioBody1, ioBody2, mWorldSpaceSwingLimitZRotationAxis, -FLT_MAX, (mRotationFlags & SwingZLocked)? FLT_MAX : 0.0f);
359
360 // Solve twist constraint
361 if (mTwistLimitConstraintPart.IsActive())
362 impulse |= mTwistLimitConstraintPart.SolveVelocityConstraint(ioBody1, ioBody2, mWorldSpaceTwistLimitRotationAxis, -FLT_MAX, (mRotationFlags & TwistXLocked)? FLT_MAX : 0.0f);
363
364 return impulse;
365 }
366
373 inline bool SolvePositionConstraint(Body &ioBody1, Body &ioBody2, QuatArg inConstraintRotation, QuatArg inConstraintToBody1, QuatArg inConstraintToBody2, float inBaumgarte) const
374 {
375 Quat q_swing, q_twist;
376 inConstraintRotation.GetSwingTwist(q_swing, q_twist);
377
378 bool swing_y_clamped, swing_z_clamped, twist_clamped;
379 ClampSwingTwist(q_swing, swing_y_clamped, swing_z_clamped, q_twist, twist_clamped);
380
381 // Solve rotation violations
382 if (swing_y_clamped || swing_z_clamped || twist_clamped)
383 {
385 Quat inv_initial_orientation = inConstraintToBody2 * (inConstraintToBody1 * q_swing * q_twist).Conjugated();
386 part.CalculateConstraintProperties(ioBody1, Mat44::sRotation(ioBody1.GetRotation()), ioBody2, Mat44::sRotation(ioBody2.GetRotation()));
387 return part.SolvePositionConstraint(ioBody1, ioBody2, inv_initial_orientation, inBaumgarte);
388 }
389
390 return false;
391 }
392
394 inline float GetTotalSwingYLambda() const
395 {
396 return mSwingLimitYConstraintPart.GetTotalLambda();
397 }
398
399 inline float GetTotalSwingZLambda() const
400 {
401 return mSwingLimitZConstraintPart.GetTotalLambda();
402 }
403
405 inline float GetTotalTwistLambda() const
406 {
407 return mTwistLimitConstraintPart.GetTotalLambda();
408 }
409
411 void SaveState(StateRecorder &inStream) const
412 {
413 mSwingLimitYConstraintPart.SaveState(inStream);
414 mSwingLimitZConstraintPart.SaveState(inStream);
415 mTwistLimitConstraintPart.SaveState(inStream);
416 }
417
420 {
421 mSwingLimitYConstraintPart.RestoreState(inStream);
422 mSwingLimitZConstraintPart.RestoreState(inStream);
423 mTwistLimitConstraintPart.RestoreState(inStream);
424 }
425
426private:
427 // CONFIGURATION PROPERTIES FOLLOW
428
429 enum ERotationFlags
430 {
432 TwistXLocked = 1 << 0,
433 SwingYLocked = 1 << 1,
434 SwingZLocked = 1 << 2,
435
437 TwistXFree = 1 << 3,
438 SwingYFree = 1 << 4,
439 SwingZFree = 1 << 5,
440 SwingYZFree = SwingYFree | SwingZFree
441 };
442
443 uint8 mRotationFlags;
444
445 // Constants
446 float mSinTwistHalfMinAngle;
447 float mSinTwistHalfMaxAngle;
448 float mCosTwistHalfMinAngle;
449 float mCosTwistHalfMaxAngle;
450 float mSinSwingYQuarterAngle;
451 float mSinSwingZQuarterAngle;
452
453 // RUN TIME PROPERTIES FOLLOW
454
456 Vec3 mWorldSpaceSwingLimitYRotationAxis;
457 Vec3 mWorldSpaceSwingLimitZRotationAxis;
458 Vec3 mWorldSpaceTwistLimitRotationAxis;
459
461 AngleConstraintPart mSwingLimitYConstraintPart;
462 AngleConstraintPart mSwingLimitZConstraintPart;
463 AngleConstraintPart mTwistLimitConstraintPart;
464};
465
#define JPH_NAMESPACE_END
Definition: Core.h:240
uint8_t uint8
Definition: Core.h:310
#define JPH_NAMESPACE_BEGIN
Definition: Core.h:234
#define JPH_ASSERT(...)
Definition: IssueReporting.h:33
constexpr T Clamp(T inV, T inMin, T inMax)
Clamp a value between two values.
Definition: Math.h:45
constexpr T Square(T inV)
Square a value.
Definition: Math.h:52
constexpr T Sign(T inV)
Get the sign of a value.
Definition: Math.h:66
constexpr float DegreesToRadians(float inV)
Convert a value from degrees to radians.
Definition: Math.h:13
Definition: AngleConstraintPart.h:36
void Deactivate()
Deactivate this constraint.
Definition: AngleConstraintPart.h:87
bool IsActive() const
Check if constraint is active.
Definition: AngleConstraintPart.h:94
void CalculateConstraintProperties(float inDeltaTime, const Body &inBody1, const Body &inBody2, Vec3Arg inWorldSpaceAxis, float inBias=0.0f, float inC=0.0f, float inFrequency=0.0f, float inDamping=0.0f)
Definition: AngleConstraintPart.h:71
void RestoreState(StateRecorder &inStream)
Restore state of this constraint part.
Definition: AngleConstraintPart.h:183
void WarmStart(Body &ioBody1, Body &ioBody2, float inWarmStartImpulseRatio)
Definition: AngleConstraintPart.h:103
bool SolveVelocityConstraint(Body &ioBody1, Body &ioBody2, Vec3Arg inWorldSpaceAxis, float inMinLambda, float inMaxLambda)
Definition: AngleConstraintPart.h:115
void SaveState(StateRecorder &inStream) const
Save state of this constraint part.
Definition: AngleConstraintPart.h:177
float GetTotalLambda() const
Return lagrange multiplier.
Definition: AngleConstraintPart.h:129
Definition: Body.h:33
Quat GetRotation() const
World space rotation of the body.
Definition: Body.h:187
Definition: Ellipse.h:14
Float2 GetClosestPoint(const Float2 &inPoint) const
Definition: Ellipse.h:30
bool IsInside(const Float2 &inPoint) const
Check if inPoint is inside the ellipsse.
Definition: Ellipse.h:22
Class that holds 2 floats, used as a storage class mainly.
Definition: Float2.h:11
float y
Definition: Float2.h:30
float x
Definition: Float2.h:29
static JPH_INLINE Mat44 sRotation(Vec3Arg inAxis, float inAngle)
Rotate around arbitrary axis.
Definition: Mat44.inl:139
Definition: Quat.h:33
JPH_INLINE float GetW() const
Get W component (real part)
Definition: Quat.h:77
JPH_INLINE float GetY() const
Get Y component (imaginary part j)
Definition: Quat.h:71
JPH_INLINE float GetZ() const
Get Z component (imaginary part k)
Definition: Quat.h:74
JPH_INLINE float GetX() const
Get X component (imaginary part i)
Definition: Quat.h:68
static JPH_INLINE Quat sIdentity()
Definition: Quat.h:93
JPH_INLINE void GetSwingTwist(Quat &outSwing, Quat &outTwist) const
Definition: Quat.inl:215
JPH_INLINE Vec3 RotateAxisZ() const
Rotate a the vector (0, 0, 1) with this quaternion.
Definition: Quat.inl:306
JPH_INLINE Vec3 RotateAxisY() const
Rotate a the vector (0, 1, 0) with this quaternion.
Definition: Quat.inl:297
bool IsNormalized(float inTolerance=1.0e-5f) const
If the length of this quaternion is 1 +/- inTolerance.
Definition: Quat.h:58
Definition: RotationEulerConstraintPart.h:36
bool SolvePositionConstraint(Body &ioBody1, Body &ioBody2, QuatArg inInvInitialOrientation, float inBaumgarte) const
Iteratively update the position constraint. Makes sure C(...) = 0.
Definition: RotationEulerConstraintPart.h:181
void CalculateConstraintProperties(const Body &inBody1, Mat44Arg inRotation1, const Body &inBody2, Mat44Arg inRotation2)
Calculate properties used during the functions below.
Definition: RotationEulerConstraintPart.h:139
Definition: StateRecorder.h:15
Definition: SwingTwistConstraintPart.h:26
float GetTotalSwingYLambda() const
Return lagrange multiplier for swing.
Definition: SwingTwistConstraintPart.h:394
void ClampSwingTwist(Quat &ioSwing, bool &outSwingYClamped, bool &outSwingZClamped, Quat &ioTwist, bool &outTwistClamped) const
Clamp twist and swing against the constraint limits, returns which parts were clamped (everything ass...
Definition: SwingTwistConstraintPart.h:102
void RestoreState(StateRecorder &inStream)
Restore state of this constraint part.
Definition: SwingTwistConstraintPart.h:419
float GetTotalSwingZLambda() const
Definition: SwingTwistConstraintPart.h:399
float GetTotalTwistLambda() const
Return lagrange multiplier for twist.
Definition: SwingTwistConstraintPart.h:405
void WarmStart(Body &ioBody1, Body &ioBody2, float inWarmStartImpulseRatio)
Must be called from the WarmStartVelocityConstraint call to apply the previous frame's impulses.
Definition: SwingTwistConstraintPart.h:341
void SaveState(StateRecorder &inStream) const
Save state of this constraint part.
Definition: SwingTwistConstraintPart.h:411
void SetLimits(float inTwistMinAngle, float inTwistMaxAngle, float inSwingYHalfAngle, float inSwingZHalfAngle)
Set limits for this constraint (see description above for parameters)
Definition: SwingTwistConstraintPart.h:29
bool SolveVelocityConstraint(Body &ioBody1, Body &ioBody2)
Iteratively update the velocity constraint. Makes sure d/dt C(...) = 0, where C is the constraint equ...
Definition: SwingTwistConstraintPart.h:349
void Deactivate()
Deactivate this constraint.
Definition: SwingTwistConstraintPart.h:327
bool SolvePositionConstraint(Body &ioBody1, Body &ioBody2, QuatArg inConstraintRotation, QuatArg inConstraintToBody1, QuatArg inConstraintToBody2, float inBaumgarte) const
Definition: SwingTwistConstraintPart.h:373
void CalculateConstraintProperties(float inDeltaTime, const Body &inBody1, const Body &inBody2, QuatArg inConstraintRotation, QuatArg inConstraintToWorld)
Definition: SwingTwistConstraintPart.h:217
bool IsActive() const
Check if constraint is active.
Definition: SwingTwistConstraintPart.h:335
Definition: Vec3.h:16
JPH_INLINE Vec3 Cross(Vec3Arg inV2) const
Cross product.
Definition: Vec3.inl:582
JPH_INLINE float Length() const
Length of vector.
Definition: Vec3.inl:669
Definition: Vec4.h:14
JPH_INLINE float GetW() const
Definition: Vec4.h:115
JPH_INLINE float GetX() const
Get individual components.
Definition: Vec4.h:112
JPH_INLINE float GetZ() const
Definition: Vec4.h:114
JPH_INLINE float GetY() const
Definition: Vec4.h:113