Files
FC1/CryAnimation/Controller.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

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
}
}