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
216 inline void CalculateConstraintProperties(const Body &inBody1, const Body &inBody2, QuatArg inConstraintRotation, QuatArg inConstraintToWorld)
217 {
218 // Decompose into swing and twist
219 Quat q_swing, q_twist;
220 inConstraintRotation.GetSwingTwist(q_swing, q_twist);
221
222 // Clamp against joint limits
223 Quat q_clamped_swing = q_swing, q_clamped_twist = q_twist;
224 bool swing_y_clamped, swing_z_clamped, twist_clamped;
225 ClampSwingTwist(q_clamped_swing, swing_y_clamped, swing_z_clamped, q_clamped_twist, twist_clamped);
226
227 if (mRotationFlags & SwingYLocked)
228 {
229 Quat twist_to_world = inConstraintToWorld * q_swing;
230 mWorldSpaceSwingLimitYRotationAxis = twist_to_world.RotateAxisY();
231 mWorldSpaceSwingLimitZRotationAxis = twist_to_world.RotateAxisZ();
232
233 if (mRotationFlags & SwingZLocked)
234 {
235 // Swing fully locked
236 mSwingLimitYConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceSwingLimitYRotationAxis);
237 mSwingLimitZConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceSwingLimitZRotationAxis);
238 }
239 else
240 {
241 // Swing only locked around Y
242 mSwingLimitYConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceSwingLimitYRotationAxis);
243 if (swing_z_clamped)
244 {
245 if (Sign(q_swing.GetW()) * q_swing.GetZ() < 0.0f)
246 mWorldSpaceSwingLimitZRotationAxis = -mWorldSpaceSwingLimitZRotationAxis; // Flip axis if angle is negative because the impulse limit is going to be between [-FLT_MAX, 0]
247 mSwingLimitZConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceSwingLimitZRotationAxis);
248 }
249 else
250 mSwingLimitZConstraintPart.Deactivate();
251 }
252 }
253 else if (mRotationFlags & SwingZLocked)
254 {
255 // Swing only locked around Z
256 Quat twist_to_world = inConstraintToWorld * q_swing;
257 mWorldSpaceSwingLimitYRotationAxis = twist_to_world.RotateAxisY();
258 mWorldSpaceSwingLimitZRotationAxis = twist_to_world.RotateAxisZ();
259
260 if (swing_y_clamped)
261 {
262 if (Sign(q_swing.GetW()) * q_swing.GetY() < 0.0f)
263 mWorldSpaceSwingLimitYRotationAxis = -mWorldSpaceSwingLimitYRotationAxis; // Flip axis if angle is negative because the impulse limit is going to be between [-FLT_MAX, 0]
264 mSwingLimitYConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceSwingLimitYRotationAxis);
265 }
266 else
267 mSwingLimitYConstraintPart.Deactivate();
268 mSwingLimitZConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceSwingLimitZRotationAxis);
269 }
270 else if ((mRotationFlags & SwingYZFree) != SwingYZFree)
271 {
272 // Swing has limits around Y and Z
273 if (swing_y_clamped || swing_z_clamped)
274 {
275 // Calculate axis of rotation from clamped swing to swing
276 Vec3 current = (inConstraintToWorld * q_swing).RotateAxisX();
277 Vec3 desired = (inConstraintToWorld * q_clamped_swing).RotateAxisX();
278 mWorldSpaceSwingLimitYRotationAxis = desired.Cross(current);
279 float len = mWorldSpaceSwingLimitYRotationAxis.Length();
280 if (len != 0.0f)
281 {
282 mWorldSpaceSwingLimitYRotationAxis /= len;
283 mSwingLimitYConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceSwingLimitYRotationAxis);
284 }
285 else
286 mSwingLimitYConstraintPart.Deactivate();
287 }
288 else
289 mSwingLimitYConstraintPart.Deactivate();
290 mSwingLimitZConstraintPart.Deactivate();
291 }
292 else
293 {
294 // No swing limits
295 mSwingLimitYConstraintPart.Deactivate();
296 mSwingLimitZConstraintPart.Deactivate();
297 }
298
299 if (mRotationFlags & TwistXLocked)
300 {
301 // Twist locked, always activate constraint
302 mWorldSpaceTwistLimitRotationAxis = (inConstraintToWorld * q_swing).RotateAxisX();
303 mTwistLimitConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceTwistLimitRotationAxis);
304 }
305 else if ((mRotationFlags & TwistXFree) == 0)
306 {
307 // Twist has limits
308 if (twist_clamped)
309 {
310 mWorldSpaceTwistLimitRotationAxis = (inConstraintToWorld * q_swing).RotateAxisX();
311 if (Sign(q_twist.GetW()) * q_twist.GetX() < 0.0f)
312 mWorldSpaceTwistLimitRotationAxis = -mWorldSpaceTwistLimitRotationAxis; // Flip axis if angle is negative because the impulse limit is going to be between [-FLT_MAX, 0]
313 mTwistLimitConstraintPart.CalculateConstraintProperties(inBody1, inBody2, mWorldSpaceTwistLimitRotationAxis);
314 }
315 else
316 mTwistLimitConstraintPart.Deactivate();
317 }
318 else
319 {
320 // No twist limits
321 mTwistLimitConstraintPart.Deactivate();
322 }
323 }
324
327 {
328 mSwingLimitYConstraintPart.Deactivate();
329 mSwingLimitZConstraintPart.Deactivate();
330 mTwistLimitConstraintPart.Deactivate();
331 }
332
334 inline bool IsActive() const
335 {
336 return mSwingLimitYConstraintPart.IsActive() || mSwingLimitZConstraintPart.IsActive() || mTwistLimitConstraintPart.IsActive();
337 }
338
340 inline void WarmStart(Body &ioBody1, Body &ioBody2, float inWarmStartImpulseRatio)
341 {
342 mSwingLimitYConstraintPart.WarmStart(ioBody1, ioBody2, inWarmStartImpulseRatio);
343 mSwingLimitZConstraintPart.WarmStart(ioBody1, ioBody2, inWarmStartImpulseRatio);
344 mTwistLimitConstraintPart.WarmStart(ioBody1, ioBody2, inWarmStartImpulseRatio);
345 }
346
348 inline bool SolveVelocityConstraint(Body &ioBody1, Body &ioBody2)
349 {
350 bool impulse = false;
351
352 // Solve swing constraint
353 if (mSwingLimitYConstraintPart.IsActive())
354 impulse |= mSwingLimitYConstraintPart.SolveVelocityConstraint(ioBody1, ioBody2, mWorldSpaceSwingLimitYRotationAxis, -FLT_MAX, (mRotationFlags & SwingYLocked)? FLT_MAX : 0.0f);
355
356 if (mSwingLimitZConstraintPart.IsActive())
357 impulse |= mSwingLimitZConstraintPart.SolveVelocityConstraint(ioBody1, ioBody2, mWorldSpaceSwingLimitZRotationAxis, -FLT_MAX, (mRotationFlags & SwingZLocked)? FLT_MAX : 0.0f);
358
359 // Solve twist constraint
360 if (mTwistLimitConstraintPart.IsActive())
361 impulse |= mTwistLimitConstraintPart.SolveVelocityConstraint(ioBody1, ioBody2, mWorldSpaceTwistLimitRotationAxis, -FLT_MAX, (mRotationFlags & TwistXLocked)? FLT_MAX : 0.0f);
362
363 return impulse;
364 }
365
372 inline bool SolvePositionConstraint(Body &ioBody1, Body &ioBody2, QuatArg inConstraintRotation, QuatArg inConstraintToBody1, QuatArg inConstraintToBody2, float inBaumgarte) const
373 {
374 Quat q_swing, q_twist;
375 inConstraintRotation.GetSwingTwist(q_swing, q_twist);
376
377 bool swing_y_clamped, swing_z_clamped, twist_clamped;
378 ClampSwingTwist(q_swing, swing_y_clamped, swing_z_clamped, q_twist, twist_clamped);
379
380 // Solve rotation violations
381 if (swing_y_clamped || swing_z_clamped || twist_clamped)
382 {
384 Quat inv_initial_orientation = inConstraintToBody2 * (inConstraintToBody1 * q_swing * q_twist).Conjugated();
385 part.CalculateConstraintProperties(ioBody1, Mat44::sRotation(ioBody1.GetRotation()), ioBody2, Mat44::sRotation(ioBody2.GetRotation()));
386 return part.SolvePositionConstraint(ioBody1, ioBody2, inv_initial_orientation, inBaumgarte);
387 }
388
389 return false;
390 }
391
393 inline float GetTotalSwingYLambda() const
394 {
395 return mSwingLimitYConstraintPart.GetTotalLambda();
396 }
397
398 inline float GetTotalSwingZLambda() const
399 {
400 return mSwingLimitZConstraintPart.GetTotalLambda();
401 }
402
404 inline float GetTotalTwistLambda() const
405 {
406 return mTwistLimitConstraintPart.GetTotalLambda();
407 }
408
410 void SaveState(StateRecorder &inStream) const
411 {
412 mSwingLimitYConstraintPart.SaveState(inStream);
413 mSwingLimitZConstraintPart.SaveState(inStream);
414 mTwistLimitConstraintPart.SaveState(inStream);
415 }
416
419 {
420 mSwingLimitYConstraintPart.RestoreState(inStream);
421 mSwingLimitZConstraintPart.RestoreState(inStream);
422 mTwistLimitConstraintPart.RestoreState(inStream);
423 }
424
425private:
426 // CONFIGURATION PROPERTIES FOLLOW
427
428 enum ERotationFlags
429 {
431 TwistXLocked = 1 << 0,
432 SwingYLocked = 1 << 1,
433 SwingZLocked = 1 << 2,
434
436 TwistXFree = 1 << 3,
437 SwingYFree = 1 << 4,
438 SwingZFree = 1 << 5,
439 SwingYZFree = SwingYFree | SwingZFree
440 };
441
442 uint8 mRotationFlags;
443
444 // Constants
445 float mSinTwistHalfMinAngle;
446 float mSinTwistHalfMaxAngle;
447 float mCosTwistHalfMinAngle;
448 float mCosTwistHalfMaxAngle;
449 float mSinSwingYQuarterAngle;
450 float mSinSwingZQuarterAngle;
451
452 // RUN TIME PROPERTIES FOLLOW
453
455 Vec3 mWorldSpaceSwingLimitYRotationAxis;
456 Vec3 mWorldSpaceSwingLimitZRotationAxis;
457 Vec3 mWorldSpaceTwistLimitRotationAxis;
458
460 AngleConstraintPart mSwingLimitYConstraintPart;
461 AngleConstraintPart mSwingLimitZConstraintPart;
462 AngleConstraintPart mTwistLimitConstraintPart;
463};
464
std::uint8_t uint8
Definition: Core.h:427
#define JPH_NAMESPACE_END
Definition: Core.h:354
#define JPH_NAMESPACE_BEGIN
Definition: Core.h:348
#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:37
void Deactivate()
Deactivate this constraint.
Definition: AngleConstraintPart.h:148
bool IsActive() const
Check if constraint is active.
Definition: AngleConstraintPart.h:155
void CalculateConstraintProperties(const Body &inBody1, const Body &inBody2, Vec3Arg inWorldSpaceAxis, float inBias=0.0f)
Definition: AngleConstraintPart.h:81
void RestoreState(StateRecorder &inStream)
Restore state of this constraint part.
Definition: AngleConstraintPart.h:244
void WarmStart(Body &ioBody1, Body &ioBody2, float inWarmStartImpulseRatio)
Definition: AngleConstraintPart.h:164
bool SolveVelocityConstraint(Body &ioBody1, Body &ioBody2, Vec3Arg inWorldSpaceAxis, float inMinLambda, float inMaxLambda)
Definition: AngleConstraintPart.h:176
void SaveState(StateRecorder &inStream) const
Save state of this constraint part.
Definition: AngleConstraintPart.h:238
float GetTotalLambda() const
Return lagrange multiplier.
Definition: AngleConstraintPart.h:190
Definition: Body.h:35
Quat GetRotation() const
World space rotation of the body.
Definition: Body.h:210
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:31
float x
Definition: Float2.h:30
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:78
JPH_INLINE float GetY() const
Get Y component (imaginary part j)
Definition: Quat.h:72
JPH_INLINE float GetZ() const
Get Z component (imaginary part k)
Definition: Quat.h:75
JPH_INLINE float GetX() const
Get X component (imaginary part i)
Definition: Quat.h:69
static JPH_INLINE Quat sIdentity()
Definition: Quat.h:103
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:59
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:182
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:48
Definition: SwingTwistConstraintPart.h:26
float GetTotalSwingYLambda() const
Return lagrange multiplier for swing.
Definition: SwingTwistConstraintPart.h:393
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:418
float GetTotalSwingZLambda() const
Definition: SwingTwistConstraintPart.h:398
float GetTotalTwistLambda() const
Return lagrange multiplier for twist.
Definition: SwingTwistConstraintPart.h:404
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:340
void SaveState(StateRecorder &inStream) const
Save state of this constraint part.
Definition: SwingTwistConstraintPart.h:410
void CalculateConstraintProperties(const Body &inBody1, const Body &inBody2, QuatArg inConstraintRotation, QuatArg inConstraintToWorld)
Definition: SwingTwistConstraintPart.h:216
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:348
void Deactivate()
Deactivate this constraint.
Definition: SwingTwistConstraintPart.h:326
bool SolvePositionConstraint(Body &ioBody1, Body &ioBody2, QuatArg inConstraintRotation, QuatArg inConstraintToBody1, QuatArg inConstraintToBody2, float inBaumgarte) const
Definition: SwingTwistConstraintPart.h:372
bool IsActive() const
Check if constraint is active.
Definition: SwingTwistConstraintPart.h:334
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:116
JPH_INLINE float GetX() const
Get individual components.
Definition: Vec4.h:113
JPH_INLINE float GetZ() const
Definition: Vec4.h:115
JPH_INLINE float GetY() const
Definition: Vec4.h:114