123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
- // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #include <Jolt/Jolt.h>
- #include <Jolt/Physics/Body/MotionProperties.h>
- #include <Jolt/Physics/StateRecorder.h>
- JPH_NAMESPACE_BEGIN
- void MotionProperties::SetMassProperties(EAllowedDOFs inAllowedDOFs, const MassProperties &inMassProperties)
- {
- // Store allowed DOFs
- mAllowedDOFs = inAllowedDOFs;
- // Decompose DOFs
- uint allowed_translation_axis = uint(inAllowedDOFs) & 0b111;
- uint allowed_rotation_axis = (uint(inAllowedDOFs) >> 3) & 0b111;
- // Set inverse mass
- if (allowed_translation_axis == 0)
- {
- // No translation possible
- mInvMass = 0.0f;
- }
- else
- {
- JPH_ASSERT(inMassProperties.mMass > 0.0f);
- mInvMass = 1.0f / inMassProperties.mMass;
- }
- if (allowed_rotation_axis == 0b111)
- {
- // Set inverse inertia
- Mat44 rotation;
- Vec3 diagonal;
- if (inMassProperties.DecomposePrincipalMomentsOfInertia(rotation, diagonal)
- && !diagonal.IsNearZero())
- {
- mInvInertiaDiagonal = diagonal.Reciprocal();
- mInertiaRotation = rotation.GetQuaternion();
- }
- else
- {
- // Failed! Fall back to inertia tensor of sphere with radius 1.
- mInvInertiaDiagonal = Vec3::sReplicate(2.5f * mInvMass);
- mInertiaRotation = Quat::sIdentity();
- }
- }
- else if (allowed_rotation_axis == 0)
- {
- // No rotation possible
- mInvInertiaDiagonal = Vec3::sZero();
- mInertiaRotation = Quat::sIdentity();
- }
- else
- {
- uint num_allowed_rotation_axis = CountBits(allowed_rotation_axis);
- if (num_allowed_rotation_axis == 1)
- {
- // We can only rotate around one axis so the inverse inertia is trivial to calculate
- mInertiaRotation = Quat::sIdentity();
- mInvInertiaDiagonal = Vec3::sZero();
- for (int axis = 0; axis < 3; ++axis)
- if ((allowed_rotation_axis & (1 << axis)) != 0)
- mInvInertiaDiagonal.SetComponent(axis, 1.0f / inMassProperties.mInertia(axis, axis));
- }
- else
- {
- JPH_ASSERT(num_allowed_rotation_axis == 2);
- uint locked_axis = CountTrailingZeros(~allowed_rotation_axis);
- // Copy the mass properties so we can modify it
- MassProperties copy = inMassProperties;
- Mat44 &inertia = copy.mInertia;
- // Set the locked row and column to 0
- for (uint axis = 0; axis < 3; ++axis)
- {
- inertia(axis, locked_axis) = 0.0f;
- inertia(locked_axis, axis) = 0.0f;
- }
- // Set the diagonal entry to 1
- inertia(locked_axis, locked_axis) = 1.0f;
- // Decompose the inertia matrix, note that using a 2x2 matrix would have been more efficient
- // but we happen to have a 3x3 matrix version lying around so we use that.
- Mat44 rotation;
- Vec3 diagonal;
- if (copy.DecomposePrincipalMomentsOfInertia(rotation, diagonal))
- {
- mInvInertiaDiagonal = diagonal.Reciprocal();
- mInertiaRotation = rotation.GetQuaternion();
- // Now set the diagonal entry corresponding to the locked axis to 0
- for (uint axis = 0; axis < 3; ++axis)
- if (abs(inertia.GetColumn3(locked_axis).Dot(rotation.GetColumn3(axis))) > 0.999f)
- {
- mInvInertiaDiagonal.SetComponent(axis, 0.0f);
- break;
- }
- // Check that we placed a zero
- JPH_ASSERT(Vec3::sEquals(mInvInertiaDiagonal, Vec3::sZero()).TestAnyXYZTrue());
- }
- else
- {
- // Failed! Fall back to inaccurate version.
- mInertiaRotation = Quat::sIdentity();
- mInvInertiaDiagonal = Vec3::sZero();
- for (uint axis = 0; axis < 3; ++axis)
- if (axis != locked_axis)
- mInvInertiaDiagonal.SetComponent(axis, 1.0f / inertia.GetColumn3(axis).Length());
- }
- }
- }
- JPH_ASSERT(mInvMass != 0.0f || mInvInertiaDiagonal != Vec3::sZero(), "Can't lock all axes, use a static body for this. This will crash with a division by zero later!");
- }
- void MotionProperties::SaveState(StateRecorder &inStream) const
- {
- // Only write properties that can change at runtime
- inStream.Write(mLinearVelocity);
- inStream.Write(mAngularVelocity);
- inStream.Write(mForce);
- inStream.Write(mTorque);
- #ifdef JPH_DOUBLE_PRECISION
- inStream.Write(mSleepTestOffset);
- #endif // JPH_DOUBLE_PRECISION
- inStream.Write(mSleepTestSpheres);
- inStream.Write(mSleepTestTimer);
- inStream.Write(mAllowSleeping);
- }
- void MotionProperties::RestoreState(StateRecorder &inStream)
- {
- inStream.Read(mLinearVelocity);
- inStream.Read(mAngularVelocity);
- inStream.Read(mForce);
- inStream.Read(mTorque);
- #ifdef JPH_DOUBLE_PRECISION
- inStream.Read(mSleepTestOffset);
- #endif // JPH_DOUBLE_PRECISION
- inStream.Read(mSleepTestSpheres);
- inStream.Read(mSleepTestTimer);
- inStream.Read(mAllowSleeping);
- }
- JPH_NAMESPACE_END
|