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-12-20 10:55:04 +01:00
using namespace : : Utility : : Value ;
2013-11-12 12:33:52 +01:00
2013-12-19 21:39:20 +01:00
RigidBody : : RigidBody ( )
{ // by Dan Andersson
this - > centerPos = Float4 : : standard_unit_w ;
this - > axis = Float4 : : null ;
this - > boundingReach = Float4 ( 0.5f , 0.5f , 0.5f , 0.0f ) ;
this - > momentum_Linear = Float4 : : null ;
this - > momentum_Angular = Float4 : : null ;
this - > impulse_Linear = Float4 : : null ;
this - > impulse_Angular = Float4 : : null ;
2013-12-18 14:16:13 +01:00
this - > restitutionCoeff = 1.0f ;
2013-12-19 21:39:20 +01:00
this - > frictionCoeff_Static = 0.5f ;
2013-12-19 10:03:56 +01:00
this - > frictionCoeff_Kinetic = 1.0f ;
2013-12-19 21:39:20 +01:00
this - > mass = 10 ;
this - > momentOfInertiaTensor = Float4x4 : : identity ;
this - > rotation = Quaternion : : identity ;
2013-11-12 12:33:52 +01:00
}
RigidBody & RigidBody : : operator = ( const RigidBody & body )
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
this - > centerPos = body . centerPos ;
this - > axis = body . axis ;
this - > boundingReach = body . boundingReach ;
this - > momentum_Linear = body . momentum_Linear ;
this - > momentum_Angular = body . momentum_Angular ;
this - > impulse_Linear = body . impulse_Linear ;
this - > impulse_Angular = body . impulse_Angular ;
2013-12-18 14:16:13 +01:00
this - > restitutionCoeff = body . restitutionCoeff ;
2013-12-19 10:03:56 +01:00
this - > frictionCoeff_Static = body . frictionCoeff_Static ;
this - > frictionCoeff_Kinetic = body . frictionCoeff_Kinetic ;
2013-11-12 12:33:52 +01:00
this - > mass = body . mass ;
this - > momentOfInertiaTensor = body . momentOfInertiaTensor ;
2013-12-19 21:39:20 +01:00
this - > rotation = body . rotation ;
2013-11-12 12:33:52 +01:00
return * this ;
}
2013-12-19 21:39:20 +01:00
void RigidBody : : Update_LeapFrog ( Float updateFrameLength )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson: Euler leap frog update when Runga Kutta is not needed
// updating the linear
2013-11-21 11:39:11 +01:00
// ds = dt * Formula::LinearVelocity( m, avg_G ) = dt * avg_G / m = (dt / m) * avg_G
2013-12-20 10:55:04 +01:00
this - > centerPos + = ( updateFrameLength / this - > mass ) * AverageWithDelta ( this - > momentum_Linear , this - > impulse_Linear ) ;
2013-11-12 12:33:52 +01:00
// updating the angular
2013-12-19 21:39:20 +01:00
Float4x4 rotationMatrix ; : : Oyster : : Math3D : : RotationMatrix ( this - > rotation , rotationMatrix ) ;
// 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.
Float4x4 wMomentOfInertiaTensor = TransformMatrix ( rotationMatrix , this - > momentOfInertiaTensor ) ; // RI
2013-11-12 12:33:52 +01:00
2013-12-19 21:39:20 +01:00
// dO = dt * Formula::AngularVelocity( (RI)^-1, avg_H ) = dt * (RI)^-1 * avg_H
2013-12-20 10:55:04 +01:00
this - > axis + = Formula : : AngularVelocity ( wMomentOfInertiaTensor . GetInverse ( ) , AverageWithDelta ( this - > momentum_Angular , this - > impulse_Angular ) ) ;
2013-12-19 21:39:20 +01:00
this - > rotation = Rotation ( this - > axis ) ;
2013-11-12 12:33:52 +01:00
2013-12-19 21:39:20 +01:00
// update momentums and clear impulse_Linear and impulse_Angular
this - > momentum_Linear + = this - > impulse_Linear ;
this - > impulse_Linear = Float4 : : null ;
this - > momentum_Angular + = this - > impulse_Angular ;
this - > impulse_Angular = Float4 : : null ;
2013-11-12 12:33:52 +01:00
}
2013-12-20 10:55:04 +01:00
void RigidBody : : Predict_LeapFrog ( Float4 & outDeltaPos , Float4 & outDeltaAxis , const Float4 & actingLinearImpulse , const Float4 & actingAngularImpulse , Float deltaTime )
{
// updating the linear
// ds = dt * Formula::LinearVelocity( m, avg_G ) = dt * avg_G / m = (dt / m) * avg_G
outDeltaPos = ( deltaTime / this - > mass ) * AverageWithDelta ( this - > momentum_Linear , actingLinearImpulse ) ;
// updating the angular
Float4x4 rotationMatrix ; : : Oyster : : Math3D : : RotationMatrix ( this - > rotation , rotationMatrix ) ;
Float4x4 wMomentOfInertiaTensor = TransformMatrix ( rotationMatrix , this - > momentOfInertiaTensor ) ; // RI
// dO = dt * Formula::AngularVelocity( (RI)^-1, avg_H ) = dt * (RI)^-1 * avg_H
outDeltaAxis = Formula : : AngularVelocity ( wMomentOfInertiaTensor . GetInverse ( ) , AverageWithDelta ( this - > momentum_Angular , actingAngularImpulse ) ) ;
}
2013-12-19 21:39:20 +01:00
void RigidBody : : ApplyImpulse ( const Float4 & worldJ , const Float4 & atWorldPos )
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
Float4 worldOffset = atWorldPos - this - > centerPos ;
if ( worldOffset ! = Float4 : : null )
2013-11-12 12:33:52 +01:00
{
2013-12-19 21:39:20 +01:00
this - > impulse_Linear + = VectorProjection ( worldJ , atWorldPos ) ;
this - > impulse_Angular + = Formula : : ImpulseTorque ( worldJ , atWorldPos ) ;
2013-11-12 12:33:52 +01:00
}
else
{
2013-12-19 21:39:20 +01:00
this - > impulse_Linear + = worldJ ;
2013-11-12 12:33:52 +01:00
}
}
const Float4x4 & RigidBody : : GetMomentOfInertia ( ) const
{ // by Dan Andersson
return this - > momentOfInertiaTensor ;
}
2013-12-19 21:39:20 +01:00
Float RigidBody : : GetMass ( ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
return this - > mass ;
}
2013-12-19 21:39:20 +01:00
const Quaternion & RigidBody : : GetRotation ( ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
return this - > rotation ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
Float4x4 RigidBody : : GetRotationMatrix ( ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
return RotationMatrix ( this - > rotation ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
Float4x4 RigidBody : : GetOrientation ( ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
return : : Oyster : : Math3D : : OrientationMatrix ( this - > rotation , this - > centerPos ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
Float4x4 RigidBody : : GetView ( ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
return ViewMatrix ( this - > rotation , this - > centerPos ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
Float4 RigidBody : : GetVelocity_Linear ( ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
return Formula : : LinearVelocity ( this - > mass , this - > momentum_Linear ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
Float4 RigidBody : : GetVelocity_Angular ( ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
return Formula : : AngularVelocity ( this - > momentOfInertiaTensor . GetInverse ( ) , this - > momentum_Angular ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
Float4 RigidBody : : GetLinearMomentum ( const Float4 & atWorldPos ) const
2013-11-12 12:33:52 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
return this - > momentum_Linear + Formula : : TangentialLinearMomentum ( this - > momentum_Angular , atWorldPos - this - > centerPos ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
void RigidBody : : SetMomentOfInertia_KeepVelocity ( const Float4x4 & localTensorI )
2013-11-21 17:22:13 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
if ( localTensorI . GetDeterminant ( ) ! = 0.0f )
{ // insanity check! MomentOfInertiaTensor must be invertable
Float4x4 rotationMatrix ; RotationMatrix ( this - > rotation , rotationMatrix ) ;
2013-11-12 12:33:52 +01:00
2013-12-19 21:39:20 +01:00
Float4 w = Formula : : AngularVelocity ( ( rotationMatrix * this - > momentOfInertiaTensor ) . GetInverse ( ) , this - > momentum_Angular ) ;
this - > momentOfInertiaTensor = localTensorI ;
this - > momentum_Angular = Formula : : AngularMomentum ( rotationMatrix * localTensorI , w ) ;
2013-11-21 17:22:13 +01:00
}
}
2013-12-19 21:39:20 +01:00
void RigidBody : : SetMomentOfInertia_KeepMomentum ( const Float4x4 & localTensorI )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
if ( localTensorI . GetDeterminant ( ) ! = 0.0f )
{ // insanity check! MomentOfInertiaTensor must be invertable
this - > momentOfInertiaTensor = localTensorI ;
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
2013-12-19 21:39:20 +01:00
if ( m ! = 0.0f )
{ // insanity check! Mass must be invertable
Float4 v = Formula : : LinearVelocity ( this - > mass , this - > momentum_Linear ) ;
2013-11-18 14:01:23 +01:00
this - > mass = m ;
2013-12-19 21:39:20 +01:00
this - > momentum_Linear = 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
2013-12-19 21:39:20 +01:00
if ( m ! = 0.0f )
{ // insanity check! Mass must be invertable
2013-11-18 14:01:23 +01:00
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-12-19 21:39:20 +01:00
this - > axis = ExtractAngularAxis ( o ) ;
this - > rotation = Rotation ( this - > axis ) ;
this - > centerPos = o . v [ 3 ] . xyz ;
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
2013-12-19 21:39:20 +01:00
this - > axis = ExtractAngularAxis ( r ) ;
this - > rotation = Rotation ( this - > axis ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
void RigidBody : : SetMomentum_Linear ( const Float4 & worldG , const Float4 & atWorldPos )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
Float4 worldOffset = atWorldPos - this - > centerPos ;
this - > momentum_Linear = VectorProjection ( worldG , worldOffset ) ;
this - > momentum_Angular = Formula : : AngularMomentum ( worldG , worldOffset ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
void RigidBody : : SetVelocity_Linear ( const Float4 & worldV )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
this - > momentum_Linear = Formula : : LinearMomentum ( this - > mass , worldV ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
void RigidBody : : SetVelocity_Linear ( const Float4 & worldV , const Float4 & atWorldPos )
2013-11-18 14:01:23 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
Float4 worldOffset = atWorldPos - this - > centerPos ;
this - > momentum_Linear = Formula : : LinearMomentum ( this - > mass , VectorProjection ( worldV , worldOffset ) ) ;
this - > momentum_Angular = Formula : : AngularMomentum ( RotationMatrix ( this - > rotation ) * this - > momentOfInertiaTensor , Formula : : AngularVelocity ( worldV , worldOffset ) ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
void RigidBody : : SetVelocity_Angular ( const Float4 & worldW )
2013-11-21 11:39:11 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
this - > momentum_Angular = Formula : : AngularMomentum ( this - > momentOfInertiaTensor , worldW ) ;
2013-11-12 12:33:52 +01:00
}
2013-12-19 21:39:20 +01:00
void RigidBody : : SetImpulse_Linear ( const Float4 & worldJ , const Float4 & atWorldPos )
2013-11-21 11:39:11 +01:00
{ // by Dan Andersson
2013-12-19 21:39:20 +01:00
Float4 worldOffset = atWorldPos - this - > centerPos ;
this - > impulse_Linear = VectorProjection ( worldJ , worldOffset ) ;
this - > impulse_Angular = Formula : : ImpulseTorque ( worldJ , worldOffset ) ;
2013-11-12 12:33:52 +01:00
}