Unity SkinnedMeshRenderer 动态换装系统 Mesh合并 贴图合并

之前的文章:

  1. 基础换装
  2. Mesh合并

效果演示
请添加图片描述

普通换装
请添加图片描述

通过Mesh合并后的换装
请添加图片描述

完成的换装包含以下几步:

  1. 合并Mesh
  2. 刷新骨骼
  3. 替换材质
  4. 合并贴图
  5. 刷新UV

下面是每一步的详细介绍

一、合并Mesh

通过Unity中的CombineInstance对所有需要合并的SkinnedMeshRenderer合并

List<CombineInstance> combineInstancesList = new List<CombineInstance>();
for (int i = 0; i < skinnedMeshRenderers.Length; i++){
    
    
    CombineInstance combineInstance = new CombineInstance();
    combineInstance.mesh = skinnedMeshRenderer.sharedMesh;
    combineInstance.transform = skinnedMeshRenderer.localToWorldMatrix;
    combineInstancesList.Add(combineInstance);   
}
Mesh newMesh = new Mesh();
newMesh.CombineMeshes(combineInstancesList.ToArray(), true, true);

二、刷新骨骼

1. bones

通过各个部件收集骨骼,然后赋值个大的合并后的Mesh,在通过原有的骨骼列表依次刷新骨骼

// 收集各个部件的骨骼
List<Transform> bones = new List<Transform>();
for (int i = 0; i < skinnedMeshRenderers.Length; i++)
{
    
    
    for (int j = 0; j < skinnedMeshRenderer.bones.Length; j++)
    {
    
    
        bones.Add(skinnedMeshRenderer.bones[j]);
    }
}
combinedSkinnedMeshRenderer.bones = bones.ToArray();

// 正确刷新骨骼
List<Transform> newBones = new List<Transform>();
for (int i = 0; i < combinedSkinnedMeshRenderer.bones.Length; i++)
{
    
    
    string name = combinedSkinnedMeshRenderer.bones[i].name;
    if (bonesDic.ContainsKey(name))
    {
    
    
        newBones.Add(bonesDic[name]);
    }
}
combinedSkinnedMeshRenderer.bones = newBones.ToArray();

2. boneWeights

刷新骨骼权重,根据原有Mesh的权重+合并后的Mesh偏移

List<BoneWeight> boneWeightsList = new List<BoneWeight>();
int boneOffset = 0;
for (int i = 0; i < skinnedMeshRenderers.Length; i++)
{
    
    
    SkinnedMeshRenderer skinnedMeshRenderer = skinnedMeshRenderers[i];
    skinnedMeshRenderer.gameObject.SetActive(false);
    CombineInstance combineInstance = new CombineInstance();
    combineInstance.mesh = skinnedMeshRenderer.sharedMesh;
    combineInstance.transform = skinnedMeshRenderer.localToWorldMatrix;
    combineInstancesList.Add(combineInstance);
    // Bone
    BoneWeight[] boneWeightsArr = skinnedMeshRenderer.sharedMesh.boneWeights;
    for (int j = 0; j < skinnedMeshRenderer.bones.Length; j++)
    {
    
    
        bones.Add(skinnedMeshRenderer.bones[j]);
    }
    for (int j = 0; j < boneWeightsArr.Length; j++)
    {
    
    
        BoneWeight bw = boneWeightsArr[j];
        bw.boneIndex0 += boneOffset;
        bw.boneIndex1 += boneOffset;
        bw.boneIndex2 += boneOffset;
        bw.boneIndex3 += boneOffset;
        boneWeightsList.Add(bw);
    }
    boneOffset += skinnedMeshRenderer.bones.Length;
}
combinedSkinnedMeshRenderer.sharedMesh.boneWeights = boneWeightsList.ToArray();

3. bindposes

T-pose下的顶点位置,用矩阵转换

// bones为收集各个部件后的列表
for(int i = 0; i < bones.Count; i++)
{
    
    
    bindPosesList.Add(bones[i].worldToLocalMatrix * transform.localToWorldMatrix);
}
combinedSkinnedMeshRenderer.sharedMesh.bindposes = bindPosesList.ToArray();

三、替换材质

将合并后的SkinnedMeshRenderer的material替换

四、合并贴图

合并后的贴图
请添加图片描述

扫描二维码关注公众号,回复: 14669074 查看本文章

PS:如果材中有多个贴图,则分别要按照下面步骤进行合并

1. 收集贴图

在合并Mesh之前,通过每个SkinnedMeshRenderer的material获取
List<Texture> textureList存储

2. pack

atlasTexture 就是合并后的图集

Texture2D atlasTexture = new Texture2D(width, height);
Rect[] packRet = atlasTexture.PackTextures(textureList.ToArray(), padding=0f)

3. 修改材质贴图

直接使用Material.SetTexture(name, texture)修改贴图

五、刷新UV

packRet中存储了每个原贴图在大的图集中位置信息,需要将每个部件的顶点的uv进行重新计算

// uvCount 是遍历所有部件的定点时候累加得到 smr.sharedMesh.uvs.Length 求和
// uvList(List<Vector2[]>)  是存储了每个部件的顶点的列表
Vector2[] atlasUVs = new Vector2[uvCount]; // 大Mesh的UV列表
int counter = 0;
for (int index = 0; index < uvList.Count; ++index)
{
    
    
    foreach (Vector2 uv in uvList[index])
    {
    
    
        atlasUVs[counter].x = Mathf.Lerp(packingResults[i][index].xMin, packingResults[i][index].xMax, uv.x);
        atlasUVs[counter].y = Mathf.Lerp(packingResults[i][index].yMin, packingResults[i][index].yMax, uv.y);
        counter++;
    }
}
combinedSkinnedMeshRenderer.sharedMesh.uv = atlasUVs;

猜你喜欢

转载自blog.csdn.net/YuAnHandSome/article/details/128250339