Unity记一次时装骨骼换装的合并
Posted avi9111
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity记一次时装骨骼换装的合并相关的知识,希望对你有一定的参考价值。
换装入门
之前做过一次,好久没做了
国内团队都会做,做法也是各自精彩,只是分享的少;而国外的技术相对比较单一,但是模型细节度,丰富度都远不如国内,也很难和国内技术栈整合;所以网上一堆看上去还行的资料
(当然,我们拿到的国外素材很多都是几年前的,和国内团队当前素材进行比较并不公平,这里只是说下易用程度,国内素材+简单代码==容易使用)
重新做的时候被网上的资料坑了很多
搞了2个星期,终于搞完
记录一哈
(以下为残缺代码,非整个项目)
只记录重点,关键就是2个预制体或FBX融合的时候,bones要整合用第一个(很多网上的做法都是直接bones addList(),这种做法的基础必须是所有时装的bones是在同一个预制体,同一个fbx内部的,其实无需要自我限制,骨骼绑定,mesh合并,添加材质等等都是可以很“松耦合”的)
第二个重点,就是选择采用单一mesh合并(skinnedmeshrenderer相当黑盒啊),否则多个mesh,多个材质也是一种办法,相互转化,但Unity官方的东西就是。。好像能 这么用,又好像能那么用。。就是不告诉你怎么用。。。。(不公开透明的API)还真实很多坑的,
烧菜坑思路就是“怎么简单怎么来”
其他重点,就是boneposes和matrix4x4的转换了
for (int i = 0; i < length; i++)
{
if(i==0) continue;//个人模型问题,这个判断可以不要,(个人第二个模型才是人体主模型)
SkinnedMeshRenderer oneRender = combineRenders[i];
// 记录骨骼
//bones.AddRange(oneRender.bones);
//(两个预制体合并,所以需要合并骨骼,不能用自己的骨骼)
var bonesInRoot = combinedRoot.GetComponentsInChildren<Transform>();
List<Transform> findBones = new List<Transform>();
foreach (var b in oneRender.bones)
{
bool did = false;
foreach (var t in bonesInRoot)
{
if (t.name == b.name)
{
findBones.Add(t);
did = true;
}
}
if(did==false)
findBones.Add(b);
}
bones.AddRange(findBones);
// 记录权重
BoneWeight[] meshBoneweight = oneRender.sharedMesh.boneWeights;
for (int j = 0; j < meshBoneweight.Length; ++j)
{
BoneWeight bw = meshBoneweight[j];
BoneWeight bWeight = bw;
bWeight.boneIndex0 += boneOffset;
bWeight.boneIndex1 += boneOffset;
bWeight.boneIndex2 += boneOffset;
bWeight.boneIndex3 += boneOffset;
boneWeights.Add(bWeight);
}
// offset是为了合并之后BoneWeight.boneIndex还能正确定向骨骼
boneOffset += oneRender.bones.Length;
// 记录网格相关信息
CombineInstance combineInstance = new CombineInstance();
Mesh mesh = new Mesh();
oneRender.BakeMesh(mesh);
mesh.uv = oneRender.sharedMesh.uv;
combineInstance.mesh = mesh;
//combineInstance.transform = oneRender.localToWorldMatrix;//有个天坑是 oneRender.localToWorldMatrix 和 oneRender.transform.localToWorldMatrix 是两回事
//Matrix4x4 matrix = oneRender.transform.worldToLocalMatrix;
// combineInstance.transform = oneRender.transform.localToWorldMatrix ;
combineInstance.transform =
oneRender.transform.localToWorldMatrix * Matrix4x4_Rotation( EnemyManager_Axle.X, -90);
//combineInstance.subMeshIndex = i-1;//个人模型问题,这个判断可以不要,(个人第二个模型才是人体主模型),也不可以这么分,骨骼会错乱(个人采用了合并单一Mesh方法)
combineInstances.Add(combineInstance);
// oneRender.gameObject.SetActive(false);//网上抄的方法,完全不知道为什么要这么用
}
// 将所有的骨骼变换矩阵从自身转换到当前预制件下
List<Matrix4x4> bindposes = new List<Matrix4x4>();
int boneLength = bones.Count;
for (int i = 0; i < boneLength; i++)
{
bindposes.Add(bones[i].worldToLocalMatrix * combineMatrix);
}
Mesh combinedMesh = new Mesh();
combinedMesh.CombineMeshes(combineInstances.ToArray(), true, true);
combinedSkinnedRenderer.sharedMesh = combinedMesh;
combinedSkinnedRenderer.bones = bones.ToArray();
combinedSkinnedRenderer.sharedMesh.boneWeights = boneWeights.ToArray();
combinedSkinnedRenderer.sharedMesh.bindposes = bindposes.ToArray();
combinedSkinnedRenderer.sharedMesh.RecalculateBounds();
combinedSkinnedRenderer.material = combineMaterial;
/// <summary>
/// 一个简单的旋转,其他Matrix4x4变换可看:https://blog.csdn.net/aaa583004321/article/details/81948780
/// </summary>
/// <param name="transform"></param>
/// <param name="axle"></param>
/// <param name="angle"></param>
public static Matrix4x4 Matrix4x4_Rotation(EnemyManager_Axle axle, float angle)
{
Matrix4x4 matrix = Matrix4x4.identity;
if (axle == EnemyManager_Axle.X)
{
matrix.m11 = Mathf.Cos(angle * Mathf.Deg2Rad);
matrix.m12 = -Mathf.Sin(angle * Mathf.Deg2Rad);
matrix.m21 = Mathf.Sin(angle * Mathf.Deg2Rad);
matrix.m22 = Mathf.Cos(angle * Mathf.Deg2Rad);
}
else if (axle == EnemyManager_Axle.Y)
{
matrix.m00 = Mathf.Cos(angle * Mathf.Deg2Rad);
matrix.m02 = Mathf.Sin(angle * Mathf.Deg2Rad);
matrix.m20 = -Mathf.Sin(angle * Mathf.Deg2Rad);
matrix.m22 = Mathf.Cos(angle * Mathf.Deg2Rad);
}
else
{
matrix.m00 = Mathf.Cos(angle * Mathf.Deg2Rad);
matrix.m01 = -Mathf.Sin(angle * Mathf.Deg2Rad);
matrix.m10 = Mathf.Sin(angle * Mathf.Deg2Rad);
matrix.m11 = Mathf.Cos(angle * Mathf.Deg2Rad);
}
return matrix;
}
public enum EnemyManager_Axle
{
X,
Y,
Z
}
参考:
以上是关于Unity记一次时装骨骼换装的合并的主要内容,如果未能解决你的问题,请参考以下文章