123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Matrix3x3.h>
- #include <Mathematics/Rotation.h>
- #include <functional>
- namespace WwiseGTE
- {
- template <typename Real>
- class RigidBody
- {
- public:
- // Construction and destruction. The rigid body state is
- // uninitialized. Use the set functions to initialize the state
- // before starting the simulation.
- virtual ~RigidBody() = default;
- RigidBody()
- :
- mMass(std::numeric_limits<Real>::max()),
- mInvMass((Real)0),
- mInertia(Matrix3x3<Real>::Identity()),
- mInvInertia(Matrix3x3<Real>::Zero()),
- mPosition(Vector3<Real>::Zero()),
- mQuatOrient(Quaternion<Real>::Identity()),
- mLinearMomentum(Vector3<Real>::Zero()),
- mAngularMomentum(Vector3<Real>::Zero()),
- mRotOrient(Matrix3x3<Real>::Identity()),
- mLinearVelocity(Vector3<Real>::Zero()),
- mAngularVelocity(Vector3<Real>::Zero())
- {
- // The default body is immovable.
- }
- // Set rigid body state.
- void SetMass(float mass)
- {
- if ((Real)0 < mass && mass < std::numeric_limits<Real>::max())
- {
- mMass = mass;
- mInvMass = (Real)1 / mass;
- }
- else
- {
- // Assume the body as immovable.
- mMass = std::numeric_limits<Real>::max();
- mInvMass = (Real)0;
- mInertia = Matrix3x3<Real>::Identity();
- mInvInertia = Matrix3x3<Real>::Zero();
- mQuatOrient = Quaternion<Real>::Identity();
- mLinearMomentum = Vector3<Real>::Zero();
- mAngularMomentum = Vector3<Real>::Zero();
- mRotOrient = Matrix3x3<Real>::Identity();
- mLinearVelocity = Vector3<Real>::Zero();
- mAngularVelocity = Vector3<Real>::Zero();
- }
- }
- void SetBodyInertia(Matrix3x3<Real> const& inertia)
- {
- mInertia = inertia;
- mInvInertia = Inverse(mInertia);
- }
- inline void SetPosition(Vector3<Real> const& position)
- {
- mPosition = position;
- }
- void SetQOrientation(Quaternion<Real> const& quatOrient)
- {
- mQuatOrient = quatOrient;
- mRotOrient = Rotation<3, Real>(mQuatOrient);
- }
- void SetLinearMomentum(Vector3<Real> const& linearMomentum)
- {
- mLinearMomentum = linearMomentum;
- mLinearVelocity = mInvMass * mLinearMomentum;
- }
- void SetAngularMomentum(Vector3<Real> const& angularMomentum)
- {
- mAngularMomentum = angularMomentum;
- // V = R^T*M
- mAngularVelocity = mAngularMomentum * mRotOrient;
- // V = J^{-1}*R^T*M
- mAngularVelocity = mInvInertia * mAngularVelocity;
- // V = R*J^{-1}*R^T*M
- mAngularVelocity = mRotOrient * mAngularVelocity;
- }
- void SetROrientation(Matrix3x3<Real> const& rotOrient)
- {
- mRotOrient = rotOrient;
- mQuatOrient = Rotation<3, Real>(mRotOrient);
- }
- void SetLinearVelocity(Vector3<Real> const& linearVelocity)
- {
- mLinearVelocity = linearVelocity;
- mLinearMomentum = mMass * mLinearVelocity;
- }
- void SetAngularVelocity(Vector3<Real> const& angularVelocity)
- {
- mAngularVelocity = angularVelocity;
- // M = R^T*V
- mAngularMomentum = mAngularVelocity * mRotOrient;
- // M = J*R^T*V
- mAngularMomentum = mInertia * mAngularMomentum;
- // M = R*J*R^T*V
- mAngularMomentum = mRotOrient * mAngularMomentum;
- }
- // Get rigid body state.
- inline Real GetMass() const
- {
- return mMass;
- }
- inline Real GetInverseMass() const
- {
- return mInvMass;
- }
- inline Matrix3x3<Real> const& GetBodyInertia() const
- {
- return mInertia;
- }
- inline Matrix3x3<Real> const& GetBodyInverseInertia() const
- {
- return mInvInertia;
- }
- Matrix3x3<Real> GetWorldInertia() const
- {
- return MultiplyABT(mRotOrient * mInertia, mRotOrient); // R*J*R^T
- }
- Matrix3x3<Real> GetWorldInverseInertia() const
- {
- // R*J^{-1}*R^T
- return MultiplyABT(mRotOrient * mInvInertia, mRotOrient);
- }
- inline Vector3<Real> const& GetPosition() const
- {
- return mPosition;
- }
- Quaternion<Real> const& GetQOrientation() const
- {
- return mQuatOrient;
- }
- inline Vector3<Real> const& GetLinearMomentum() const
- {
- return mLinearMomentum;
- }
- inline Vector3<Real> const& GetAngularMomentum() const
- {
- return mAngularMomentum;
- }
- inline Matrix3x3<Real> const& GetROrientation() const
- {
- return mRotOrient;
- }
- inline Vector3<Real> const& GetLinearVelocity() const
- {
- return mLinearVelocity;
- }
- inline Vector3<Real> const& GetAngularVelocity() const
- {
- return mAngularVelocity;
- }
- // Force/torque function format.
- typedef std::function
- <
- Vector3<Real>
- (
- Real, // time of application
- Real, // mass
- Vector3<Real> const&, // position
- Quaternion<Real> const&, // orientation
- Vector3<Real> const&, // linear momentum
- Vector3<Real> const&, // angular momentum
- Matrix3x3<Real> const&, // orientation
- Vector3<Real> const&, // linear velocity
- Vector3<Real> const& // angular velocity
- )
- >
- Function;
- // Force and torque functions.
- Function mForce;
- Function mTorque;
- // Runge-Kutta fourth-order differential equation solver
- void Update(Real t, Real dt)
- {
- // TODO: When GTE_MAT_VEC is not defined (i.e. use vec-mat),
- // test to see whether dq/dt = 0.5 * w * q (mat-vec convention)
- // needs to become a different equation.
- Real halfDT = (Real)0.5 * dt;
- Real sixthDT = dt / (Real)6;
- Real TpHalfDT = t + halfDT;
- Real TpDT = t + dt;
- Vector3<Real> newPosition, newLinearMomentum, newAngularMomentum;
- Vector3<Real> newLinearVelocity, newAngularVelocity;
- Quaternion<Real> newQuatOrient;
- Matrix3x3<Real> newRotOrient;
- // A1 = G(T,S0), B1 = S0 + (DT/2)*A1
- Vector3<Real> A1DXDT = mLinearVelocity;
- Quaternion<Real> W = Quaternion<Real>(mAngularVelocity[0],
- mAngularVelocity[1], mAngularVelocity[2], (Real)0);
- Quaternion<Real> A1DQDT = (Real)0.5 * W * mQuatOrient;
- Vector3<Real> A1DPDT = mForce(t, mMass, mPosition, mQuatOrient,
- mLinearMomentum, mAngularMomentum, mRotOrient, mLinearVelocity,
- mAngularVelocity);
- Vector3<Real> A1DLDT = mTorque(t, mMass, mPosition, mQuatOrient,
- mLinearMomentum, mAngularMomentum, mRotOrient, mLinearVelocity,
- mAngularVelocity);
- newPosition = mPosition + halfDT * A1DXDT;
- newQuatOrient = mQuatOrient + halfDT * A1DQDT;
- newLinearMomentum = mLinearMomentum + halfDT * A1DPDT;
- newAngularMomentum = mAngularMomentum + halfDT * A1DLDT;
- newRotOrient = Rotation<3, Real>(newQuatOrient);
- newLinearVelocity = mInvMass * newLinearMomentum;
- newAngularVelocity = newAngularMomentum * newRotOrient;
- newAngularVelocity = mInvInertia * newAngularVelocity;
- newAngularVelocity = newRotOrient * newAngularVelocity;
- // A2 = G(T+DT/2,B1), B2 = S0 + (DT/2)*A2
- Vector3<Real> A2DXDT = newLinearVelocity;
- W = Quaternion<Real>(newAngularVelocity[0], newAngularVelocity[1],
- newAngularVelocity[2], (Real)0);
- Quaternion<Real> A2DQDT = (Real)0.5 * W * newQuatOrient;
- Vector3<Real> A2DPDT = mForce(TpHalfDT, mMass, newPosition,
- newQuatOrient, newLinearMomentum, newAngularMomentum, newRotOrient,
- newLinearVelocity, newAngularVelocity);
- Vector3<Real> A2DLDT = mTorque(TpHalfDT, mMass, newPosition,
- newQuatOrient, newLinearMomentum, newAngularMomentum, newRotOrient,
- newLinearVelocity, newAngularVelocity);
- newPosition = mPosition + halfDT * A2DXDT;
- newQuatOrient = mQuatOrient + halfDT * A2DQDT;
- newLinearMomentum = mLinearMomentum + halfDT * A2DPDT;
- newAngularMomentum = mAngularMomentum + halfDT * A2DLDT;
- newRotOrient = Rotation<3, Real>(newQuatOrient);
- newLinearVelocity = mInvMass * newLinearMomentum;
- newAngularVelocity = newAngularMomentum * newRotOrient;
- newAngularVelocity = mInvInertia * newAngularVelocity;
- newAngularVelocity = newRotOrient * newAngularVelocity;
- // A3 = G(T+DT/2,B2), B3 = S0 + DT*A3
- Vector3<Real> A3DXDT = newLinearVelocity;
- W = Quaternion<Real>(newAngularVelocity[0], newAngularVelocity[1],
- newAngularVelocity[2], (Real)0);
- Quaternion<Real> A3DQDT = (Real)0.5 * W * newQuatOrient;
- Vector3<Real> A3DPDT = mForce(TpHalfDT, mMass, newPosition,
- newQuatOrient, newLinearMomentum, newAngularMomentum, newRotOrient,
- newLinearVelocity, newAngularVelocity);
- Vector3<Real> A3DLDT = mTorque(TpHalfDT, mMass, newPosition,
- newQuatOrient, newLinearMomentum, newAngularMomentum, newRotOrient,
- newLinearVelocity, newAngularVelocity);
- newPosition = mPosition + dt * A3DXDT;
- newQuatOrient = mQuatOrient + dt * A3DQDT;
- newLinearMomentum = mLinearMomentum + dt * A3DPDT;
- newAngularMomentum = mAngularMomentum + dt * A3DLDT;
- newRotOrient = Rotation<3, Real>(newQuatOrient);
- newLinearVelocity = mInvMass * newLinearMomentum;
- newAngularVelocity = newAngularMomentum * newRotOrient;
- newAngularVelocity = mInvInertia * newAngularVelocity;
- newAngularVelocity = newRotOrient * newAngularVelocity;
- // A4 = G(T+DT,B3), S1 = S0 + (DT/6)*(A1+2*(A2+A3)+A4)
- Vector3<Real> A4DXDT = newLinearVelocity;
- W = Quaternion<Real>(newAngularVelocity[0], newAngularVelocity[1],
- newAngularVelocity[2], (Real)0);
- Quaternion<Real> A4DQDT = (Real)0.5 * W * newQuatOrient;
- Vector3<Real> A4DPDT = mForce(TpDT, mMass, newPosition,
- newQuatOrient, newLinearMomentum, newAngularMomentum, newRotOrient,
- newLinearVelocity, newAngularVelocity);
- Vector3<Real> A4DLDT = mTorque(TpDT, mMass, newPosition, newQuatOrient,
- newLinearMomentum, newAngularMomentum, newRotOrient,
- newLinearVelocity, newAngularVelocity);
- mPosition += sixthDT * (A1DXDT + (Real)2 * (A2DXDT + A3DXDT) + A4DXDT);
- mQuatOrient += sixthDT * (A1DQDT + (Real)2 * (A2DQDT + A3DQDT) + A4DQDT);
- mLinearMomentum += sixthDT * (A1DPDT + (Real)2 * (A2DPDT + A3DPDT) + A4DPDT);
- mAngularMomentum += sixthDT * (A1DLDT + (Real)2 * (A2DLDT + A3DLDT) + A4DLDT);
- mRotOrient = Rotation<3, Real>(mQuatOrient);
- mLinearVelocity = mInvMass * mLinearMomentum;
- mAngularVelocity = mAngularMomentum * mRotOrient;
- mAngularVelocity = mInvInertia * mAngularVelocity;
- mAngularVelocity = mRotOrient * mAngularVelocity;
- }
- protected:
- // Constant quantities (matrices in body coordinates).
- Real mMass, mInvMass;
- Matrix3x3<Real> mInertia, mInvInertia;
- // State variables.
- Vector3<Real> mPosition;
- Quaternion<Real> mQuatOrient;
- Vector3<Real> mLinearMomentum;
- Vector3<Real> mAngularMomentum;
- // Derived state variables.
- Matrix3x3<Real> mRotOrient;
- Vector3<Real> mLinearVelocity;
- Vector3<Real> mAngularVelocity;
- };
- }
|