550 lines
16 KiB
C++
550 lines
16 KiB
C++
|
// Copyright (C) 2007 Id Software, Inc.
|
||
|
//
|
||
|
|
||
|
|
||
|
#include "../precompiled.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
#include "VehicleSuspension.h"
|
||
|
#include "Transport.h"
|
||
|
#include "TransportComponents.h"
|
||
|
|
||
|
sdVehicleSuspension::factoryType_t sdVehicleSuspension::suspensionFactory;
|
||
|
|
||
|
// These should be tweaked so stationary vehicles don't cause any reskinning
|
||
|
// These are in degrees and world units
|
||
|
#define SUSPENSION_PIVOT_ANGLE_THRESHOLD 0.5f
|
||
|
#define SUSPENSION_DOUBLEWISHBONE_ANGLE_THRESHOLD 0.5f
|
||
|
#define SUSPENSION_VERTICAL_OFFSET_THRESHOLD 0.25f
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleSuspension
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension::Startup
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleSuspension::Startup( void ) {
|
||
|
suspensionFactory.RegisterType( sdVehicleSuspension_Pivot::TypeName(), factoryType_t::Allocator< sdVehicleSuspension_Pivot > );
|
||
|
suspensionFactory.RegisterType( sdVehicleSuspension_DoubleWishbone::TypeName(), factoryType_t::Allocator< sdVehicleSuspension_DoubleWishbone > );
|
||
|
suspensionFactory.RegisterType( sdVehicleSuspension_Vertical::TypeName(), factoryType_t::Allocator< sdVehicleSuspension_Vertical > );
|
||
|
suspensionFactory.RegisterType( sdVehicleSuspension_2JointLeg::TypeName(), factoryType_t::Allocator< sdVehicleSuspension_2JointLeg > );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleView::Shutdown
|
||
|
================
|
||
|
*/
|
||
|
|
||
|
void sdVehicleSuspension::Shutdown( void ) {
|
||
|
suspensionFactory.Shutdown();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension::GetSuspension
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleSuspension* sdVehicleSuspension::GetSuspension( const char* name ) {
|
||
|
return suspensionFactory.CreateType( name );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleSuspension_Pivot
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Pivot::sdVehicleSuspension_Pivot
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleSuspension_Pivot::sdVehicleSuspension_Pivot( void ) {
|
||
|
_object = NULL;
|
||
|
_suspensionJoint = INVALID_JOINT;
|
||
|
_suspensionRadius = 0;
|
||
|
_suspensionAngle = 0;
|
||
|
_initialOffset = 0;
|
||
|
_lastOffset = 0;
|
||
|
_idealSuspensionAngle = 0;
|
||
|
_oldSuspensionAngle = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Pivot::~sdVehicleSuspension_Pivot
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleSuspension_Pivot::~sdVehicleSuspension_Pivot( void ) {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Pivot::Init
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_Pivot::Init( sdVehicleSuspensionInterface* object, const idDict& info ) {
|
||
|
idVec3 wheelOrg, suspensionOrg;
|
||
|
|
||
|
_object = object;
|
||
|
|
||
|
sdTransport* transport = _object->GetParent();
|
||
|
idAnimator* animator = transport->GetAnimator();
|
||
|
|
||
|
_suspensionJoint = animator->GetJointHandle( info.GetString( "joint" ) );
|
||
|
if ( _suspensionJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleSuspension_Pivot::Init Invalid Suspension Joint '%s'", info.GetString( "joint" ) );
|
||
|
}
|
||
|
|
||
|
transport->GetJointTransformForAnim( _suspensionJoint, 1, gameLocal.time, suspensionOrg, _suspensionAxis );
|
||
|
transport->GetJointTransformForAnim( _object->GetJoint(), 1, gameLocal.time, wheelOrg );
|
||
|
|
||
|
idVec3 dir = wheelOrg - suspensionOrg;
|
||
|
dir[ 1 ] = 0.f;
|
||
|
|
||
|
_suspensionRadius = dir.Normalize();
|
||
|
|
||
|
float v = -dir[ 2 ];
|
||
|
float h = dir[ 0 ];
|
||
|
|
||
|
_suspensionAngle = RAD2DEG( atan2( v, h ) );
|
||
|
_initialOffset = v * _suspensionRadius;
|
||
|
_lastOffset = -idMath::INFINITY;
|
||
|
|
||
|
_reverse = info.GetBool( "reverse" );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Pivot::ClearIKJoints
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleSuspension_Pivot::ClearIKJoints( idAnimator* animator ) {
|
||
|
animator->SetJointAxis( _suspensionJoint, JOINTMOD_NONE, mat3_identity );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Pivot::UpdateIKJoints
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_Pivot::UpdateIKJoints( idAnimator* animator ) {
|
||
|
float offset = _object->GetOffset();
|
||
|
if ( _lastOffset != -idMath::INFINITY ) {
|
||
|
if ( offset < _lastOffset ) {
|
||
|
offset = Lerp( _lastOffset, offset, 0.5f );
|
||
|
}
|
||
|
}
|
||
|
_lastOffset = offset;
|
||
|
|
||
|
float offsetAngle = RAD2DEG( asin( ( _initialOffset - offset ) / _suspensionRadius ) );
|
||
|
if ( !_reverse ) {
|
||
|
_idealSuspensionAngle = offsetAngle - _suspensionAngle;
|
||
|
} else {
|
||
|
_idealSuspensionAngle = -( offsetAngle - ( 180 - _suspensionAngle ) );
|
||
|
}
|
||
|
|
||
|
if ( fabs( _oldSuspensionAngle - _idealSuspensionAngle ) > SUSPENSION_PIVOT_ANGLE_THRESHOLD ) {
|
||
|
_oldSuspensionAngle = _idealSuspensionAngle;
|
||
|
|
||
|
idMat3 temp;
|
||
|
idAngles::PitchToMat3( _idealSuspensionAngle, temp );
|
||
|
|
||
|
animator->SetJointAxis( _suspensionJoint, JOINTMOD_WORLD_OVERRIDE, _suspensionAxis * temp );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleSuspension_DoubleWishbone
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_DoubleWishbone::sdVehicleSuspension_DoubleWishbone
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleSuspension_DoubleWishbone::sdVehicleSuspension_DoubleWishbone( void ) {
|
||
|
_object = NULL;
|
||
|
_upperSuspensionJoint = INVALID_JOINT;
|
||
|
_lowerSuspensionJoint = INVALID_JOINT;
|
||
|
_suspensionRadius = 0;
|
||
|
_suspensionAngle = 0;
|
||
|
_initialOffset = 0;
|
||
|
_lastOffset = 0;
|
||
|
_currentSuspensionAngle = 0;
|
||
|
_oldSuspensionAngle = 0;
|
||
|
_upperSuspensionAxes.Identity();
|
||
|
_lowerSuspensionAxes.Identity();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_DoubleWishbone::~sdVehicleSuspension_DoubleWishbone
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleSuspension_DoubleWishbone::~sdVehicleSuspension_DoubleWishbone( void ) {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_DoubleWishbone::Init
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_DoubleWishbone::Init( sdVehicleSuspensionInterface* object, const idDict& info ) {
|
||
|
idVec3 wheelOrg, suspensionOrg;
|
||
|
idMat3 suspensionAxes;
|
||
|
|
||
|
_object = object;
|
||
|
|
||
|
sdTransport* transport = _object->GetParent();
|
||
|
idAnimator* animator = transport->GetAnimator();
|
||
|
|
||
|
_upperSuspensionJoint = animator->GetJointHandle( info.GetString( "joint_upper" ) );
|
||
|
if ( _upperSuspensionJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleSuspension_DoubleWishbone::Init Invalid Suspension Joint '%s'", info.GetString( "joint_upper" ) );
|
||
|
}
|
||
|
_lowerSuspensionJoint = animator->GetJointHandle( info.GetString( "joint_lower" ) );
|
||
|
if ( _lowerSuspensionJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleSuspension_DoubleWishbone::Init Invalid Suspension Joint '%s'", info.GetString( "joint_lower" ) );
|
||
|
}
|
||
|
|
||
|
_lerpScale = info.GetFloat( "lerp_scale", "0.5" );
|
||
|
|
||
|
transport->GetJointTransformForAnim( _lowerSuspensionJoint, 1, gameLocal.time, _lowerSuspensionAxes );
|
||
|
transport->GetJointTransformForAnim( _upperSuspensionJoint, 1, gameLocal.time, _upperSuspensionAxes );
|
||
|
|
||
|
transport->GetJointTransformForAnim( _upperSuspensionJoint, 1, gameLocal.time, suspensionOrg );
|
||
|
transport->GetJointTransformForAnim( _object->GetJoint(), 1, gameLocal.time, wheelOrg );
|
||
|
|
||
|
_rightWheel = suspensionOrg[ 1 ] < wheelOrg[ 1 ];
|
||
|
|
||
|
idVec3 dir = wheelOrg - suspensionOrg;
|
||
|
dir[ 0 ] = 0.f;
|
||
|
|
||
|
_suspensionRadius = dir.Normalize();
|
||
|
|
||
|
_suspensionAngle = RAD2DEG( atan2( -dir[ 2 ], dir[ 1 ] ) );
|
||
|
_initialOffset = -dir[ 2 ] * _suspensionRadius;
|
||
|
_lastOffset = -idMath::INFINITY;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_DoubleWishbone::ClearIKJoints
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleSuspension_DoubleWishbone::ClearIKJoints( idAnimator* animator ) {
|
||
|
animator->SetJointAxis( _upperSuspensionJoint, JOINTMOD_NONE, mat3_identity );
|
||
|
animator->SetJointAxis( _lowerSuspensionJoint, JOINTMOD_NONE, mat3_identity );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_DoubleWishbone::UpdateIKJoints
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_DoubleWishbone::UpdateIKJoints( idAnimator* animator ) {
|
||
|
float offset = _object->GetOffset();
|
||
|
if ( _lastOffset != -idMath::INFINITY ) {
|
||
|
if ( offset < _lastOffset ) {
|
||
|
offset = Lerp( _lastOffset, offset, _lerpScale );
|
||
|
}
|
||
|
}
|
||
|
_lastOffset = offset;
|
||
|
|
||
|
float offsetAngle = RAD2DEG( asin( ( _initialOffset - offset ) / _suspensionRadius ) );
|
||
|
if ( _rightWheel ) {
|
||
|
_currentSuspensionAngle = offsetAngle;
|
||
|
} else {
|
||
|
_currentSuspensionAngle = 180 - offsetAngle;
|
||
|
}
|
||
|
_currentSuspensionAngle -= _suspensionAngle;
|
||
|
|
||
|
if ( fabs( _oldSuspensionAngle - _currentSuspensionAngle ) > SUSPENSION_DOUBLEWISHBONE_ANGLE_THRESHOLD ) {
|
||
|
_oldSuspensionAngle = _currentSuspensionAngle;
|
||
|
|
||
|
idMat3 temp;
|
||
|
idAngles::RollToMat3( -_currentSuspensionAngle, temp );
|
||
|
|
||
|
animator->SetJointAxis( _upperSuspensionJoint, JOINTMOD_WORLD_OVERRIDE, _upperSuspensionAxes * temp );
|
||
|
animator->SetJointAxis( _lowerSuspensionJoint, JOINTMOD_WORLD_OVERRIDE, _lowerSuspensionAxes * temp );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleSuspension_Vertical
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Vertical::sdVehicleSuspension_Vertical
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleSuspension_Vertical::sdVehicleSuspension_Vertical( void ) {
|
||
|
_oldOffset = 0.0f;
|
||
|
_offset = -idMath::INFINITY;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Vertical::~sdVehicleSuspension_Vertical
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleSuspension_Vertical::~sdVehicleSuspension_Vertical( void ) {
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Vertical::Init
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_Vertical::Init( sdVehicleSuspensionInterface* object, const idDict& info ) {
|
||
|
return Init( object, info.GetString( "joint" ) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Vertical::Init
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_Vertical::Init( sdVehicleSuspensionInterface* object, const char* jointName ) {
|
||
|
_object = object;
|
||
|
|
||
|
sdTransport* transport = _object->GetParent();
|
||
|
idAnimator* animator = transport->GetAnimator();
|
||
|
|
||
|
_suspensionJoint = animator->GetJointHandle( jointName );
|
||
|
if ( _suspensionJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleSuspension_Vertical::Init Invalid Suspension Joint '%s'", jointName );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Vertical::ClearIKJoints
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleSuspension_Vertical::ClearIKJoints( idAnimator* animator ) {
|
||
|
animator->SetJointPos( _suspensionJoint, JOINTMOD_NONE, vec3_origin );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_Vertical::UpdateIKJoints
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_Vertical::UpdateIKJoints( idAnimator* animator ) {
|
||
|
float offset = _object->GetOffset();
|
||
|
if ( _offset != -idMath::INFINITY && offset < _offset ) {
|
||
|
_offset = Lerp( _offset, offset, 0.3f );
|
||
|
} else {
|
||
|
_offset = offset;
|
||
|
}
|
||
|
|
||
|
if ( idMath::Fabs( _oldOffset - _offset ) < SUSPENSION_VERTICAL_OFFSET_THRESHOLD ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
animator->SetJointPos( _suspensionJoint, JOINTMOD_WORLD, idVec3( 0.f, 0.f, _offset ) );
|
||
|
_oldOffset = _offset;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
sdVehicleSuspension_2JointLeg
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_2JointLeg::sdVehicleSuspension_2JointLeg
|
||
|
================
|
||
|
*/
|
||
|
sdVehicleSuspension_2JointLeg::sdVehicleSuspension_2JointLeg( void ) {
|
||
|
_lastOffset = -idMath::INFINITY;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_2JointLeg::Init
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_2JointLeg::Init( sdVehicleSuspensionInterface* object, const idDict& info ) {
|
||
|
const char* jointName;
|
||
|
|
||
|
_object = object;
|
||
|
|
||
|
idAnimator* animator = object->GetParent()->GetAnimator();
|
||
|
|
||
|
jointHandle_t _ankleJoint = object->GetJoint();
|
||
|
if ( _ankleJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleSuspension_2JointLeg::Init: Invalid ankle joint" );
|
||
|
}
|
||
|
|
||
|
jointName = info.GetString( "joint_knee" );
|
||
|
_kneeJoint = animator->GetJointHandle( jointName );
|
||
|
if ( _kneeJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleSuspension_2JointLeg::Init: invalid knee joint '%s'", jointName );
|
||
|
}
|
||
|
|
||
|
jointName = info.GetString( "joint_hip" );
|
||
|
_hipJoint = animator->GetJointHandle( jointName );
|
||
|
if ( _hipJoint == INVALID_JOINT ) {
|
||
|
gameLocal.Error( "sdVehicleSuspension_2JointLeg::Init: invalid hip joint '%s'", jointName );
|
||
|
}
|
||
|
|
||
|
idVec3 ankleOrigin;
|
||
|
idMat3 ankleAxis;
|
||
|
animator->GetJointTransform( _ankleJoint, gameLocal.time, ankleOrigin, ankleAxis );
|
||
|
|
||
|
idVec3 kneeOrigin;
|
||
|
idMat3 kneeAxis;
|
||
|
animator->GetJointTransform( _kneeJoint, gameLocal.time, kneeOrigin, kneeAxis );
|
||
|
|
||
|
idVec3 hipOrigin;
|
||
|
idMat3 hipAxis;
|
||
|
animator->GetJointTransform( _hipJoint, gameLocal.time, hipOrigin, hipAxis );
|
||
|
|
||
|
animator->GetJointTransform( _object->GetJoint(), gameLocal.time, _offset );
|
||
|
|
||
|
idVec3 dir = info.GetVector( "dir_hip", "0 0 1" );
|
||
|
dir.Normalize();
|
||
|
|
||
|
_hipForward = dir * hipAxis.Transpose();
|
||
|
_kneeForward = dir * kneeAxis.Transpose();
|
||
|
|
||
|
idMat3 axis;
|
||
|
|
||
|
// conversion from upper leg bone axis to hip joint axis
|
||
|
_upperLegLength = idIK::GetBoneAxis( hipOrigin, kneeOrigin, dir, axis );
|
||
|
_upperLegToHipJoint = hipAxis * axis.Transpose();
|
||
|
|
||
|
// conversion from lower leg bone axis to knee joint axis
|
||
|
_lowerLegLength = idIK::GetBoneAxis( kneeOrigin, ankleOrigin, dir, axis );
|
||
|
_lowerLegToKneeJoint = kneeAxis * axis.Transpose();
|
||
|
|
||
|
_lerpScale = info.GetFloat( "lerp_scale", "0.3" );
|
||
|
_reverse = info.GetBool( "reverse", "0" );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_2JointLeg::UpdateIKJoints
|
||
|
================
|
||
|
*/
|
||
|
bool sdVehicleSuspension_2JointLeg::UpdateIKJoints( idAnimator* animator ) {
|
||
|
float offset = _object->GetOffset();
|
||
|
if ( _lastOffset != idMath::INFINITY ) {
|
||
|
if ( offset < _lastOffset ) {
|
||
|
offset = Lerp( _lastOffset, offset, _lerpScale );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( idMath::Fabs( _lastOffset - offset ) < 0.1f ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
_lastOffset = offset;
|
||
|
|
||
|
idMat3 axis;
|
||
|
|
||
|
const idVec3& modelOrigin = _object->GetParent()->GetRenderEntity()->origin;
|
||
|
const idMat3& modelAxis = _object->GetParent()->GetRenderEntity()->axis;
|
||
|
|
||
|
idVec3 newOffset = _offset;
|
||
|
if ( !_reverse ) {
|
||
|
newOffset[ 2 ] -= _lastOffset;
|
||
|
} else {
|
||
|
newOffset[ 2 ] += _lastOffset;
|
||
|
}
|
||
|
|
||
|
idVec3 target = modelOrigin + ( newOffset * modelAxis );
|
||
|
|
||
|
// get the position of the hip in world space
|
||
|
idVec3 hipOrigin;
|
||
|
animator->GetJointTransform( _hipJoint, gameLocal.time, hipOrigin, axis );
|
||
|
hipOrigin = modelOrigin + hipOrigin * modelAxis;
|
||
|
idVec3 hipDir = _hipForward * axis * modelAxis;
|
||
|
|
||
|
// get the IK bend direction
|
||
|
idVec3 kneeOrigin;
|
||
|
animator->GetJointTransform( _kneeJoint, gameLocal.time, kneeOrigin, axis );
|
||
|
idVec3 kneeDir = _kneeForward * axis * modelAxis;
|
||
|
|
||
|
// solve IK and calculate knee position
|
||
|
idIK::SolveTwoBones( hipOrigin, target, kneeDir, _upperLegLength, _lowerLegLength, kneeOrigin );
|
||
|
|
||
|
// get the axis for the hip joint
|
||
|
idIK::GetBoneAxis( hipOrigin, kneeOrigin, hipDir, axis );
|
||
|
idMat3 hipAxis = _upperLegToHipJoint * ( axis * modelAxis.Transpose() );
|
||
|
|
||
|
// get the axis for the knee joint
|
||
|
idIK::GetBoneAxis( kneeOrigin, target, kneeDir, axis );
|
||
|
idMat3 kneeAxis = _lowerLegToKneeJoint * ( axis * modelAxis.Transpose() );
|
||
|
|
||
|
animator->SetJointAxis( _hipJoint, JOINTMOD_WORLD_OVERRIDE, hipAxis );
|
||
|
animator->SetJointAxis( _kneeJoint, JOINTMOD_WORLD_OVERRIDE, kneeAxis );
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
sdVehicleSuspension_2JointLeg::ClearIKJoints
|
||
|
================
|
||
|
*/
|
||
|
void sdVehicleSuspension_2JointLeg::ClearIKJoints( idAnimator* animator ) {
|
||
|
animator->SetJointAxis( _hipJoint, JOINTMOD_NONE, mat3_identity );
|
||
|
animator->SetJointAxis( _kneeJoint, JOINTMOD_NONE, mat3_identity );
|
||
|
}
|