Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Constraints/SliderConstraint.cpp
9913 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#include <Jolt/Jolt.h>
6
7
#include <Jolt/Physics/Constraints/SliderConstraint.h>
8
#include <Jolt/Physics/Body/Body.h>
9
#include <Jolt/ObjectStream/TypeDeclarations.h>
10
#include <Jolt/Core/StreamIn.h>
11
#include <Jolt/Core/StreamOut.h>
12
#ifdef JPH_DEBUG_RENDERER
13
#include <Jolt/Renderer/DebugRenderer.h>
14
#endif // JPH_DEBUG_RENDERER
15
16
JPH_NAMESPACE_BEGIN
17
18
using namespace literals;
19
20
JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(SliderConstraintSettings)
21
{
22
JPH_ADD_BASE_CLASS(SliderConstraintSettings, TwoBodyConstraintSettings)
23
24
JPH_ADD_ENUM_ATTRIBUTE(SliderConstraintSettings, mSpace)
25
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mAutoDetectPoint)
26
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mPoint1)
27
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mSliderAxis1)
28
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mNormalAxis1)
29
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mPoint2)
30
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mSliderAxis2)
31
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mNormalAxis2)
32
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mLimitsMin)
33
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mLimitsMax)
34
JPH_ADD_ENUM_ATTRIBUTE_WITH_ALIAS(SliderConstraintSettings, mLimitsSpringSettings.mMode, "mSpringMode")
35
JPH_ADD_ATTRIBUTE_WITH_ALIAS(SliderConstraintSettings, mLimitsSpringSettings.mFrequency, "mFrequency") // Renaming attributes to stay compatible with old versions of the library
36
JPH_ADD_ATTRIBUTE_WITH_ALIAS(SliderConstraintSettings, mLimitsSpringSettings.mDamping, "mDamping")
37
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mMaxFrictionForce)
38
JPH_ADD_ATTRIBUTE(SliderConstraintSettings, mMotorSettings)
39
}
40
41
void SliderConstraintSettings::SetSliderAxis(Vec3Arg inSliderAxis)
42
{
43
JPH_ASSERT(mSpace == EConstraintSpace::WorldSpace);
44
45
mSliderAxis1 = mSliderAxis2 = inSliderAxis;
46
mNormalAxis1 = mNormalAxis2 = inSliderAxis.GetNormalizedPerpendicular();
47
}
48
49
void SliderConstraintSettings::SaveBinaryState(StreamOut &inStream) const
50
{
51
ConstraintSettings::SaveBinaryState(inStream);
52
53
inStream.Write(mSpace);
54
inStream.Write(mAutoDetectPoint);
55
inStream.Write(mPoint1);
56
inStream.Write(mSliderAxis1);
57
inStream.Write(mNormalAxis1);
58
inStream.Write(mPoint2);
59
inStream.Write(mSliderAxis2);
60
inStream.Write(mNormalAxis2);
61
inStream.Write(mLimitsMin);
62
inStream.Write(mLimitsMax);
63
inStream.Write(mMaxFrictionForce);
64
mLimitsSpringSettings.SaveBinaryState(inStream);
65
mMotorSettings.SaveBinaryState(inStream);
66
}
67
68
void SliderConstraintSettings::RestoreBinaryState(StreamIn &inStream)
69
{
70
ConstraintSettings::RestoreBinaryState(inStream);
71
72
inStream.Read(mSpace);
73
inStream.Read(mAutoDetectPoint);
74
inStream.Read(mPoint1);
75
inStream.Read(mSliderAxis1);
76
inStream.Read(mNormalAxis1);
77
inStream.Read(mPoint2);
78
inStream.Read(mSliderAxis2);
79
inStream.Read(mNormalAxis2);
80
inStream.Read(mLimitsMin);
81
inStream.Read(mLimitsMax);
82
inStream.Read(mMaxFrictionForce);
83
mLimitsSpringSettings.RestoreBinaryState(inStream);
84
mMotorSettings.RestoreBinaryState(inStream);
85
}
86
87
TwoBodyConstraint *SliderConstraintSettings::Create(Body &inBody1, Body &inBody2) const
88
{
89
return new SliderConstraint(inBody1, inBody2, *this);
90
}
91
92
SliderConstraint::SliderConstraint(Body &inBody1, Body &inBody2, const SliderConstraintSettings &inSettings) :
93
TwoBodyConstraint(inBody1, inBody2, inSettings),
94
mMaxFrictionForce(inSettings.mMaxFrictionForce),
95
mMotorSettings(inSettings.mMotorSettings)
96
{
97
// Store inverse of initial rotation from body 1 to body 2 in body 1 space
98
mInvInitialOrientation = RotationEulerConstraintPart::sGetInvInitialOrientationXY(inSettings.mSliderAxis1, inSettings.mNormalAxis1, inSettings.mSliderAxis2, inSettings.mNormalAxis2);
99
100
if (inSettings.mSpace == EConstraintSpace::WorldSpace)
101
{
102
RMat44 inv_transform1 = inBody1.GetInverseCenterOfMassTransform();
103
RMat44 inv_transform2 = inBody2.GetInverseCenterOfMassTransform();
104
105
if (inSettings.mAutoDetectPoint)
106
{
107
// Determine anchor point: If any of the bodies can never be dynamic use the other body as anchor point
108
RVec3 anchor;
109
if (!inBody1.CanBeKinematicOrDynamic())
110
anchor = inBody2.GetCenterOfMassPosition();
111
else if (!inBody2.CanBeKinematicOrDynamic())
112
anchor = inBody1.GetCenterOfMassPosition();
113
else
114
{
115
// Otherwise use weighted anchor point towards the lightest body
116
Real inv_m1 = Real(inBody1.GetMotionPropertiesUnchecked()->GetInverseMassUnchecked());
117
Real inv_m2 = Real(inBody2.GetMotionPropertiesUnchecked()->GetInverseMassUnchecked());
118
Real total_inv_mass = inv_m1 + inv_m2;
119
if (total_inv_mass != 0.0_r)
120
anchor = (inv_m1 * inBody1.GetCenterOfMassPosition() + inv_m2 * inBody2.GetCenterOfMassPosition()) / total_inv_mass;
121
else
122
anchor = inBody1.GetCenterOfMassPosition();
123
}
124
125
// Store local positions
126
mLocalSpacePosition1 = Vec3(inv_transform1 * anchor);
127
mLocalSpacePosition2 = Vec3(inv_transform2 * anchor);
128
}
129
else
130
{
131
// Store local positions
132
mLocalSpacePosition1 = Vec3(inv_transform1 * inSettings.mPoint1);
133
mLocalSpacePosition2 = Vec3(inv_transform2 * inSettings.mPoint2);
134
}
135
136
// If all properties were specified in world space, take them to local space now
137
mLocalSpaceSliderAxis1 = inv_transform1.Multiply3x3(inSettings.mSliderAxis1).Normalized();
138
mLocalSpaceNormal1 = inv_transform1.Multiply3x3(inSettings.mNormalAxis1).Normalized();
139
140
// Constraints were specified in world space, so we should have replaced c1 with q10^-1 c1 and c2 with q20^-1 c2
141
// => r0^-1 = (q20^-1 c2) (q10^-1 c1)^1 = q20^-1 (c2 c1^-1) q10
142
mInvInitialOrientation = inBody2.GetRotation().Conjugated() * mInvInitialOrientation * inBody1.GetRotation();
143
}
144
else
145
{
146
// Store local positions
147
mLocalSpacePosition1 = Vec3(inSettings.mPoint1);
148
mLocalSpacePosition2 = Vec3(inSettings.mPoint2);
149
150
// Store local space axis
151
mLocalSpaceSliderAxis1 = inSettings.mSliderAxis1;
152
mLocalSpaceNormal1 = inSettings.mNormalAxis1;
153
}
154
155
// Calculate 2nd local space normal
156
mLocalSpaceNormal2 = mLocalSpaceSliderAxis1.Cross(mLocalSpaceNormal1);
157
158
// Store limits
159
JPH_ASSERT(inSettings.mLimitsMin != inSettings.mLimitsMax || inSettings.mLimitsSpringSettings.mFrequency > 0.0f, "Better use a fixed constraint");
160
SetLimits(inSettings.mLimitsMin, inSettings.mLimitsMax);
161
162
// Store spring settings
163
SetLimitsSpringSettings(inSettings.mLimitsSpringSettings);
164
}
165
166
void SliderConstraint::NotifyShapeChanged(const BodyID &inBodyID, Vec3Arg inDeltaCOM)
167
{
168
if (mBody1->GetID() == inBodyID)
169
mLocalSpacePosition1 -= inDeltaCOM;
170
else if (mBody2->GetID() == inBodyID)
171
mLocalSpacePosition2 -= inDeltaCOM;
172
}
173
174
float SliderConstraint::GetCurrentPosition() const
175
{
176
// See: CalculateR1R2U and CalculateSlidingAxisAndPosition
177
Vec3 r1 = mBody1->GetRotation() * mLocalSpacePosition1;
178
Vec3 r2 = mBody2->GetRotation() * mLocalSpacePosition2;
179
Vec3 u = Vec3(mBody2->GetCenterOfMassPosition() - mBody1->GetCenterOfMassPosition()) + r2 - r1;
180
return u.Dot(mBody1->GetRotation() * mLocalSpaceSliderAxis1);
181
}
182
183
void SliderConstraint::SetLimits(float inLimitsMin, float inLimitsMax)
184
{
185
JPH_ASSERT(inLimitsMin <= 0.0f);
186
JPH_ASSERT(inLimitsMax >= 0.0f);
187
mLimitsMin = inLimitsMin;
188
mLimitsMax = inLimitsMax;
189
mHasLimits = mLimitsMin != -FLT_MAX || mLimitsMax != FLT_MAX;
190
}
191
192
void SliderConstraint::CalculateR1R2U(Mat44Arg inRotation1, Mat44Arg inRotation2)
193
{
194
// Calculate points relative to body
195
mR1 = inRotation1 * mLocalSpacePosition1;
196
mR2 = inRotation2 * mLocalSpacePosition2;
197
198
// Calculate X2 + R2 - X1 - R1
199
mU = Vec3(mBody2->GetCenterOfMassPosition() - mBody1->GetCenterOfMassPosition()) + mR2 - mR1;
200
}
201
202
void SliderConstraint::CalculatePositionConstraintProperties(Mat44Arg inRotation1, Mat44Arg inRotation2)
203
{
204
// Calculate world space normals
205
mN1 = inRotation1 * mLocalSpaceNormal1;
206
mN2 = inRotation1 * mLocalSpaceNormal2;
207
208
mPositionConstraintPart.CalculateConstraintProperties(*mBody1, inRotation1, mR1 + mU, *mBody2, inRotation2, mR2, mN1, mN2);
209
}
210
211
void SliderConstraint::CalculateSlidingAxisAndPosition(Mat44Arg inRotation1)
212
{
213
if (mHasLimits || mMotorState != EMotorState::Off || mMaxFrictionForce > 0.0f)
214
{
215
// Calculate world space slider axis
216
mWorldSpaceSliderAxis = inRotation1 * mLocalSpaceSliderAxis1;
217
218
// Calculate slide distance along axis
219
mD = mU.Dot(mWorldSpaceSliderAxis);
220
}
221
}
222
223
void SliderConstraint::CalculatePositionLimitsConstraintProperties(float inDeltaTime)
224
{
225
// Check if distance is within limits
226
bool below_min = mD <= mLimitsMin;
227
if (mHasLimits && (below_min || mD >= mLimitsMax))
228
mPositionLimitsConstraintPart.CalculateConstraintPropertiesWithSettings(inDeltaTime, *mBody1, mR1 + mU, *mBody2, mR2, mWorldSpaceSliderAxis, 0.0f, mD - (below_min? mLimitsMin : mLimitsMax), mLimitsSpringSettings);
229
else
230
mPositionLimitsConstraintPart.Deactivate();
231
}
232
233
void SliderConstraint::CalculateMotorConstraintProperties(float inDeltaTime)
234
{
235
switch (mMotorState)
236
{
237
case EMotorState::Off:
238
if (mMaxFrictionForce > 0.0f)
239
mMotorConstraintPart.CalculateConstraintProperties(*mBody1, mR1 + mU, *mBody2, mR2, mWorldSpaceSliderAxis);
240
else
241
mMotorConstraintPart.Deactivate();
242
break;
243
244
case EMotorState::Velocity:
245
mMotorConstraintPart.CalculateConstraintProperties(*mBody1, mR1 + mU, *mBody2, mR2, mWorldSpaceSliderAxis, -mTargetVelocity);
246
break;
247
248
case EMotorState::Position:
249
if (mMotorSettings.mSpringSettings.HasStiffness())
250
mMotorConstraintPart.CalculateConstraintPropertiesWithSettings(inDeltaTime, *mBody1, mR1 + mU, *mBody2, mR2, mWorldSpaceSliderAxis, 0.0f, mD - mTargetPosition, mMotorSettings.mSpringSettings);
251
else
252
mMotorConstraintPart.Deactivate();
253
break;
254
}
255
}
256
257
void SliderConstraint::SetupVelocityConstraint(float inDeltaTime)
258
{
259
// Calculate constraint properties that are constant while bodies don't move
260
Mat44 rotation1 = Mat44::sRotation(mBody1->GetRotation());
261
Mat44 rotation2 = Mat44::sRotation(mBody2->GetRotation());
262
CalculateR1R2U(rotation1, rotation2);
263
CalculatePositionConstraintProperties(rotation1, rotation2);
264
mRotationConstraintPart.CalculateConstraintProperties(*mBody1, rotation1, *mBody2, rotation2);
265
CalculateSlidingAxisAndPosition(rotation1);
266
CalculatePositionLimitsConstraintProperties(inDeltaTime);
267
CalculateMotorConstraintProperties(inDeltaTime);
268
}
269
270
void SliderConstraint::ResetWarmStart()
271
{
272
mMotorConstraintPart.Deactivate();
273
mPositionConstraintPart.Deactivate();
274
mRotationConstraintPart.Deactivate();
275
mPositionLimitsConstraintPart.Deactivate();
276
}
277
278
void SliderConstraint::WarmStartVelocityConstraint(float inWarmStartImpulseRatio)
279
{
280
// Warm starting: Apply previous frame impulse
281
mMotorConstraintPart.WarmStart(*mBody1, *mBody2, mWorldSpaceSliderAxis, inWarmStartImpulseRatio);
282
mPositionConstraintPart.WarmStart(*mBody1, *mBody2, mN1, mN2, inWarmStartImpulseRatio);
283
mRotationConstraintPart.WarmStart(*mBody1, *mBody2, inWarmStartImpulseRatio);
284
mPositionLimitsConstraintPart.WarmStart(*mBody1, *mBody2, mWorldSpaceSliderAxis, inWarmStartImpulseRatio);
285
}
286
287
bool SliderConstraint::SolveVelocityConstraint(float inDeltaTime)
288
{
289
// Solve motor
290
bool motor = false;
291
if (mMotorConstraintPart.IsActive())
292
{
293
switch (mMotorState)
294
{
295
case EMotorState::Off:
296
{
297
float max_lambda = mMaxFrictionForce * inDeltaTime;
298
motor = mMotorConstraintPart.SolveVelocityConstraint(*mBody1, *mBody2, mWorldSpaceSliderAxis, -max_lambda, max_lambda);
299
break;
300
}
301
302
case EMotorState::Velocity:
303
case EMotorState::Position:
304
motor = mMotorConstraintPart.SolveVelocityConstraint(*mBody1, *mBody2, mWorldSpaceSliderAxis, inDeltaTime * mMotorSettings.mMinForceLimit, inDeltaTime * mMotorSettings.mMaxForceLimit);
305
break;
306
}
307
}
308
309
// Solve position constraint along 2 axis
310
bool pos = mPositionConstraintPart.SolveVelocityConstraint(*mBody1, *mBody2, mN1, mN2);
311
312
// Solve rotation constraint
313
bool rot = mRotationConstraintPart.SolveVelocityConstraint(*mBody1, *mBody2);
314
315
// Solve limits along slider axis
316
bool limit = false;
317
if (mPositionLimitsConstraintPart.IsActive())
318
{
319
float min_lambda, max_lambda;
320
if (mLimitsMin == mLimitsMax)
321
{
322
min_lambda = -FLT_MAX;
323
max_lambda = FLT_MAX;
324
}
325
else if (mD <= mLimitsMin)
326
{
327
min_lambda = 0.0f;
328
max_lambda = FLT_MAX;
329
}
330
else
331
{
332
min_lambda = -FLT_MAX;
333
max_lambda = 0.0f;
334
}
335
limit = mPositionLimitsConstraintPart.SolveVelocityConstraint(*mBody1, *mBody2, mWorldSpaceSliderAxis, min_lambda, max_lambda);
336
}
337
338
return motor || pos || rot || limit;
339
}
340
341
bool SliderConstraint::SolvePositionConstraint(float inDeltaTime, float inBaumgarte)
342
{
343
// Motor operates on velocities only, don't call SolvePositionConstraint
344
345
// Solve position constraint along 2 axis
346
Mat44 rotation1 = Mat44::sRotation(mBody1->GetRotation());
347
Mat44 rotation2 = Mat44::sRotation(mBody2->GetRotation());
348
CalculateR1R2U(rotation1, rotation2);
349
CalculatePositionConstraintProperties(rotation1, rotation2);
350
bool pos = mPositionConstraintPart.SolvePositionConstraint(*mBody1, *mBody2, mU, mN1, mN2, inBaumgarte);
351
352
// Solve rotation constraint
353
mRotationConstraintPart.CalculateConstraintProperties(*mBody1, Mat44::sRotation(mBody1->GetRotation()), *mBody2, Mat44::sRotation(mBody2->GetRotation()));
354
bool rot = mRotationConstraintPart.SolvePositionConstraint(*mBody1, *mBody2, mInvInitialOrientation, inBaumgarte);
355
356
// Solve limits along slider axis
357
bool limit = false;
358
if (mHasLimits && mLimitsSpringSettings.mFrequency <= 0.0f)
359
{
360
rotation1 = Mat44::sRotation(mBody1->GetRotation());
361
rotation2 = Mat44::sRotation(mBody2->GetRotation());
362
CalculateR1R2U(rotation1, rotation2);
363
CalculateSlidingAxisAndPosition(rotation1);
364
CalculatePositionLimitsConstraintProperties(inDeltaTime);
365
if (mPositionLimitsConstraintPart.IsActive())
366
{
367
if (mD <= mLimitsMin)
368
limit = mPositionLimitsConstraintPart.SolvePositionConstraint(*mBody1, *mBody2, mWorldSpaceSliderAxis, mD - mLimitsMin, inBaumgarte);
369
else
370
{
371
JPH_ASSERT(mD >= mLimitsMax);
372
limit = mPositionLimitsConstraintPart.SolvePositionConstraint(*mBody1, *mBody2, mWorldSpaceSliderAxis, mD - mLimitsMax, inBaumgarte);
373
}
374
}
375
}
376
377
return pos || rot || limit;
378
}
379
380
#ifdef JPH_DEBUG_RENDERER
381
void SliderConstraint::DrawConstraint(DebugRenderer *inRenderer) const
382
{
383
RMat44 transform1 = mBody1->GetCenterOfMassTransform();
384
RMat44 transform2 = mBody2->GetCenterOfMassTransform();
385
386
// Transform the local positions into world space
387
Vec3 slider_axis = transform1.Multiply3x3(mLocalSpaceSliderAxis1);
388
RVec3 position1 = transform1 * mLocalSpacePosition1;
389
RVec3 position2 = transform2 * mLocalSpacePosition2;
390
391
// Draw constraint
392
inRenderer->DrawMarker(position1, Color::sRed, 0.1f);
393
inRenderer->DrawMarker(position2, Color::sGreen, 0.1f);
394
inRenderer->DrawLine(position1, position2, Color::sGreen);
395
396
// Draw motor
397
switch (mMotorState)
398
{
399
case EMotorState::Position:
400
inRenderer->DrawMarker(position1 + mTargetPosition * slider_axis, Color::sYellow, 1.0f);
401
break;
402
403
case EMotorState::Velocity:
404
{
405
Vec3 cur_vel = (mBody2->GetLinearVelocity() - mBody1->GetLinearVelocity()).Dot(slider_axis) * slider_axis;
406
inRenderer->DrawLine(position2, position2 + cur_vel, Color::sBlue);
407
inRenderer->DrawArrow(position2 + cur_vel, position2 + mTargetVelocity * slider_axis, Color::sRed, 0.1f);
408
break;
409
}
410
411
case EMotorState::Off:
412
break;
413
}
414
}
415
416
void SliderConstraint::DrawConstraintLimits(DebugRenderer *inRenderer) const
417
{
418
if (mHasLimits)
419
{
420
RMat44 transform1 = mBody1->GetCenterOfMassTransform();
421
RMat44 transform2 = mBody2->GetCenterOfMassTransform();
422
423
// Transform the local positions into world space
424
Vec3 slider_axis = transform1.Multiply3x3(mLocalSpaceSliderAxis1);
425
RVec3 position1 = transform1 * mLocalSpacePosition1;
426
RVec3 position2 = transform2 * mLocalSpacePosition2;
427
428
// Calculate the limits in world space
429
RVec3 limits_min = position1 + mLimitsMin * slider_axis;
430
RVec3 limits_max = position1 + mLimitsMax * slider_axis;
431
432
inRenderer->DrawLine(limits_min, position1, Color::sWhite);
433
inRenderer->DrawLine(position2, limits_max, Color::sWhite);
434
435
inRenderer->DrawMarker(limits_min, Color::sWhite, 0.1f);
436
inRenderer->DrawMarker(limits_max, Color::sWhite, 0.1f);
437
}
438
}
439
#endif // JPH_DEBUG_RENDERER
440
441
void SliderConstraint::SaveState(StateRecorder &inStream) const
442
{
443
TwoBodyConstraint::SaveState(inStream);
444
445
mMotorConstraintPart.SaveState(inStream);
446
mPositionConstraintPart.SaveState(inStream);
447
mRotationConstraintPart.SaveState(inStream);
448
mPositionLimitsConstraintPart.SaveState(inStream);
449
450
inStream.Write(mMotorState);
451
inStream.Write(mTargetVelocity);
452
inStream.Write(mTargetPosition);
453
}
454
455
void SliderConstraint::RestoreState(StateRecorder &inStream)
456
{
457
TwoBodyConstraint::RestoreState(inStream);
458
459
mMotorConstraintPart.RestoreState(inStream);
460
mPositionConstraintPart.RestoreState(inStream);
461
mRotationConstraintPart.RestoreState(inStream);
462
mPositionLimitsConstraintPart.RestoreState(inStream);
463
464
inStream.Read(mMotorState);
465
inStream.Read(mTargetVelocity);
466
inStream.Read(mTargetPosition);
467
}
468
469
Ref<ConstraintSettings> SliderConstraint::GetConstraintSettings() const
470
{
471
SliderConstraintSettings *settings = new SliderConstraintSettings;
472
ToConstraintSettings(*settings);
473
settings->mSpace = EConstraintSpace::LocalToBodyCOM;
474
settings->mPoint1 = RVec3(mLocalSpacePosition1);
475
settings->mSliderAxis1 = mLocalSpaceSliderAxis1;
476
settings->mNormalAxis1 = mLocalSpaceNormal1;
477
settings->mPoint2 = RVec3(mLocalSpacePosition2);
478
Mat44 inv_initial_rotation = Mat44::sRotation(mInvInitialOrientation);
479
settings->mSliderAxis2 = inv_initial_rotation.Multiply3x3(mLocalSpaceSliderAxis1);
480
settings->mNormalAxis2 = inv_initial_rotation.Multiply3x3(mLocalSpaceNormal1);
481
settings->mLimitsMin = mLimitsMin;
482
settings->mLimitsMax = mLimitsMax;
483
settings->mLimitsSpringSettings = mLimitsSpringSettings;
484
settings->mMaxFrictionForce = mMaxFrictionForce;
485
settings->mMotorSettings = mMotorSettings;
486
return settings;
487
}
488
489
Mat44 SliderConstraint::GetConstraintToBody1Matrix() const
490
{
491
return Mat44(Vec4(mLocalSpaceSliderAxis1, 0), Vec4(mLocalSpaceNormal1, 0), Vec4(mLocalSpaceNormal2, 0), Vec4(mLocalSpacePosition1, 1));
492
}
493
494
Mat44 SliderConstraint::GetConstraintToBody2Matrix() const
495
{
496
Mat44 mat = Mat44::sRotation(mInvInitialOrientation).Multiply3x3(Mat44(Vec4(mLocalSpaceSliderAxis1, 0), Vec4(mLocalSpaceNormal1, 0), Vec4(mLocalSpaceNormal2, 0), Vec4(0, 0, 0, 1)));
497
mat.SetTranslation(mLocalSpacePosition2);
498
return mat;
499
}
500
501
JPH_NAMESPACE_END
502
503