Merge multiple SkinnedMeshRenderers on the same bone

public class MeshRendererUtility
{
    
    
    public static void Merge(Transform transform)
    {
    
    
        var skins = transform.GetComponentsInChildren<SkinnedMeshRenderer>().Where(x=>x.sharedMesh!=null).ToArray();
        List<Material> materials = new List<Material>();
        List<Mesh> meshes = new List<Mesh>();
        List<Texture2D> textures = new List<Texture2D>();
        foreach (var skin in skins)
        {
    
    
            meshes.Add(skin.sharedMesh);
            foreach (var mat in skin.sharedMaterials)
            {
    
    
                materials.Add(mat);
                var texture = mat.GetTexture("_MainTex") as Texture2D;
                if (texture != null)
                {
    
    
                    textures.Add(texture);
                }
            }
        }

        var rects = MergeTexture(textures.ToArray(), out Texture2D result);
        var material = MergeMaterial(materials.ToArray(), result);
        var mesh = MergeMesh(meshes.ToArray(), rects);
        mesh.bindposes = GetMeshBindPoses(skins[0].bones, transform);

        var skinned = transform.gameObject.AddComponent<SkinnedMeshRenderer>();
        skinned.rootBone = skins[0].rootBone;
        skinned.bones = skins[0].bones;
        skinned.sharedMesh = mesh;
        skinned.material = material;
    }


    public static Mesh MergeMesh(Mesh[]meshes,Rect[] rects)
    {
    
    
        CombineInstance[] combineInstances = new CombineInstance[meshes.Length];
        List<BoneWeight> boneWeights = new List<BoneWeight>();
        for (int i=0;i<meshes.Length;i++)
        {
    
    
            var rect = rects[i];
            Mesh mesh = new Mesh();
            mesh.vertices = meshes[i].vertices;
            mesh.triangles = meshes[i].triangles;
            mesh.normals = meshes[i].normals;
            boneWeights.AddRange(meshes[i].boneWeights);
            Vector2 []uvs = new Vector2[meshes[i].uv.Length];
            for (int j = 0; j < uvs.Length; j++)
            {
    
    
                uvs[j].x = rect.x + meshes[i].uv[j].x * rect.width;
                uvs[j].y = rect.y + meshes[i].uv[j].y * rect.height;
            }

            mesh.uv = uvs;
            combineInstances[i] = new CombineInstance {
    
    mesh=mesh };
        }
        Mesh result = new Mesh();
        result.CombineMeshes(combineInstances, true, false);
        result.boneWeights = boneWeights.ToArray();
        return result;
    }

    public static Rect[] MergeTexture(Texture2D [] textures,out Texture2D result)
    {
    
    
        result = new Texture2D(1024, 1024);

        string[] assetPaths = new string[textures.Length];
        for (int i=0;i<textures.Length;i++)
        {
    
    
            assetPaths[i] = AssetDatabase.GetAssetPath(textures[i]);
        }

        Texture2D[] newTextures = new Texture2D[textures.Length];
        for(int i=0;i<textures.Length;i++)
        {
    
    
            var texture = textures[i];
            newTextures[i] = GetTexture(texture);
        }

        for (int i = 0; i < assetPaths.Length; i++)
        {
    
    
            AssetDatabase.DeleteAsset(assetPaths[i]);
        }

        var rects = result.PackTextures(newTextures, 0, 1024);

        for (int i=0;i< newTextures.Length;i++)
        {
    
    
            UnityEngine.Object.DestroyImmediate(newTextures[i]);
        }

        return rects;
    }


    static Texture2D GetTexture(Texture2D texture)
    {
    
    
        RenderTexture renderTexture = new RenderTexture(texture.width, texture.height, 0);
        Graphics.Blit(texture, renderTexture);

        Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
        var rt = RenderTexture.active;
        RenderTexture.active = renderTexture;
        texture2D.ReadPixels(new Rect(0, 0, texture.width, texture.height), 0, 0);
        texture2D.Apply();

        RenderTexture.active = rt;
        UnityEngine.Object.DestroyImmediate(renderTexture);

        return texture2D;
    }

    static Material MergeMaterial(Material[] materials,Texture2D texture)
    {
    
    
        Material material = new Material(materials[0].shader);
        material.CopyPropertiesFromMaterial(materials[0]);
        material.SetTexture("_MainTex", texture);
        return material;
    }

    static Matrix4x4[] GetMeshBindPoses(Transform[] transforms, Transform transform)
    {
    
    
        Matrix4x4[] bindPoses = new Matrix4x4[transforms.Length];
        for (int i = 0; i < transforms.Length; i++)
        {
    
    
            bindPoses[i] = transforms[i].worldToLocalMatrix * transform.localToWorldMatrix;
        }
        return bindPoses;
    }

}

Guess you like

Origin blog.csdn.net/qq_17813937/article/details/130150657