?? meshanimout.cpp
字號:
//**************************************************************************
//* MeshAnimout.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 animated mesh output(sampling to morph or conversion to skin)
//*
//***************************************************************************
#include "Precomp.h"
#include "Max2Nmo.h"
extern BOOL g_CharacterStudio312;
/****************************************************************************
Mesh Animation output
****************************************************************************/
void Max2Nmo::ExportAnimMesh(INode* node)
{
ObjectState os = node->EvalWorldState(GetStaticFrame());
if (!os.obj) return;
CK3dEntity* entity = VirtoolsExporter->GetEntityByKey(node);
if (!entity) return;
//-- Check if a skin modifier exists on this node
if (ExportSkinnedMesh(node,entity)) return;
//-- Check if a physique modifier exists on this node
if (GetConvertPhysiqueToSkin())
if (ExportPhysiqueMesh(node,entity)) return;
//-- Otherwise check if the object is animated to create a morph animation
//-- we will output the entire mesh definition for every specified frame.
Interval animRange = ip->GetAnimRange();
Interval objRange = os.obj->ObjectValidity(GetStaticFrame());
//if (objRange.Start()==0 && objRange.End()==0) return;
//-- If the animation range is not fully included in the validity
//-- interval of the object, then we're animated.
if (!objRange.InInterval(animRange)) {
TimeValue t = animRange.Start();
CKObjectAnimation* anim = entity->GetObjectAnimationCount() ? entity->GetObjectAnimation(0) : NULL;
CKMorphController* mctrl = NULL;
while (1) {
// This may seem strange, but the object in the pipeline
// might not be valid anymore.
os = node->EvalWorldState(t);
objRange = os.obj->ObjectValidity(t);
TimeValue t2 = objRange.Start() < animRange.Start() ? animRange.Start() : objRange.Start();
if (t2<t) break;
t = t2;
//----- Export the mesh definition at this frame
if (!anim) {
anim = VirtoolsExporter->AddObjectAnimation(entity,(const char *)entity->GetName(),node);
anim->SetLength(FrameTime(m_EndFrame));
}
if (!mctrl) {
mctrl = (CKMorphController*)anim->CreateController(CKANIMATION_MORPH_CONTROL);
mctrl->SetLength(FrameTime(m_EndFrame));
}
if (os.obj->ClassID() == Class_ID(PATCHOBJ_CLASS_ID, 0))
DumpPatchMeshMorphKey(mctrl,node,t);
else
DumpMeshMorphKey(mctrl,node,t);
//------
if (objRange.End() >= animRange.End()) {
break;
}
else {
t2 = (objRange.End()/GetTicksPerFrame()+GetMeshFrameStep()) * GetTicksPerFrame();
if (t2<=t) break;
t = t2;
}
}
if (mctrl && (mctrl->GetKeyCount()<2)) {
anim->DeleteController(CKANIMATION_MORPH_CONTROL);
mctrl=NULL;
}
if (mctrl) {
Report(REPORT_HLEVEL,"%s : Sampling to morph animation : %d keys\r\n",node->GetName(),mctrl->GetKeyCount());
}
}
}
BOOL Max2Nmo::ExportSkinnedMesh(INode* node,CK3dEntity* ent)
{
if (!ent) return FALSE;
Modifier *mod = FindSkinModifier(node);
if(!mod) return FALSE;
ISkin *iskin = (ISkin *) mod->GetInterface(I_SKIN);
if (!iskin) return FALSE;
if (!iskin->GetNumBones()) return FALSE;
ISkinContextData *iskinMC = iskin->GetContextInterface(node);
if (!iskinMC) return FALSE;
CKMesh* mesh=ent->GetCurrentMesh();
if (!mesh) return FALSE;
Report(REPORT_HLEVEL,"%s : Saving Skin Data\r\n",node->GetName());
Matrix3 InitTM;
VxMatrix Mat;
VirtoolsTransitionMesh* tmp_mesh = VirtoolsExporter->GetTransitionMesh(mesh);
CKSkin* skin = ent->CreateSkin();
int VertexCount = mesh->GetModifierVertexCount();
BOOL DoNormal = (mesh->GetClassID() != CKCID_PATCHMESH);
skin->SetBoneCount(iskin->GetNumBones());
skin->SetVertexCount(VertexCount);
if (DoNormal) {
skin->SetNormalCount(VertexCount);
}
for(int j = 0 ; j < iskin->GetNumBones() ; j++) {
CK3dEntity* bone = VirtoolsExporter->GetEntityByKey(iskin->GetBone(j));
CKSkinBoneData* bonedata = skin->GetBoneData(j);
bonedata->SetBone(bone);
if (bone) {
Matrix3 MaxBoneMat;
VxMatrix InvBoneMat,BoneMat;
/*
// Do not use GetBoneInitTM from skin since
// we cannot have the vertex original position
if (iskin->GetBoneInitTM(iskin->GetBone(j),MaxBoneMat)) {
ConvertMaxMatrix2Virtools(MaxBoneMat, BoneMat);
Vx3DInverseMatrix(InvBoneMat,BoneMat);
bonedata->SetBoneInitialInverseMatrix(InvBoneMat);
} else {
*/
bonedata->SetBoneInitialInverseMatrix(bone->GetInverseWorldMatrix());
// }
}
}
if(iskin->GetSkinInitTM(node, InitTM)) {
ConvertMaxMatrix2Virtools(InitTM, Mat);
skin->SetObjectInitMatrix(Mat);
}
CKDWORD Stride=0;
BYTE* pts=mesh->GetModifierVertices(&Stride);
CKDWORD NStride=0;
BYTE* norms=(BYTE*)mesh->GetNormalsPtr(&NStride);
for(j = 0 ; j < VertexCount ; j++,pts+=Stride,norms+=NStride ) {
int MaxVertexIndex = tmp_mesh ? tmp_mesh->m_VirtoolsVertices[j].OriginalPosIndex : j;
CKSkinVertexData* vertexdata = skin->GetVertexData(j);
if (DoNormal) {
skin->SetNormal(j,*(VxVector *)norms);
}
vertexdata->SetInitialPos(*(VxVector *)pts);
//int numPoint=iskinMC->GetNumPoints();
//if (MaxVertexIndex>=numPoint) MaxVertexIndex = numPoint-1;
vertexdata->SetBoneCount(iskinMC->GetNumAssignedBones(MaxVertexIndex));
int boneindex=0;
for(int k= 0 ; k < vertexdata->GetBoneCount(); ++k) {
boneindex = iskinMC->GetAssignedBone(MaxVertexIndex,k);
if (boneindex < 0) {
Report(REPORT_HLEVEL,"WARNING: Invalid bone index in vertex bone list. Setting this bone to index 0\r\n");
vertexdata->SetBone(k,0);
//Do we need to do something on the weight if the bone is invalid ?
}
else
vertexdata->SetBone(k,boneindex);
vertexdata->SetWeight(k,iskinMC->GetBoneWeight(MaxVertexIndex,k));
}
}
// iskin->ReleaseContextInterface(iskinMC);
return TRUE;
}
int AddBoneToArray(XVoidArray* bones,void* bone)
{
int pos=bones->GetPosition(bone);
if (pos>=0) return pos;
bones->PushBack(bone);
return bones->Size()-1;
}
BOOL Max2Nmo::ExportPhysiqueMesh(INode* node,CK3dEntity* ent)
{
#ifndef MAX42
if (g_CharacterStudio312) {
return ExportPhysiqueMeshCS312(node,ent);
} else
#endif
{
return ExportPhysiqueMeshCS300(node,ent);
}
}
/********************************************************************
Adds a Morph Key for a mesh at the specified time t. For this we
evaluate the node at the specified time value and convert its vertices
and normals to Virtools format.
If the vertices have not moved the key is not stored.
********************************************************************/
void Max2Nmo::DumpMeshMorphKey(CKMorphController* ctrl,INode* node,TimeValue t)
{
Matrix3 tm = node->GetNodeTM(t);
int i;
// Since referential is not the same in Virtools indices 1 & 2 are swapped
int vx1 = 0, vx2 = 2, vx3 = 1;
ObjectState os = node->EvalWorldState(t);
if (!os.obj || os.obj->SuperClassID()!=GEOMOBJECT_CLASS_ID) {
return; // Safety net. This shouldn't happen.
}
BOOL needDel;
TriObject* tri = GetTriObjectFromNode(node, t, needDel);
if (!tri) return;
Mesh* mesh = &tri->GetMesh();
mesh->buildNormals();
int numVtx = mesh->getNumVerts(); // Vertex Count
int numFaces = mesh->getNumFaces(); // Face Count
if (!numVtx || !numFaces) return;
int numCVx = mesh->numCVerts; // Vertex color Count
BOOL UseVertexColor = node->GetCVertMode() && numCVx;
//-- Get back the transition mesh, it will be used to store temporary vertices and normals
VirtoolsTransitionMesh* tmp_mesh = VirtoolsExporter->GetTransitionMesh(node);
if (!tmp_mesh) return;
//-- Test invalid number of vertices or faces (topology may have changed !!!)
if (tmp_mesh->m_Vertices.Size() != numVtx) return ;
if (tmp_mesh->m_Faces.Size() != numFaces) return ;
//-------------- Update the vertices pos --------------------------
// Max Vertices are given in the ObjectTM referential and we need them in NodeTM referential
// So transform them using OffsetTM
Matrix3 OffsetTM = GetNodeOffsetTM(node);
// (transform them and invert Y & Z
for (i=0; i<numVtx; i++) {
Point3 tmp = OffsetTM.PointTransform(mesh->verts[i]);
tmp_mesh->m_Vertices[i]=VxVector(tmp.x,tmp.z,tmp.y);
}
//---------- Vertex normals. --------------------------------
// In MAX a vertex can have more than one normal (but doesn't always have it).
// This is depending on the face you are accessing the vertex through.
// To get all information we need to export all three vertex normals
// for every face.
if (!UseVertexColor) {
int Nindex=0;
for (i=0; i<numFaces; i++,Nindex+=3) {
Face* f = &mesh->faces[i];
Point3 vn;
vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(f->getVert(vx1)));
tmp_mesh->m_Normals[Nindex]=VxVector(vn.x,vn.z,vn.y);
vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(f->getVert(vx2)));
tmp_mesh->m_Normals[Nindex+1]=VxVector(vn.x,vn.z,vn.y);
vn = GetVertexNormal(mesh, i, mesh->getRVertPtr(f->getVert(vx3)));
tmp_mesh->m_Normals[Nindex+2]=VxVector(vn.x,vn.z,vn.y);
}
}
//-------- And refresh Virtools Data
tmp_mesh->RefreshVirtoolsVerticesPosition();
int VirtoolsVertexCount = tmp_mesh->m_VirtoolsVertices.Size();
ctrl->SetMorphVertexCount(VirtoolsVertexCount);
//-- We compare if there were changes in geometry between two keys
//-- No need to have two similar keys
BOOL Same = TRUE;
if (ctrl->GetKeyCount()>0) {
CKMorphKey* PrevKey = (CKMorphKey*)ctrl->GetKey(ctrl->GetKeyCount()-1);
for (int i=0; i< VirtoolsVertexCount; ++i) {
if (PrevKey->PosArray[i]!=tmp_mesh->m_VirtoolsVertices[i].Pos) { Same = FALSE; break; }
}
} else Same = FALSE;
if (!Same) {
int index = ctrl->AddKey(FrameTime(t),!UseVertexColor);
CKMorphKey* key = (CKMorphKey*)ctrl->GetKey(index);
for (i = 0 ; i< VirtoolsVertexCount; ++i) {
key->PosArray[i] = tmp_mesh->m_VirtoolsVertices[i].Pos;
}
if (!UseVertexColor)
for (i = 0 ; i< VirtoolsVertexCount; ++i) {
key->NormArray[i] = tmp_mesh->m_VirtoolsVertices[i].Norm;
}
}
if (needDel) {
delete tri;
}
}
/********************************************************************
Adds a Morph Key for a patch mesh. Same function as above..
********************************************************************/
void Max2Nmo::DumpPatchMeshMorphKey(CKMorphController* ctrl,INode* node,TimeValue t)
{
Mtl* nodeMtl = node->GetMtl();
Matrix3 tm = node->GetNodeTM(t);
int channel = 0;
ObjectState os = node->EvalWorldState(t);
if (!os.obj || os.obj->SuperClassID()!=GEOMOBJECT_CLASS_ID) {
return; // Safety net. This shouldn't happen.
}
BOOL needDel;
PatchObject* patch = GetPatchObjectFromNode(node, t, needDel);
if (!patch) return;
PatchMesh* pmesh = &patch->patch;
//-------------- Export the patch vertices and tangent vectors --------------------------
// Max Vertices are given in the ObjectTM referential and we need them in NodeTM referential
// So transform them using OffsetTM
Matrix3 OffsetTM = GetNodeOffsetTM(node);
// (transform them and invert Y & Z
int VirtoolsVertexCount = pmesh->numVerts + pmesh->numVecs;
if (! VirtoolsVertexCount) return;
ctrl->SetMorphVertexCount(VirtoolsVertexCount);
CKMorphKey key;
key.NormArray = NULL;
key.TimeStep = FrameTime(t);
key.PosArray = new VxVector[VirtoolsVertexCount];
for (int i=0; i<pmesh->numVerts; i++) {
Point3 tmp = OffsetTM.PointTransform(pmesh->verts[i].p);
key.PosArray[i] = VxVector(tmp.x,tmp.z,tmp.y);
}
for (i=0; i<pmesh->numVecs; i++) {
Point3 tmp = OffsetTM.PointTransform(pmesh->vecs[i].p);
key.PosArray[i+pmesh->numVerts] = VxVector(tmp.x,tmp.z,tmp.y);
}
// Compare if there was changes in geometry between two keys
// No need to have two similar keys
BOOL Same = TRUE;
if (ctrl->GetKeyCount()>0) {
CKMorphKey* PrevKey = (CKMorphKey*)ctrl->GetKey(ctrl->GetKeyCount()-1);
for (int i=0; i< VirtoolsVertexCount; ++i) {
if (PrevKey->PosArray[i]!=key.PosArray[i]) { Same = FALSE; break; }
}
} else Same = FALSE;
if (!Same)
ctrl->AddKey(&key,FALSE);
delete[] key.PosArray;
if (needDel) {
delete patch;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -