作者 任晓宇
1 基本概念
1,Morpher Modifier
在3dsmax中,使用Morpher Modifier可以改变mesh, patch, NURBS model的形状,同时支持Material morphing,通常用来实现复杂的表情动画。
为Mesh添加Morpher Modifier:选择一个mesh->Modify面板->Modifier List->Morpher。
2,Channel
每个channel对应一个不同的Mesh,代表一种表情。
通过指定在不同关健帧时每个channel的权重,来实现不同表情的组合过渡。
2 准备工作
3dsmax6 sdk并没有暴露访问morpher modifier的接口,但是我们可以在3dsmax6/maxsdk/samples/modifiers/morpher/wm3.h中找到它的定义和ClassID:
#define MR3_CLASS_ID Class_ID(0x17bb6854, 0xa5cba2a3)
…
class MorphR3 : public Modifier, TimeChangeCallback
{
…
};
将此文件include到你的工程中就可以访问morpher modifier接口了。注意,把下面两行代码注释才可以联接通过:
…
//static GetMorphMod theModPickmode;
…
//static GetMorphNode thePickMode;
3 实现代码
1,得到morpher modifier
Modifier *wxFindMorpherModifier(INode *pINode)
{
#if MAX_RELEASE >= 4000
// get the object reference of the node
Object *pObject;
pObject = pINode->GetObjectRef();
if(pObject == 0) return 0;
// loop through all derived objects
while(pObject->SuperClassID() == GEN_DERIVOB_CLASS_ID)
{
IDerivedObject *pDerivedObject;
pDerivedObject = static_cast<IDerivedObject *>(pObject);
// loop through all modifiers
int stackId;
for(stackId = 0; stackId < pDerivedObject->NumModifiers(); stackId++)
{
// get the modifier
Modifier *pModifier;
pModifier = pDerivedObject->GetModifier(stackId);
// check if we found the morpher modifier
if(pModifier->ClassID() == MR3_CLASS_ID) return pModifier;
}
// continue with next derived object
pObject = pDerivedObject->GetObjRef();
}
#endif
return 0;
}
2,得到每个channel相对于原始Mesh的变化顶点和偏移量:
MorphR3*pMorpherModifier = static_cast<MorphR3*>( wxFindMorpherModifier(pNode));
if(pMorpherModifier != NULL )
{
intiNumPoses = (int)pMorpherModifier->chanBank.size();
for(int i = 0; i<iNumPoses; ++i )
{
morphChannel&currChannel =pMorpherModifier->chanBank[i];
if( !currChannel.mActive || !currChannel.mActiveOverride ||!currChannel.cblock || !currChannel.mNumPoints )
{
continue;
}
wxPose pose;
//表情的名称
memcpy( pose.chName, currChannel.mName, sizeof(char)*64);
wxPose::wxOffsetVertex offsetVertex;
//遍历所有顶点
for( int iVertexID = 0; iVertexID<currChannel.mNumPoints;++iVertexID )
{
//判断是否有偏移
if(currChannel.mDeltas[iVertexID] == Point3(0,0,0) )
continue;
//保存顶点ID和偏移量
offsetVertex.index =iVertexID;
offsetVertex.pos =currChannel.mPoints[iVertexID] - m_aVertexArray[iVertexID].vPos;
pose.m_VertexOffsetMap.push_back(offsetVertex);
}
3,得到channel的关健帧信息
// 权重的变化范围
float fRange = currChannel.mSpinmax - currChannel.mSpinmin;
Control *Controller = currChannel.cblock->GetController(0);
IKeyControl *pIKeyControl = GetKeyControlInterface(Controller);
// 关健帧数目
int iNumKeys = pIKeyControl->GetNumKeys();
for( int j = 0; j < iNumKeys; ++j )
{
IBezFloatKey FKey;
pIKeyControl->GetKey( j, &FKey);