⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 animout.cpp

📁 3dmax导出3d模型二次开发插件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//************************************************************************** 
//* 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 + -