📄 animout.cpp
字号:
//**************************************************************************
//* Animout.cpp - Virtools File Exporter
//*
//* Romain Sididris - Copyright (c) Virtools 2000
//*
//* (Based on Ascii File Exporter source code
//* By Christer Janson
//* Kinetix Development
//* Copyright (c) Kinetix 1997, All Rights Reserved. )
//*
//* This module handles controller key output and controller sampling.
//*
//***************************************************************************
#include "Precomp.h"
#include "Max2Nmo.h"
#define ALMOST_ZERO 1.0e-3f
BOOL EqualPoint3(Point3 p1, Point3 p2);
/****************************************************************************
Export animation keys for a node, if the node use known Max controllers
(Linear,Bezier,TCB) PRS scale controller, these controller are converted to Virtools
format, otherwise if the object is animated we sample the animation to create
key frame data.
****************************************************************************/
void Max2Nmo::ExportAnimKeys(INode* node,CK3dEntity *entity)
{
BOOL bDoKeys = FALSE;
BOOL bForceKey = FALSE;
Control* tmC = node->GetTMController();
Control* pC = tmC->GetPositionController();
Control* rC = tmC->GetRotationController();
Control* sC = tmC->GetScaleController();
// Force at least one key to be created on biped controlled objects... :(
Class_ID cid = tmC->ClassID();
// For a biped controlled object some objects
// may not be animed but they may need at least one key to have
// a correct position when warping between different animation
// If the controller has at least one key, we force the creation of the animation
if ((cid == BIPBODY_CONTROL_CLASS_ID) || (cid == BIPSLAVE_CONTROL_CLASS_ID) ||
(cid == FOOTPRINT_CLASS_ID)) {
bForceKey = TRUE;
}
if ((cid == Class_ID(PRS_CONTROL_CLASS_ID,0)) && IsKnownController(pC) && IsKnownController(rC) && IsKnownController(sC)) {
bDoKeys = TRUE;
}
CKObjectAnimation* anim = NULL;
if (bDoKeys) {
anim = VirtoolsExporter->AddObjectAnimation(entity,entity->GetName(),node);
DumpPosKeys(pC,anim);
DumpRotKeys(rC,anim);
DumpScaleKeys(sC,anim);
} else {
anim = VirtoolsExporter->AddObjectAnimation(entity,entity->GetName(),node);
DumpSampledAnim(node,anim);
}
//--- Check validity of every animation controller and report
if (anim) {
anim->SetLength(FrameTime(m_EndFrame));
int KeyLimitCount = bForceKey ? 1 : 2;
// Check rotation controller
CKAnimController* Rctrl = anim->GetRotationController();
if (Rctrl) {
if (Rctrl->GetKeyCount()<KeyLimitCount) {
anim->DeleteController(CKANIMATION_CONTROLLER_ROT);
Rctrl = NULL;
} else {
if (!anim->GetScaleController()) {
// We add a fake scale controller with only one key
// to preserve errors from coming from lose of precision
// when applying successive rotation without reseting the scale
VxVector Pos,Scale;
VxQuaternion Quat;
Vx3DDecomposeMatrix(entity->GetLocalMatrix(),Quat,Pos,Scale);
CKAnimController* Sctrl = anim->CreateController(CKANIMATION_LINSCL_CONTROL);
Sctrl->AddKey(&CKScaleKey(0,Scale));
}
}
}
// Check position controller
CKAnimController* Pctrl = anim->GetPositionController();
if (Pctrl && Pctrl->GetKeyCount()<KeyLimitCount) {
anim->DeleteController(CKANIMATION_CONTROLLER_POS);
Pctrl = NULL;
}
// Check scale controller
CKAnimController* Sctrl = anim->GetScaleController();
if (Sctrl && Sctrl->GetKeyCount()<KeyLimitCount) {
anim->DeleteController(CKANIMATION_CONTROLLER_SCL);
Sctrl = NULL;
}
// Check Off-Axis scale controller
CKAnimController* SActrl= anim->GetScaleAxisController();
if (SActrl && SActrl->GetKeyCount()<KeyLimitCount) {
anim->DeleteController(CKANIMATION_CONTROLLER_SCLAXIS);
SActrl = NULL;
}
// Report
if (Pctrl || Rctrl || Sctrl || SActrl) {
if (bDoKeys)
Report(REPORT_MLEVEL,"\r\nSaving standard animation...\r\n");
else
Report(REPORT_MLEVEL,"\r\nConverting unknown animation (Sampling)...\r\n");
Report(REPORT_LLEVEL,"Position: %d keys, Rotation: %d keys, Scale: %d keys\r\n",
Pctrl ? Pctrl->GetKeyCount() : 0,
Rctrl ? Rctrl->GetKeyCount() : 0,
Sctrl ? Sctrl->GetKeyCount() : 0);
if (SActrl && SActrl->GetKeyCount())
Report(REPORT_LLEVEL,"Warning : OffAxis Scale : %d keys\r\n",SActrl->GetKeyCount());
} else {
// every controller was deleted : remove the animation
// will be done by exporter...
}
}
}
/**************************************************************************************
To really see if a node is animated we can step through the animation range
and decompose the TM matrix for every frame and examine the components.
This way we can identify position, rotation and scale animation separately.
RS : Added support for off axis scale...
****************************************************************************************/
BOOL Max2Nmo::CheckForAnimation(INode* node, BOOL& bPos, BOOL& bRot, BOOL& bScale, BOOL& bScaleAxis)
{
TimeValue start = ip->GetAnimRange().Start();
TimeValue end = ip->GetAnimRange().End();
TimeValue t;
int delta = GetTicksPerFrame();
Matrix3 tm;
AffineParts ap;
Point3 firstPos;
float rotAngle, firstRotAngle;
Point3 rotAxis, firstRotAxis;
float scaleRotAngle, firstScaleRotAngle;
Point3 scaleRotAxis, firstScaleRotAxis;
Point3 firstScaleFactor;
bPos = bRot = bScale = bScaleAxis = FALSE;
for (t=start; t<=end; t+=delta) {
tm = node->GetNodeTM(t) * Inverse(node->GetParentTM(t));
decomp_affine(tm, &ap);
AngAxisFromQ(ap.q, &rotAngle, rotAxis); // Rotation
AngAxisFromQ(ap.u, &scaleRotAngle,scaleRotAxis); // Off Axis rotation
if (!ap.u.IsIdentity()) bScaleAxis = TRUE;
if (t != start) {
// Position changes
if (!bPos) {
if (!EqualPoint3(ap.t, firstPos)) {
bPos = TRUE;
}
}
// Rotation changes
if (!bRot) {
if (fabs(rotAngle - firstRotAngle) > ALMOST_ZERO) {
bRot = TRUE;
} else if (!EqualPoint3(rotAxis, firstRotAxis)) {
bRot = TRUE;
}
}
// Scale changes
if (!bScale) {
if (!EqualPoint3(ap.k, firstScaleFactor)) {
bScale = TRUE;
}
}
// Off-Axis Scale changes
if (!bScaleAxis) {
if (fabs(scaleRotAngle - firstScaleRotAngle) > ALMOST_ZERO) {
bScaleAxis = TRUE;
} else if (!EqualPoint3(scaleRotAxis, firstScaleRotAxis)) {
bScaleAxis = TRUE;
}
}
} else {
firstPos = ap.t;
firstRotAngle = rotAngle;
firstRotAxis = rotAxis;
firstScaleRotAngle = scaleRotAngle;
firstScaleRotAxis = scaleRotAxis;
firstScaleFactor = ap.k;
}
// No need to continue looping if all components are animated
if (bPos && bRot && bScale && bScaleAxis) break;
}
if (!(bPos || bRot || bScale) && bScaleAxis) bScaleAxis = FALSE;
return bPos || bRot || bScale || bScaleAxis;
}
/********************************************************************************
Samples the animation range of a Node and create keys every N frame (given by GetKeyframeStep in
the dialog box ). This is done by decomposing the TM matrix.
If two successive keys are equal, no new key is created.
********************************************************************************/
void Max2Nmo::DumpSampledAnim(INode* node,CKObjectAnimation* anim)
{
TimeValue start = ip->GetAnimRange().Start();
TimeValue end = ip->GetAnimRange().End();
TimeValue t;
int delta = GetTicksPerFrame() * GetKeyFrameStep();
Matrix3 tm;
AffineParts ap;
//-- Light and Camera animation need an additional rotation around X axis to be valid
//-- in Virtools ( Z axis is supposed to be the direction of the lights and cameras )
Quat RotateX;
RotateX.Identity();
CK3dEntity* entity = anim->Get3dEntity();
if (CKIsChildClassOf(entity,CKCID_CAMERA) || CKIsChildClassOf(entity,CKCID_LIGHT)) {
RotateX=QFromAngAxis(HALFPI,Point3(1.0f,0.0f,0.0f));
}
Point3 prevPos;
Quat prevQ;
Quat prevU;
Point3 prevScl;
prevQ.Identity();
prevU.Identity();
CKAnimController* Pctrl = anim->CreateController(CKANIMATION_LINPOS_CONTROL);
CKAnimController* Rctrl = anim->CreateController(CKANIMATION_LINROT_CONTROL);
CKAnimController* Sctrl = anim->CreateController(CKANIMATION_LINSCL_CONTROL);
CKAnimController* SActrl = anim->CreateController(CKANIMATION_LINSCLAXIS_CONTROL);
for (t=start; t<=end; t+=delta) {
tm = node->GetNodeTM(t) * Inverse(node->GetParentTM(t));
decomp_affine(tm, &ap);
// Position key
if (Pctrl) {
Point3 pos = ap.t;
if (t== start || !EqualPoint3(pos, prevPos)) {
Pctrl->AddKey(&CKPositionKey(FrameTime(t),
VxVector(pos.x,pos.z,pos.y)));
}
prevPos = pos;
}
// Rotation Key
if (Rctrl) {
Quat q = ap.q / prevQ;
prevQ = ap.q;
if (t== start || !q.IsIdentity()) {
Quat Val = RotateX*ap.q;
Rctrl->AddKey(&CKRotationKey(FrameTime(t),
VxQuaternion(-Val.x,-Val.z,-Val.y,Val.w)));
}
}
// Scale Key
if (Sctrl) {
Point3 scl = ap.k;
if (t== start || !EqualPoint3(scl, prevScl)) {
Sctrl->AddKey(&CKScaleKey(FrameTime(t),
VxVector(scl.x,scl.z,scl.y)));
}
prevScl = scl;
}
// Off-Axis Scale Key
if (SActrl) {
Quat u = ap.u / prevU;
prevU = ap.u;
if (t== start || !u.IsIdentity()) {
Quat Val = RotateX*ap.u;
SActrl->AddKey(&CKScaleAxisKey(FrameTime(t),
VxQuaternion(-Val.x,-Val.z,-Val.y,Val.w)));
}
}
// Ensure to have the last animation key
if ((t<end) && (t + delta > end)) {
t = end;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -