永发信息网

求高级骨骼插件AdvancedSkeleton2.0

答案:2  悬赏:0  手机版
解决时间 2021-07-16 16:16

要免费可以用的

我在电驴上下了好几个都不知道怎么用

最佳答案
文/潘李亮

查找Skin修改器

要找到一个Mesh上是不是有Skin修改器,根据MAX的几何管道的结构,需要遍历整个ModStack中的Derived Object。判断应用在这些Derived Object上的修改器的类型。MAX中所有的对象都有一个类似COM的GUID的唯一标记ClassID。Skin修改器的ClassID为SKIN_CLASSID,在获得Derived Object的修改器后只需要检查修改器的ClassID是不是SKIN_CLASSID即可。示例代码如下:

ISkin * FindSkinModifier(INode *pINode){

Object * pObject = pINode->GetObjectRef();

if(pObject == 0) return 0;

// 循环检测所有的DerivedObject

while(pObject->SuperClassID() == GEN_DERIVOB_CLASS_ID)

{

IDerivedObject * pDerivedObject =

static_cast<IDerivedObject *>(pObject);

for(int stackId = 0;

stackId < pDerivedObject->NumModifiers();

stackId++)

{

Modifier * pModifier =

pDerivedObject->GetModifier(stackId);

//检测ClassID是不是Skin修改器

if(pModifier->ClassID() == SKIN_CLASSID) {

return (ISkin*) pModifier->GetInterface(I_SKIN);

}

}

//下一//个Derived Object

pObject = pDerivedObject->GetObjRef();

}

return 0;

}

获取Mesh对象

根据第四节中描述的,要从一个INode中获得Mesh对象,首先应该从INode中获得Object对象,然后再转成Mesh对象。具体代码如下:

Mesh* GetMesh(INode* pNode , int iMaxTime){

NullView view;

//NullView是自定义的View类。详细参见完整的插件代码

BOOL bNeedDelete = false;

ObjectState os = pNode->EvalWorldState(iMaxTime);

Object* pObj = os.obj;

TriObject * triObject = (TriObject *)pObj->

ConvertToType(iMaxTime, triObjectClassID);

GeomObject* pGeoObj = (GeomObject*)pObj;

Mesh * pMesh = pGeoObj->GetRenderMesh(

iMaxTime , m_pNode , view , bNeedDelete );

return pMesh;

}

获取皮肤数据与顶点的骨骼绑定信息

在成功获取到一个节点的ISkin对象和Mesh以后,就可以使用这两个对象来提取物体的顶点数据和骨骼的绑定信息了。

Mesh中的数据保存在不同的数组中,常用的包含以下几种:顶点位置信息,颜色信息,法向量,UV坐标,MapChannel信息等。其中法向量的信息不是特别的准确,需要考虑平滑组,面法向量与顶点法向量的差异等。MapChannel用于仅仅有多层纹理贴图坐标的情况,在只有一层纹理坐标的情况下则不需要考虑,使用UV坐标就足够了。本文仅仅演示如何导出顶点位置,单层纹理和骨骼绑定信息,如何准确的计算法向量以及处理多层纹理坐标的内容不在本文的讨论范围。

Mesh中的numVerts变量标记了Mesh有几个顶点位置,numTexCoords标记了有几个纹理坐标。而通常这两个值是不一样的。

要提取骨骼绑定信息,首先需要从ISkin对象中查询到ISkinContextData接口: ISkinContextData* pSkinContext

= pSkin->GetContextInterface(pNode); 通过ISkinContextData的GetNumAssignedBones函数可以得到影响到这个顶点的骨骼的个数,进而通过GetAssignedBone和GetBoneWeight接口可以到这个Bone的index已经这个Bone对这个顶点的权重。

void GetVertexBoneInfo(INode* pNode , ISkin* pSkin , Mesh* mesh , int vertexIdx , int uvIdx , Vertex_t& vOut) {

CSkeleton* pSkeleton = GetGlobalSkeleton();

ISkinContextData* pSkinCtx =

pSkin->GetContextInterface(pNode);

int nBones =

pSkinCtx->GetNumAssignedBones(vertexIdx);

vOut.pos = mesh->verts[vertexIdx] *

pNode->GetObjectTM(0,NULL);//第一帧的数据

vOut.texCoord = mesh->texCoords[uvIdx];

vOut.nEffBone = nBones;

for(int jBone = 0; jBone < nBones; jBone ++) {

INode* pBone = pSkin->GetBone(

pSkinCtx->GetAssignedBone(vertexIdx, Bone));

vOut.Bone[jBone].weight =

pSkinCtx->GetBoneWeight(vertexIdx,jBone);

vOut.Bone[jBone].boneIdx =

pSkeleton->findBoneIndex(pBone);

}

}

上述示例代码中并没有考虑到有个别顶点的骨骼数量超过4种情况,在正式的代码中应该对所有影响到这个顶点的骨骼权重进行排序,取前4个权重最大的,丢弃其余的骨骼。并要考虑有有些重复骨骼的问题。

导出面的和材质信息

在成功解决了顶点和骨骼的数据提取后,还需要获得面的信息,即顶点的拓扑关系。3D渲染器能处理的面一般都是三角形面,因此一般要求美工在制作模型的时候首先将模型转换成Editable Mesh。这样能确保在Mesh取到的面都是三角形。

MAX中的面有两种,用来表示形状的Face类和用来表示纹理的TVFace类。Face和TVFace是一一对应的。就是说要获得一个三角形的完整数据,必须同时获取Face类和TVFace类。

Face类中的信息比较重要的有三个顶点的位置索引,可以通过Face::v[i]来获得,得到这个索引后,在Mesh::verts数组里就可以获得位置的数据。同理TVFace也一样。

Face类里除了顶点信息外,还保存了和材质相关的信息:MaterialID。一个Mesh上通常只能应用一个Material,那为什么会有MaterialID这个概念呢?因为在Max里除了标准材质以外,还有一种美工非常有用的材质叫多材质(Multi-Material),这种材质可以可以包含很多个标准材质,我们可以通过判断材质的ClassID来判断它是不是一个多材质,如果是,就遍历它的所有子材质(Sub-Mateiral)。MaterialID就是对应的子材质的序号。在绘制的时候,MaterialID相同的三角形表示它们有相同的纹理和材质,在导出的时候应该按照MaterialID进行排序。

Max中的Material使用Mtl类表示,可以通过INode::GetMtl()来获得。Mtl:: NumSubMtls加GetSubMtl则可访问到这个Material的所有Material。对于一个标准材质,我们可以获得这个材质的各种属性,包括纹理贴图,纹理贴图使用的贴图坐标通道(MapChannel),以及环境光,高光等属性。处理材质的示例代码如下:

void SaveMaterial(const char* fileMat , INode* pNode){

ofstream out(fileMat,ios::binary);

Mtl* pMtl = pNode->GetMtl();

int nSubMat = pMtl->NumSubMtls();

if (nSubMat == 0) {

//处理和保存一个标准材质的代码,详见参考资料

saveStdMaterial(out , (StdMat*)pMtl);

} else {

for(int i = 0 ; i < pMtl->NumSubMtls(); i++ )

saveStdMaterial(out ,

(StdMat*)pMtl->GetSubMtl(i));

}

}

以下为简单的提取三角形数据的代码。

void SaveMesh(const char* fileMesh , INode* pNode , Mesh* pMesh) {

ISkin* pSkin = GetSkinModifier(pNode);

ofstream out(fileMesh , ios::binary);

int nFace = pMesh->numFaces ;

out.write( (char*)&nFace,sizeof(int) );

for(int i = 0 ;i < pMesh->numFaces ; i ++) {

TVFace& tvface = pMesh->tvFace[i];

Face& face = pMesh->faces[i];

for(int j = 0 ; j < 3 ; j++) {

//一个三角形三个顶点

Vertex_t vert ;

vert.matID = face.getMatID();

GetVertexBoneInfo(pNode, pSkin, pMesh,

face.v[j], tvface.getTVert(j), vert);

//保存到文件

out.write( (char*)&vert,sizeof(vert) );

}

}

}

上述代码仅仅是简单的保存了每一个面的信息,真正应用的时候,至少还应该把所有的面按照MateiralID来进行排序,并且GetVertexBoneInfo函数在生成顶点数据的时候必然有很多顶点是完全相同的,应该把这些相同的顶点都去掉。面的信息使用Index Buffer来保存。鉴于处理这些代码过长,就不在文中一一举例。

除了顶点材质相关的信息之外,Face类中比较重要的是法向量相关的信息,如RVertex和平滑组数据(smooth group)等。读者可以参阅参考资料。

进一步的工作

现在我们已经基本可以获得一个简单的骨骼动画系统所需要的大部分数据了。但是这仅仅局限于一个演示性的骨骼动画系统,离一个完整鲁棒的系统还有很多事情要做。

上述例子中,我们仅仅导出了皮肤的顶点和第一层纹理坐标。读者还需要进一步处理多层贴图,顶点颜色,法向量等数据。在导出的骨架中,还应该能更方便的处理骨架的层次关系,以及能区分角色的上身和下身。因为通常一个骨骼动画系统是需要进行上下身的动作融合的。其次骨骼的变换矩阵应该是保存相对于父骨骼的局部变换矩阵,局部矩阵可以分解成四元数,平移和缩放,使用四元数能进行更平滑的插值和动作间的过渡,而且为了减少动作文件的大小,关键帧动画也是值得考虑的一个技术点。

在数据组织方面,我认为一个完善的骨骼动画系统应该能合理而自然的管理所有数据,XReal3D的数据组织采用的是流式存储,所有的动作、骨架、顶点位置、纹理坐标都拥有自己的流。这样的存储方式,在保持弹性的前提下大大的减少了一个骨骼动画角色的文件数量,方便管理和维护。

此外,现在的角色动画系统还应该包括表情动画和柔体系统。表情动画,一般称为在3DsMax的例子里有一个修改器就是表情动画,编译这个插件和使用它的头文件,我们可以访问Max里的表情动画。这个插件的位置在X:\3dsmax\maxsdk\samples\modifiers\morpher中。柔体系统也叫布料系统,可以用它来制作衣服飘动的效果。

最后一个需要说的IGame, IGame是3DsMaxSDK中附带一个用来为导出3D游戏相关数据的开发包。基本上,IGame是3DsMAXSDK的一个包装,使用起来更加方便而已。要深入的了解和掌握3DsMax插件的开发,还是需要对3DsMaxSDK有一定的熟悉程度。

总而言之,一个完整的骨骼动画系统插件是非常复杂的工程,鉴于文章篇幅,不可能介绍的面面俱到,希望本文对那些初次接触MAX插件开发的读者能有一定的帮助。
全部回答

参考资料:

http://bbs.cg98.cn/thread-81913-1-1.html

这里下载

我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
怎样抓住一位很乖的女孩子的心,让她对我有感
湖北地区何时才想重庆一样打黑啊?
怎样写实践的心得体会
电影睡前故事里面主角跟着电台一起唱莫扎特的
财付通的账号和密码忘了怎么找回?
word的意思
求历史学习方法
爱上一个原来她并不是爱我的人怎么办;也跟那
男生喜欢女生的表现是什么样的?
口袋白金冥王龙变成第二形态的那个东西在哪里
学问藏今古 下联是什么
你好我 做完手术10天了都还没有出血“医生请
下载的歌怎么放到播放器里
用Word给一个景点做宣传,怎么弄?
为什么X5中有人的个人信息的模块是黄色的
推荐资讯
学习是什么东东啊?
诺基亚5800XM?
黑米怎么煮啊?有经验者答,胡扯的闪..可以和什
IBM笔记本哪一款比较好用?
为什么我的资料里网络游戏的DNF资料不正确
开通黄钻一个月之后需要取消吗?
谁能帮我做个妖字。炫舞自定义戒指用的~~谢谢
有没有纪念已故同学的歌?
小皇帝詹姆斯今年能问鼎吗???
计算机是学硬件好还是学软件好?
怎么做自己喜欢的QQ头像?
两道数学题/
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?