|
Unity踩坑记录(1)换装系统之坑:重新绑定之后的骨骼排序问题
最近我的游戏正在开发换装系统,最开始的时候我在资源商店买了个资源包,以这个资源包为基础开发了换装系统,一切顺利,顺利得我以为换装系统根本没有难点。
但是,年轻的开发者呦,Unity会给每个抱有这种想法的开发者一个大比斗。当我想要再新建模一些资源导入Unity来作为换装部件的时候,两个大坑正在等着我。
第一:使用maya绑定的骨骼模型导入到Unity之后,根骨骼节点不是root。
第二:重新导入unity之后的蒙皮模型对应的骨骼索引会有变化
第一个问题的解决过程:
我觉得资源包里的发型都不够个性,所以我就新建模了一个发型,打算导入到换装系统。
由于我使用的是购买得来的资源包,所以我直接把骨骼导入到maya中,然后对头发做了绑定。
等我把模型再导入回Unity,就看到了下面的景象:
这位仁兄你肚皮上的毛长得挺性感的。
经过很久的排查,我终于从资源上发现了问题出在哪里。
每个导入的骨骼模型的资源都会自动在模型子物体上添加一个SkinnedMeshRenderer组件,从这里我发现,别人的根骨骼都是root,而我做的头发的根骨骼是head。
这就导致我的头发在设置骨骼的时候,定位到了胯部。
但是我在从maya导出模型的时候,明明把每一根骨骼都选中了的。
这个问题没有困扰我太久,因为我没有选择在maya这一个软件上吊死。我尝试使用max和blender都做了一次绑定,这两个软件导出的模型的根骨骼都是正确的。
所以这个问题的结论是,别使用maya做绑定!至于max和blender,我推荐使用blender,max的绑定功能真的难用。
第二个问题的解决过程:
虽然根骨骼正确了,但是我没有高兴几秒,因为现在它的效果是这样的:
它的权重乱了,乱得一塌糊涂。
明明骨骼树都是一样的,为啥会乱。在经过一白天的搜索资料之后,终于明白了,原来骨骼导出再重新导入之后,虽然在层级视图中看起来和导出之前是一样的,但是在骨骼数组中的排序早就乱了。
蒙皮后的mesh文件里面有这样一项属性:BlendIndices
顶点就是通过这个属性来找到对应的骨骼的,所以在换装加载mesh的时候需要重新把这个属性和人物的骨骼树对应。
至于重新对应的方法我是从这个地方找到的:
https://forum.unity.com/threads/assetpostprocessor-skinned-mesh-renderer-bone-index-reorder-solved.401872/
但是这个网址的分享也是个大坑,如果你直接把他给的代码复制到了项目中,Unity会直接把所有的骨骼模型都重新导入一遍,然后你就会发现原来的所有模型都乱套了。别问我怎么知道了,都是泪。
所以我这里把没有毒副作用的代码放在这里了。
//方法:根据人物(source)的骨骼,对服装(rend)的骨骼进行重新排序,然后重设模型的骨骼索引
void Process(SkinnedMeshRenderer rend , SkinnedMeshRenderer source)
{
if (rend == null) return;
//骨骼列表
List<Transform> tList = new List<Transform>(rend.bones);
List<Transform> nList = new List<Transform>();
foreach(var sel in source.bones)
{
Transform T = tList.Find((x) => x.name == sel.name);
if (T != null) nList.Add(T);
}
Dictionary<int, int> remap = new Dictionary<int, int>();
for (int i = 0; i < rend.bones.Length; i++)
{
remap = nList.IndexOf(rend.bones);
}
//remap bone weight indexes
BoneWeight[] bw = rend.sharedMesh.boneWeights;
for (int i = 0; i < bw.Length; i++)
{
bw.boneIndex0 = remap[bw.boneIndex0];
bw.boneIndex1 = remap[bw.boneIndex1];
bw.boneIndex2 = remap[bw.boneIndex2];
bw.boneIndex3 = remap[bw.boneIndex3];
}
//重新映射bindposes
Matrix4x4[] bp = new Matrix4x4[rend.sharedMesh.bindposes.Length];
for (int i = 0; i < bp.Length; i++)
{
bp[remap] = rend.sharedMesh.bindposes;
}
//分配新的数据
rend.sharedMesh.boneWeights = bw;
rend.sharedMesh.bindposes = bp;
}终于我的换装搞定了。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|