203 lines
5.3 KiB
C++
203 lines
5.3 KiB
C++
// Controller.cpp: implementation of the utilities declared with the
|
|
// IController interface
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "CryBone.h"
|
|
#include "CryModEffector.h"
|
|
#include "CryModEffIKSolver.h"
|
|
#include "CryModelState.h"
|
|
#include "Controller.h"
|
|
#include "ControllerManager.h"
|
|
#include "CryKeyInterpolation.h"
|
|
#include "MathUtils.h"
|
|
|
|
// returns the rotation quaternion
|
|
CryQuat IController::PQLog::getOrientation()const
|
|
{
|
|
return exp( quaternionf(0,vRotLog) );
|
|
}
|
|
|
|
// resets the state to zero
|
|
void IController::PQLog::reset ()
|
|
{
|
|
vPos(0,0,0);
|
|
vRotLog(0,0,0);
|
|
}
|
|
|
|
// blends the pqSource[0] and pqSource[1] with weights 1-fBlend and fBlend into pqResult
|
|
void IController::PQLog::blendPQ (const PQLog* pqSource, float fBlend)
|
|
{
|
|
blendPQ (pqSource[0], pqSource[1], fBlend);
|
|
}
|
|
|
|
// returns the equivalent rotation in logarithmic space (the quaternion of which is negative the original)
|
|
Vec3 IController::PQLog::getComplementaryRotLog() const
|
|
{
|
|
// assuming |vRotLog| < gPi
|
|
Vec3 vResult = vRotLog * float(1 - gPi/vRotLog.Length());
|
|
#ifdef _DEBUG
|
|
//CryQuat qOrig = exp(vRotLog);
|
|
//CryQuat qNew = exp(vResult);
|
|
//assert (qOrig.Dot(qNew) < -0.99);
|
|
#endif
|
|
return vResult;
|
|
}
|
|
|
|
// blends the pqFrom and pqTo with weights 1-fBlend and fBlend into pqResult
|
|
void IController::PQLog::blendPQ (const PQLog& pqFrom, const PQLog& pqTo, float fBlend)
|
|
{
|
|
assert (fBlend >= 0 && fBlend <=1);
|
|
vPos = pqFrom.vPos * (1-fBlend) + pqTo.vPos * fBlend;
|
|
vRotLog = pqFrom.vRotLog * (1-fBlend) + pqTo.vRotLog * fBlend;
|
|
}
|
|
|
|
// builds the matrix out of the position and orientation stored in this PQLog
|
|
void IController::PQLog::buildMatrix(Matrix44& matDest)const
|
|
{
|
|
CryQuat qRot;
|
|
quaternionExponentOptimized(vRotLog, qRot);
|
|
//BuildMatrixFromQP(matDest, qRot, vPos);
|
|
matDest=Matrix44(qRot);
|
|
matDest.SetTranslationOLD(vPos);
|
|
}
|
|
|
|
void IController::PQLog::assignFromMatrix (const Matrix44& mat)
|
|
{
|
|
this->vPos = mat.GetTranslationOLD();
|
|
|
|
Matrix33 m(mat);
|
|
m.SetRow (0, mat.GetRow(0).normalized());
|
|
m.SetRow (1, mat.GetRow(1).normalized());
|
|
m.SetRow (2, mat.GetRow(2).normalized());
|
|
|
|
// check for parity
|
|
if ((m.GetRow(0)^m.GetRow(1))*m.GetRow(2) < 0)
|
|
m.SetRow (2, -m.GetRow(2));
|
|
|
|
this->vRotLog = log(CryQuat(m)).v;
|
|
|
|
#ifdef _DEBUG
|
|
Matrix44 t;
|
|
buildMatrix(t);
|
|
for (int i = 0; i < 3; ++i)
|
|
for (int j = 0; j < 3; ++j)
|
|
assert (fabs(m(i,j)-t(i,j)) < 0.5);
|
|
#endif
|
|
}
|
|
|
|
// a special version of the buildMatrix that adds a rotation to the rotation of this PQLog
|
|
void IController::PQLog::buildMatrixPlusRot(Matrix44& matDest, const CryQuat& qRotPlus)const
|
|
{
|
|
CryQuat qRot;
|
|
quaternionExponentOptimized(vRotLog, qRot);
|
|
//BuildMatrixFromQP(matDest, qRot*qRotPlus, vPos);
|
|
matDest=Matrix44(qRot*qRotPlus); matDest.SetTranslationOLD(vPos);
|
|
}
|
|
|
|
Vec3& operator *= (Vec3& v, double d)
|
|
{
|
|
v.x = float(v.x*d);
|
|
v.y = float(v.y*d);
|
|
v.z = float(v.z*d);
|
|
return v;
|
|
}
|
|
|
|
// adjusts the rotation of these PQs: if necessary, flips them or one of them (effectively NOT changing the whole rotation,but
|
|
// changing the rotation angle to Pi-X and flipping the rotation axis simultaneously)
|
|
// this is needed for blending between animations represented by quaternions rotated by ~PI in quaternion space
|
|
// (and thus ~2*PI in real space)
|
|
void AdjustLogRotations (Vec3& vRotLog1, Vec3& vRotLog2)
|
|
{
|
|
double dLen1 = DLength(vRotLog1);
|
|
if (dLen1 > gPi/2)
|
|
{
|
|
vRotLog1 *= 1 - gPi/dLen1;
|
|
// now the length of the first vector is actually gPi - dLen1,
|
|
// and it's closer to the origin than its complementary
|
|
|
|
// but we won't need the dLen1 any more
|
|
}
|
|
|
|
double dLen2 = DLength(vRotLog2);
|
|
// if the flipped 2nd rotation vector is closer to the first rotation vector,
|
|
// then flip the second vector
|
|
if (vRotLog1 * vRotLog2 < (dLen2 - gPi/2) * dLen2)
|
|
{
|
|
// flip the second rotation also
|
|
vRotLog2 *= 1 - gPi / dLen2;
|
|
}
|
|
}
|
|
|
|
void AdjustLogRotationTo (const Vec3& vRotLog1, Vec3& vRotLog2)
|
|
{
|
|
double dLen2 = DLength(vRotLog2);
|
|
|
|
if (dLen2 > gPi/2)
|
|
{
|
|
if (dLen2 > gPi)
|
|
{
|
|
double dReminder = fmod (dLen2, gPi);
|
|
if (dReminder <= gPi/2)
|
|
{
|
|
// we don't need to flip the axis
|
|
vRotLog2 *= dReminder / dLen2;
|
|
dLen2 = dReminder;
|
|
}
|
|
else
|
|
{
|
|
// we need to flip the axis
|
|
vRotLog2 *= (dReminder - gPi)/dLen2;
|
|
dLen2 = fabs(dReminder - gPi);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vRotLog2 *= 1 - gPi/dLen2; // (dLen2-gPi)/dLen2
|
|
dLen2 = fabs(dLen2 - gPi);
|
|
}
|
|
// now the length of the first vector is actually gPi - dLen1,
|
|
// and it's closer to the origin than its complementary
|
|
|
|
// but we won't need the dLen1 any more
|
|
}
|
|
|
|
// if the flipped 2nd rotation vector is closer to the first rotation vector,
|
|
// then flip the second vector
|
|
if (vRotLog1 * vRotLog2 < (dLen2 - gPi/2) * dLen2)
|
|
{
|
|
// flip the second rotation also
|
|
vRotLog2 *= 1 - gPi / dLen2;
|
|
}
|
|
}
|
|
|
|
|
|
void AdjustLogRotation(Vec3& vRotLog)
|
|
{
|
|
double dLen = DLength(vRotLog);
|
|
if (dLen > gPi/2)
|
|
{
|
|
if (dLen > gPi)
|
|
{
|
|
double dReminder = fmod (dLen, gPi);
|
|
if (dReminder <= gPi/2)
|
|
{
|
|
// we don't need to flip the axis
|
|
vRotLog *= dReminder / dLen;
|
|
}
|
|
else
|
|
{
|
|
// we need to flip the axis
|
|
vRotLog *= (dReminder - gPi)/dLen;
|
|
}
|
|
}
|
|
else
|
|
vRotLog *= 1 - gPi/dLen; // (dLen-gPi)/dLen
|
|
// now the length of the first vector is actually gPi - dLen1,
|
|
// and it's closer to the origin than its complementary
|
|
|
|
// but we won't need the dLen1 any more
|
|
}
|
|
|
|
} |