|
@@ -15,6 +15,40 @@ JPH_NAMESPACE_BEGIN
|
|
|
JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(FixedConstraintSettings)
|
|
|
{
|
|
|
JPH_ADD_BASE_CLASS(FixedConstraintSettings, TwoBodyConstraintSettings)
|
|
|
+
|
|
|
+ JPH_ADD_ENUM_ATTRIBUTE(FixedConstraintSettings, mSpace)
|
|
|
+ JPH_ADD_ATTRIBUTE(FixedConstraintSettings, mPoint1)
|
|
|
+ JPH_ADD_ATTRIBUTE(FixedConstraintSettings, mAxisX1)
|
|
|
+ JPH_ADD_ATTRIBUTE(FixedConstraintSettings, mAxisY1)
|
|
|
+ JPH_ADD_ATTRIBUTE(FixedConstraintSettings, mPoint2)
|
|
|
+ JPH_ADD_ATTRIBUTE(FixedConstraintSettings, mAxisX2)
|
|
|
+ JPH_ADD_ATTRIBUTE(FixedConstraintSettings, mAxisY2)
|
|
|
+}
|
|
|
+
|
|
|
+void FixedConstraintSettings::SaveBinaryState(StreamOut &inStream) const
|
|
|
+{
|
|
|
+ ConstraintSettings::SaveBinaryState(inStream);
|
|
|
+
|
|
|
+ inStream.Write(mSpace);
|
|
|
+ inStream.Write(mPoint1);
|
|
|
+ inStream.Write(mAxisX1);
|
|
|
+ inStream.Write(mAxisY1);
|
|
|
+ inStream.Write(mPoint2);
|
|
|
+ inStream.Write(mAxisX2);
|
|
|
+ inStream.Write(mAxisY2);
|
|
|
+}
|
|
|
+
|
|
|
+void FixedConstraintSettings::RestoreBinaryState(StreamIn &inStream)
|
|
|
+{
|
|
|
+ ConstraintSettings::RestoreBinaryState(inStream);
|
|
|
+
|
|
|
+ inStream.Read(mSpace);
|
|
|
+ inStream.Read(mPoint1);
|
|
|
+ inStream.Read(mAxisX1);
|
|
|
+ inStream.Read(mAxisY1);
|
|
|
+ inStream.Read(mPoint2);
|
|
|
+ inStream.Read(mAxisX2);
|
|
|
+ inStream.Read(mAxisY2);
|
|
|
}
|
|
|
|
|
|
TwoBodyConstraint *FixedConstraintSettings::Create(Body &inBody1, Body &inBody2) const
|
|
@@ -22,29 +56,45 @@ TwoBodyConstraint *FixedConstraintSettings::Create(Body &inBody1, Body &inBody2)
|
|
|
return new FixedConstraint(inBody1, inBody2, *this);
|
|
|
}
|
|
|
|
|
|
-FixedConstraint::FixedConstraint(Body &inBody1, Body &inBody2, const FixedConstraintSettings &inSettings) :
|
|
|
- TwoBodyConstraint(inBody1, inBody2, inSettings)
|
|
|
-{
|
|
|
+void FixedConstraintSettings::SetPoint(const Body &inBody1, const Body &inBody2)
|
|
|
+{
|
|
|
+ JPH_ASSERT(mSpace == EConstraintSpace::WorldSpace);
|
|
|
+
|
|
|
// Determine anchor point: If any of the bodies can never be dynamic use the other body as anchor point
|
|
|
Vec3 anchor;
|
|
|
- if (!mBody1->CanBeKinematicOrDynamic())
|
|
|
- anchor = mBody2->GetCenterOfMassPosition();
|
|
|
- else if (!mBody2->CanBeKinematicOrDynamic())
|
|
|
- anchor = mBody1->GetCenterOfMassPosition();
|
|
|
+ if (!inBody1.CanBeKinematicOrDynamic())
|
|
|
+ anchor = inBody2.GetCenterOfMassPosition();
|
|
|
+ else if (!inBody2.CanBeKinematicOrDynamic())
|
|
|
+ anchor = inBody1.GetCenterOfMassPosition();
|
|
|
else
|
|
|
{
|
|
|
// Otherwise use weighted anchor point towards the lightest body
|
|
|
- float inv_m1 = mBody1->GetMotionPropertiesUnchecked()->GetInverseMassUnchecked();
|
|
|
- float inv_m2 = mBody2->GetMotionPropertiesUnchecked()->GetInverseMassUnchecked();
|
|
|
- anchor = (inv_m1 * mBody1->GetCenterOfMassPosition() + inv_m2 * mBody2->GetCenterOfMassPosition()) / (inv_m1 + inv_m2);
|
|
|
+ float inv_m1 = inBody1.GetMotionPropertiesUnchecked()->GetInverseMassUnchecked();
|
|
|
+ float inv_m2 = inBody2.GetMotionPropertiesUnchecked()->GetInverseMassUnchecked();
|
|
|
+ anchor = (inv_m1 * inBody1.GetCenterOfMassPosition() + inv_m2 * inBody2.GetCenterOfMassPosition()) / (inv_m1 + inv_m2);
|
|
|
}
|
|
|
|
|
|
- // Store local positions
|
|
|
- mLocalSpacePosition1 = inBody1.GetInverseCenterOfMassTransform() * anchor;
|
|
|
- mLocalSpacePosition2 = inBody2.GetInverseCenterOfMassTransform() * anchor;
|
|
|
+ mPoint1 = mPoint2 = anchor;
|
|
|
+}
|
|
|
+
|
|
|
+FixedConstraint::FixedConstraint(Body &inBody1, Body &inBody2, const FixedConstraintSettings &inSettings) :
|
|
|
+ TwoBodyConstraint(inBody1, inBody2, inSettings),
|
|
|
+ mLocalSpacePosition1(inSettings.mPoint1),
|
|
|
+ mLocalSpacePosition2(inSettings.mPoint2)
|
|
|
+{
|
|
|
+ // Store inverse of initial rotation from body 1 to body 2 in body 1 space
|
|
|
+ mInvInitialOrientation = RotationEulerConstraintPart::sGetInvInitialOrientationXY(inSettings.mAxisX1, inSettings.mAxisY1, inSettings.mAxisX2, inSettings.mAxisY2);
|
|
|
+
|
|
|
+ if (inSettings.mSpace == EConstraintSpace::WorldSpace)
|
|
|
+ {
|
|
|
+ // Store local positions
|
|
|
+ mLocalSpacePosition1 = inBody1.GetInverseCenterOfMassTransform() * mLocalSpacePosition1;
|
|
|
+ mLocalSpacePosition2 = inBody2.GetInverseCenterOfMassTransform() * mLocalSpacePosition2;
|
|
|
|
|
|
- // Inverse of initial rotation from body 1 to body 2 in body 1 space
|
|
|
- mInvInitialOrientation = RotationEulerConstraintPart::sGetInvInitialOrientation(inBody1, inBody2);
|
|
|
+ // Constraints were specified in world space, so we should have replaced c1 with q10^-1 c1 and c2 with q20^-1 c2
|
|
|
+ // => r0^-1 = (q20^-1 c2) (q10^-1 c1)^1 = q20^-1 (c2 c1^-1) q10
|
|
|
+ mInvInitialOrientation = inBody2.GetRotation().Conjugated() * mInvInitialOrientation * inBody1.GetRotation();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void FixedConstraint::SetupVelocityConstraint(float inDeltaTime)
|
|
@@ -116,8 +166,16 @@ void FixedConstraint::RestoreState(StateRecorder &inStream)
|
|
|
|
|
|
Ref<ConstraintSettings> FixedConstraint::GetConstraintSettings() const
|
|
|
{
|
|
|
- JPH_ASSERT(false); // Not implemented yet
|
|
|
- return nullptr;
|
|
|
+ FixedConstraintSettings *settings = new FixedConstraintSettings;
|
|
|
+ ToConstraintSettings(*settings);
|
|
|
+ settings->mSpace = EConstraintSpace::LocalToBodyCOM;
|
|
|
+ settings->mPoint1 = mLocalSpacePosition1;
|
|
|
+ settings->mAxisX1 = Vec3::sAxisX();
|
|
|
+ settings->mAxisY1 = Vec3::sAxisY();
|
|
|
+ settings->mPoint2 = mLocalSpacePosition2;
|
|
|
+ settings->mAxisX2 = mInvInitialOrientation.RotateAxisX();
|
|
|
+ settings->mAxisY2 = mInvInitialOrientation.RotateAxisY();
|
|
|
+ return settings;
|
|
|
}
|
|
|
|
|
|
JPH_NAMESPACE_END
|