2013-11-12 12:33:52 +01:00
/////////////////////////////////////////////////////////////////////
// Created by Dan Andersson & Robin Engman 2013
/////////////////////////////////////////////////////////////////////
# include "RigidBody.h"
# include "Utilities.h"
using namespace : : Oyster : : Collision3D ;
using namespace : : Oyster : : Physics3D ;
using namespace : : Oyster : : Math3D ;
2013-11-28 11:58:46 +01:00
RigidBody : : RigidBody ( const Box & b , Float m , const Float4x4 & inertiaTensor )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-11-28 11:58:46 +01:00
this - > box = b ;
this - > angularMomentum = Float3 : : null ;
this - > linearMomentum = Float3 : : null ;
this - > impulseTorqueSum = Float3 : : null ;
this - > impulseForceSum = Float3 : : null ;
2013-11-12 12:33:52 +01:00
if ( m ! = 0.0f )
{
this - > mass = m ;
}
else
{
this - > mass = : : Utility : : Value : : numeric_limits < Float > : : epsilon ( ) ;
}
2013-11-28 11:58:46 +01:00
if ( inertiaTensor . GetDeterminant ( ) ! = 0.0f )
{
this - > momentOfInertiaTensor = inertiaTensor ;
}
else
{
this - > momentOfInertiaTensor = Float4x4 : : identity ;
}
2013-11-12 12:33:52 +01:00
}
RigidBody & RigidBody : : operator = ( const RigidBody & body )
{ // by Dan Andersson
this - > box = body . box ;
this - > angularMomentum = body . angularMomentum ;
this - > linearMomentum = body . linearMomentum ;
this - > impulseTorqueSum = body . impulseTorqueSum ;
this - > impulseForceSum = body . impulseForceSum ;
this - > mass = body . mass ;
this - > momentOfInertiaTensor = body . momentOfInertiaTensor ;
return * this ;
}
2013-11-25 16:35:56 +01:00
bool RigidBody : : operator = = ( const RigidBody & body )
{
if ( this - > box . center ! = body . box . center )
{
return false ;
}
if ( this - > box . rotation ! = body . box . rotation )
{
return false ;
}
if ( this - > box . boundingOffset ! = body . box . boundingOffset )
{
return false ;
}
if ( this - > angularMomentum ! = body . angularMomentum )
{
return false ;
}
if ( this - > linearMomentum ! = body . linearMomentum )
{
return false ;
}
if ( this - > impulseTorqueSum ! = body . impulseTorqueSum )
{
return false ;
}
if ( this - > impulseForceSum ! = body . impulseForceSum )
{
return false ;
}
return true ;
}
bool RigidBody : : operator ! = ( const RigidBody & body )
{
return ! this - > operator = = ( body ) ;
}
2013-11-12 12:33:52 +01:00
void RigidBody : : Update_LeapFrog ( Float deltaTime )
{ // by Dan Andersson: Euler leap frog update when Runga Kutta is not needed
2013-11-20 11:09:27 +01:00
// Important! The member data is all world data except the Inertia tensor. Thus a new InertiaTensor needs to be created to be compatible with the rest of the world data.
2013-11-21 11:39:11 +01:00
Float4x4 wMomentOfInertiaTensor = TransformMatrix ( this - > box . rotation , this - > momentOfInertiaTensor ) ; // RI
2013-11-20 11:09:27 +01:00
2013-11-12 12:33:52 +01:00
// updating the linear
2013-11-21 11:39:11 +01:00
// dG = F * dt
// ds = dt * Formula::LinearVelocity( m, avg_G ) = dt * avg_G / m = (dt / m) * avg_G
Float3 linearImpulse = this - > impulseForceSum * deltaTime ; // aka deltaLinearMomentum
Float3 deltaPos = ( deltaTime / this - > mass ) * : : Utility : : Value : : AverageWithDelta ( this - > linearMomentum , linearImpulse ) ;
2013-11-12 12:33:52 +01:00
// updating the angular
2013-11-21 11:39:11 +01:00
// dH = T * dt
// dO = dt * Formula::AngularVelocity( (RI)^-1, avg_H ) = dt * (RI)^-1 * avg_H
Float3 angularImpulse = this - > impulseTorqueSum * deltaTime ; // aka deltaAngularMomentum
Float3 rotationAxis = Formula : : AngularVelocity ( wMomentOfInertiaTensor . GetInverse ( ) ,
: : Utility : : Value : : AverageWithDelta ( this - > angularMomentum , angularImpulse ) ) ;
2013-11-12 12:33:52 +01:00
Float deltaRadian = rotationAxis . Dot ( rotationAxis ) ;
if ( deltaRadian ! = 0.0f )
{ // branch depending if there is rotation
deltaRadian = : : std : : sqrt ( deltaRadian ) ;
rotationAxis / = deltaRadian ;
2013-11-20 16:58:56 +01:00
// using rotationAxis, deltaRadian and deltaPos to create a matrix to update the box
2013-12-18 08:57:27 +01:00
this - > box . center . xyz + = deltaPos ;
2013-11-20 16:58:56 +01:00
TransformMatrix ( RotationMatrix ( deltaRadian , rotationAxis ) , this - > box . rotation , this - > box . rotation ) ;
2013-11-12 12:33:52 +01:00
}
else
{ // no rotation, only use deltaPos to translate the RigidBody
2013-12-18 08:57:27 +01:00
this - > box . center . xyz + = deltaPos ;
2013-11-12 12:33:52 +01:00
}
2013-11-21 15:19:32 +01:00
// update momentums and clear impulseForceSum and impulseTorqueSum
2013-11-21 11:39:11 +01:00
this - > linearMomentum + = linearImpulse ;
2013-11-12 12:33:52 +01:00
this - > impulseForceSum = Float3 : : null ;
2013-11-21 11:39:11 +01:00
this - > angularMomentum + = angularImpulse ;
2013-11-12 12:33:52 +01:00
this - > impulseTorqueSum = Float3 : : null ;
}
2013-11-20 11:44:54 +01:00
void RigidBody : : ApplyImpulseForce ( const Float3 & worldF )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-11-20 11:44:54 +01:00
this - > impulseForceSum + = worldF ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:44:54 +01:00
void RigidBody : : ApplyImpulseForceAt ( const Float3 & worldF , const Float3 & worldPos )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
Float3 worldOffset = worldPos - this - > box . center . xyz ;
2013-11-20 11:44:54 +01:00
if ( worldOffset ! = Float3 : : null )
2013-11-12 12:33:52 +01:00
{
2013-11-20 11:44:54 +01:00
this - > impulseForceSum + = VectorProjection ( worldF , worldOffset ) ;
this - > impulseTorqueSum + = Formula : : ImpulseTorque ( worldF , worldOffset ) ;
2013-11-12 12:33:52 +01:00
}
else
{
2013-11-20 11:44:54 +01:00
this - > impulseForceSum + = worldF ;
2013-11-12 12:33:52 +01:00
}
}
2013-11-20 11:44:54 +01:00
void RigidBody : : ApplyLinearImpulseAcceleration ( const Float3 & worldA )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-11-20 11:44:54 +01:00
this - > impulseForceSum + = Formula : : ImpulseForce ( this - > mass , worldA ) ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:44:54 +01:00
void RigidBody : : ApplyLinearImpulseAccelerationAt ( const Float3 & worldA , const Float3 & worldPos )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
Float3 worldOffset = worldPos - this - > box . center . xyz ;
2013-11-20 11:44:54 +01:00
if ( worldOffset ! = Float3 : : null )
2013-11-12 12:33:52 +01:00
{
2013-11-20 11:44:54 +01:00
this - > impulseForceSum + = Formula : : ImpulseForce ( this - > mass , VectorProjection ( worldA , worldOffset ) ) ;
2013-11-12 12:33:52 +01:00
// tanAcc = angularAcc x localPosition
// angularAcc = localPosition x tanAcc = localPosition x linearAcc
// T = I * angularAcc
2013-11-20 11:44:54 +01:00
this - > impulseTorqueSum + = Formula : : ImpulseTorque ( this - > momentOfInertiaTensor , Formula : : AngularImpulseAcceleration ( worldA , worldOffset ) ) ;
2013-11-12 12:33:52 +01:00
}
else
{
2013-11-20 11:44:54 +01:00
this - > impulseForceSum + = Formula : : ImpulseForce ( this - > mass , worldA ) ;
2013-11-12 12:33:52 +01:00
}
}
2013-11-20 11:44:54 +01:00
void RigidBody : : ApplyImpulseTorque ( const Float3 & worldT )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-11-20 11:44:54 +01:00
this - > impulseTorqueSum + = worldT ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:44:54 +01:00
void RigidBody : : ApplyAngularImpulseAcceleration ( const Float3 & worldA )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-11-20 11:44:54 +01:00
this - > impulseTorqueSum + = Formula : : ImpulseTorque ( this - > momentOfInertiaTensor , worldA ) ;
2013-11-12 12:33:52 +01:00
}
Float3 & RigidBody : : AccessBoundingReach ( )
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
return this - > box . boundingOffset . xyz ;
2013-11-12 12:33:52 +01:00
}
const Float3 & RigidBody : : AccessBoundingReach ( ) const
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
return this - > box . boundingOffset . xyz ;
2013-11-12 12:33:52 +01:00
}
Float3 & RigidBody : : AccessCenter ( )
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
return this - > box . center . xyz ;
2013-11-12 12:33:52 +01:00
}
const Float3 & RigidBody : : AccessCenter ( ) const
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
return this - > box . center . xyz ;
2013-11-12 12:33:52 +01:00
}
const Float4x4 & RigidBody : : GetMomentOfInertia ( ) const
{ // by Dan Andersson
return this - > momentOfInertiaTensor ;
}
const Float & RigidBody : : GetMass ( ) const
{ // by Dan Andersson
return this - > mass ;
}
2013-11-20 17:40:12 +01:00
const Float4x4 RigidBody : : GetOrientation ( ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
return OrientationMatrix ( this - > box . rotation , this - > box . center . xyz ) ;
2013-11-12 12:33:52 +01:00
}
Float4x4 RigidBody : : GetView ( ) const
{ // by Dan Andersson
2013-11-20 17:40:12 +01:00
return InverseOrientationMatrix ( this - > GetOrientation ( ) ) ;
2013-11-12 12:33:52 +01:00
}
const Float3 & RigidBody : : GetBoundingReach ( ) const
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
return this - > box . boundingOffset . xyz ;
2013-11-12 12:33:52 +01:00
}
Float3 RigidBody : : GetSize ( ) const
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
return 2.0f * this - > box . boundingOffset . xyz ;
2013-11-12 12:33:52 +01:00
}
const Float3 & RigidBody : : GetCenter ( ) const
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
return this - > box . center . xyz ;
2013-11-12 12:33:52 +01:00
}
const Float3 & RigidBody : : GetImpulsTorque ( ) const
{ // by Dan Andersson
return this - > impulseTorqueSum ;
}
const Float3 & RigidBody : : GetAngularMomentum ( ) const
{ // by Dan Andersson
return this - > angularMomentum ;
}
Float3 RigidBody : : GetAngularImpulseAcceleration ( ) const
{ // by Dan Andersson
return Formula : : AngularImpulseAcceleration ( this - > momentOfInertiaTensor . GetInverse ( ) , this - > impulseTorqueSum ) ;
}
Float3 RigidBody : : GetAngularVelocity ( ) const
{ // by Dan Andersson
return Formula : : AngularVelocity ( this - > momentOfInertiaTensor . GetInverse ( ) , this - > angularMomentum ) ;
}
const Float3 & RigidBody : : GetImpulseForce ( ) const
{ // by Dan Andersson
return this - > impulseForceSum ;
}
const Float3 & RigidBody : : GetLinearMomentum ( ) const
{ // by Dan Andersson
return this - > linearMomentum ;
}
Float3 RigidBody : : GetLinearImpulseAcceleration ( ) const
{ // by Dan Andersson
return Formula : : LinearImpulseAcceleration ( this - > mass , this - > impulseForceSum ) ;
}
Float3 RigidBody : : GetLinearVelocity ( ) const
{ // by Dan Andersson
return Formula : : LinearVelocity ( this - > mass , this - > linearMomentum ) ;
}
2013-11-21 11:39:11 +01:00
void RigidBody : : GetMomentumAt ( const Float3 & worldPos , const Float3 & surfaceNormal , Float3 & normalMomentum , Float3 & tangentialMomentum ) const
2013-11-21 17:22:13 +01:00
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
Float3 worldOffset = worldPos - this - > box . center . xyz ;
2013-11-21 11:39:11 +01:00
Float3 momentum = Formula : : TangentialLinearMomentum ( this - > angularMomentum , worldOffset ) ;
momentum + = this - > linearMomentum ;
2013-11-12 12:33:52 +01:00
2013-11-21 11:39:11 +01:00
normalMomentum = NormalProjection ( momentum , surfaceNormal ) ;
tangentialMomentum = momentum - normalMomentum ;
2013-11-12 12:33:52 +01:00
}
2013-11-21 17:22:13 +01:00
void RigidBody : : SetMomentOfInertia_KeepVelocity ( const : : Oyster : : Math : : Float4x4 & localI )
{ // by Dan Andersson
if ( localI . GetDeterminant ( ) ! = 0.0f ) // insanitycheck! momentOfInertiaTensor must be invertable
{
Float3 w = Formula : : AngularVelocity ( ( this - > box . rotation * this - > momentOfInertiaTensor ) . GetInverse ( ) ,
this - > angularMomentum ) ;
this - > momentOfInertiaTensor = localI ;
this - > angularMomentum = Formula : : AngularMomentum ( this - > box . rotation * localI , w ) ;
}
}
void RigidBody : : SetMomentOfInertia_KeepMomentum ( const Float4x4 & localI )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
if ( localI . GetDeterminant ( ) ! = 0.0f ) // insanitycheck! momentOfInertiaTensor must be invertable
2013-11-18 14:01:23 +01:00
{
2013-11-21 11:39:11 +01:00
this - > momentOfInertiaTensor = localI ;
2013-11-18 14:01:23 +01:00
}
2013-11-12 12:33:52 +01:00
}
void RigidBody : : SetMass_KeepVelocity ( const Float & m )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
if ( m ! = 0.0f ) // insanitycheck! mass must be invertable
{
2013-11-21 17:22:13 +01:00
Float3 v = Formula : : LinearVelocity ( this - > mass , this - > linearMomentum ) ;
2013-11-18 14:01:23 +01:00
this - > mass = m ;
2013-11-21 17:22:13 +01:00
this - > linearMomentum = Formula : : LinearMomentum ( this - > mass , v ) ;
2013-11-18 14:01:23 +01:00
}
2013-11-12 12:33:52 +01:00
}
void RigidBody : : SetMass_KeepMomentum ( const Float & m )
2013-11-18 14:01:23 +01:00
{ // by Dan Anderson
if ( m ! = 0.0f ) // insanitycheck! mass must be invertable
{
this - > mass = m ;
}
2013-11-12 12:33:52 +01:00
}
void RigidBody : : SetOrientation ( const Float4x4 & o )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
ExtractRotationMatrix ( o , this - > box . rotation ) ;
this - > box . center = o . v [ 3 ] . xyz ;
2013-11-12 12:33:52 +01:00
}
void RigidBody : : SetSize ( const Float3 & widthHeight )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
this - > box . boundingOffset = 0.5f * widthHeight ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetCenter ( const Float3 & worldPos )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:47:20 +01:00
this - > box . center = worldPos ;
2013-11-12 12:33:52 +01:00
}
2013-11-25 16:35:56 +01:00
void RigidBody : : SetRotation ( const Float4x4 & r )
{ // by Dan Andersson
this - > box . rotation = r ;
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetImpulseTorque ( const Float3 & worldT )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
this - > impulseTorqueSum = worldT ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetAngularMomentum ( const Float3 & worldH )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
this - > angularMomentum = worldH ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetAngularImpulseAcceleration ( const Float3 & worldA )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
this - > impulseTorqueSum = Formula : : ImpulseTorque ( this - > momentOfInertiaTensor , worldA ) ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetAngularVelocity ( const Float3 & worldW )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
this - > angularMomentum = Formula : : AngularMomentum ( this - > momentOfInertiaTensor , worldW ) ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetImpulseForce ( const Float3 & worldF )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
this - > impulseForceSum = worldF ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetLinearMomentum ( const Float3 & worldG )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
this - > linearMomentum = worldG ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetLinearImpulseAcceleration ( const Float3 & worldA )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
this - > impulseForceSum = Formula : : ImpulseForce ( this - > mass , worldA ) ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetLinearVelocity ( const Float3 & worldV )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-11-21 11:39:11 +01:00
this - > linearMomentum = Formula : : LinearMomentum ( this - > mass , worldV ) ;
2013-11-12 12:33:52 +01:00
}
2013-11-21 11:39:11 +01:00
void RigidBody : : SetImpulseForceAt ( const Float3 & worldForce , const Float3 & worldPos )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
Float3 worldOffset = worldPos - this - > box . center . xyz ;
2013-11-21 11:39:11 +01:00
this - > impulseForceSum = VectorProjection ( worldForce , worldOffset ) ;
this - > impulseTorqueSum = Formula : : ImpulseTorque ( worldForce , worldOffset ) ;
2013-11-12 12:33:52 +01:00
}
2013-11-20 11:48:39 +01:00
void RigidBody : : SetLinearMomentumAt ( const Float3 & worldG , const Float3 & worldPos )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
Float3 worldOffset = worldPos - this - > box . center . xyz ;
2013-11-21 11:39:11 +01:00
this - > linearMomentum = VectorProjection ( worldG , worldOffset ) ;
this - > angularMomentum = Formula : : AngularMomentum ( worldG , worldOffset ) ;
2013-11-12 12:33:52 +01:00
}
2013-11-21 11:39:11 +01:00
void RigidBody : : SetImpulseAccelerationAt ( const Float3 & worldA , const Float3 & worldPos )
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
Float3 worldOffset = worldPos - this - > box . center . xyz ;
2013-11-21 11:39:11 +01:00
this - > impulseForceSum = Formula : : ImpulseForce ( this - > mass , VectorProjection ( worldA , worldOffset ) ) ;
this - > impulseTorqueSum = Formula : : ImpulseTorque ( this - > box . rotation * this - > momentOfInertiaTensor ,
Formula : : AngularImpulseAcceleration ( worldA , worldOffset ) ) ;
2013-11-12 12:33:52 +01:00
}
2013-11-21 11:39:11 +01:00
void RigidBody : : SetLinearVelocityAt ( const Float3 & worldV , const Float3 & worldPos )
{ // by Dan Andersson
2013-12-18 08:57:27 +01:00
Float3 worldOffset = worldPos - this - > box . center . xyz ;
2013-11-21 11:39:11 +01:00
this - > linearMomentum = Formula : : LinearMomentum ( this - > mass , VectorProjection ( worldV , worldOffset ) ) ;
this - > angularMomentum = Formula : : AngularMomentum ( this - > box . rotation * this - > momentOfInertiaTensor ,
Formula : : AngularVelocity ( worldV , worldOffset ) ) ;
2013-11-12 12:33:52 +01:00
}