Unity MeshRenderer与SkinnedMeshRenderer数据自定义序列化保存

模型数据自定义的保存与加载

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SerializationGameObj_Manager : MonoBehaviour
{
    public Material matTemp;
    public GameObject obj;
    public GameObjData gameObjData;

    [ContextMenu("Save")]
    public void Save()//测试保存
    {
        gameObjData= GetGameObjData(obj);
    }
    [ContextMenu("Load")]
    public void Load()//测试加载
    {
        obj= CreateGameObject(gameObjData);
    }

    /// <summary>
    /// 生成GameObject
    /// </summary>
    /// <param name="gameObjData">GameObject信息</param>
    /// <returns></returns>
    public GameObject CreateGameObject(GameObjData gameObjData)
    {
        GameObject gameObject = new GameObject();
        List<Transform> roots = new List<Transform>();

        gameObject.name = gameObjData.name;
        foreach(nodeData nodeData in gameObjData.nodeDatas)
        {
            GameObject child = new GameObject();
            roots.Add(child.transform);
            child.name = nodeData.nodeName;
           Transform parent=  gameObject.transform.Find(nodeData.nodePath);
            if (parent == null)
            {
                parent = gameObject.transform;
            }
            child.transform.SetParent(parent);
            child.transform.localPosition = nodeData.localPosition;
            child.transform.localEulerAngles = nodeData.localEuler;
        }
       // var combineInstances = new List<CombineInstance>();
        int index = 0;
        foreach(MeshObjData meshObjData in gameObjData.meshObjDatas)
        {
            var bones = new List<Transform>();
            Transform nood = gameObject.transform.Find(meshObjData.nodePath);

            Mesh mesh = new Mesh();
            mesh.vertices = meshObjData.meshVertices;
            mesh.triangles = meshObjData.meshTriangles;
            mesh.boneWeights = meshObjData.meshBoneWeight;
            mesh.uv = meshObjData.meshUV;
            mesh.bindposes = meshObjData.meshBindPoses;
            mesh.bounds = meshObjData.meshBounds;
            mesh.normals = meshObjData.meshNormals;
            mesh.tangents = meshObjData.meshTangents;

            var newMaterial = Instantiate(matTemp);
            switch (meshObjData.rendererType)
            {
                case "UnityEngine.MeshRenderer":
                    MeshRenderer meshRenderer = nood.gameObject.AddComponent<MeshRenderer>();
                    MeshFilter meshFilter= nood.gameObject.AddComponent<MeshFilter>();
                    meshFilter.sharedMesh = mesh;
                    meshRenderer.sharedMaterial = newMaterial;
                    break;
                case "UnityEngine.SkinnedMeshRenderer":
                    SkinnedMeshRenderer skinnedMeshRenderer= nood.gameObject.AddComponent<SkinnedMeshRenderer>();
                    
                    foreach (var boneRoot in meshObjData.meshBonesRoot)
                    {
                        var target = gameObject.transform.Find(boneRoot);
                        if (target != null)
                        {
                            bones.Add(target);
                        }
                    }
                    skinnedMeshRenderer.sharedMesh = mesh;
                    skinnedMeshRenderer.bones = bones.ToArray();
                    skinnedMeshRenderer.sharedMaterial = newMaterial;
                    skinnedMeshRenderer.rootBone = gameObject.transform.Find(meshObjData.rootBonePath);

                    break;
            }
            foreach (TextureData textureData in meshObjData.textureDatas)
            {
                Texture2D texture2D = TextureDataConvertToTexture2D(textureData);
                newMaterial.SetTexture(textureData.propertyName, texture2D);
            }
            index++;
        }

        return gameObject;
    }
    /// <summary>
    /// 获得GameObject信息
    /// </summary>
    /// <param name="target">目标GameObject</param>
    /// <returns></returns>
    public GameObjData GetGameObjData(GameObject target)
    {
        GameObjData gameObjData = new GameObjData(target.name);
        gameObjData.nodeDatas = new List<nodeData>();
        foreach (Transform child in target.GetComponentsInChildren<Transform>(true))
        {
            if (child != target.transform)
            {
                gameObjData.nodeDatas.Add(new nodeData(child.name, GetChildPath(target.transform, child, false), child.localPosition, child.localEulerAngles));
            }
        }


        foreach (Renderer renderer in target.GetComponentsInChildren<Renderer>(true))
        {
            MeshObjData meshObjData = new MeshObjData();
            if (renderer != null)
            {
                switch (renderer.GetType().ToString())
                {
                    case "UnityEngine.MeshRenderer":
                        meshObjData = GetMeshObjDataByMeshRenderer((MeshRenderer)renderer);
                        break;
                    case "UnityEngine.SkinnedMeshRenderer":
                        meshObjData = GetMeshObjDataBySkinMeshRenderer((SkinnedMeshRenderer)renderer);
                        foreach (var item in ((SkinnedMeshRenderer)renderer).bones)
                        {
                            meshObjData.meshBonesRoot.Add(GetChildPath(target.transform, item.transform));
                        }
                        meshObjData.rootBonePath = GetChildPath(target.transform, ((SkinnedMeshRenderer)renderer).rootBone);
                        break;
                }
                meshObjData.rendererType = renderer.GetType().ToString();
                foreach (string propertyName in renderer.sharedMaterial.GetTexturePropertyNames())
                {
                    Texture texture = renderer.sharedMaterial.GetTexture(propertyName);
                    if (texture != null)
                    {
                        if (texture.GetType() == typeof(Texture2D))
                        {
                            Texture2D currentTexture2D = (Texture2D)texture;
                            Texture2D newTexture2D = new Texture2D(currentTexture2D.width, currentTexture2D.height, currentTexture2D.format, currentTexture2D.mipmapCount > 1);
                            Graphics.ConvertTexture(currentTexture2D, newTexture2D);
                            string texture2DBase64 = Texture2DToBase64(currentTexture2D);
                            meshObjData.textureDatas.Add(new TextureData(texture.name, propertyName, texture2DBase64, newTexture2D.width, newTexture2D.height, newTexture2D.format, newTexture2D.mipmapCount>1));
                        }
                    }
                }
            }
            meshObjData.nodePath = GetChildPath(target.transform, renderer.transform, true);
            gameObjData.meshObjDatas.Add(meshObjData);
        }


        return gameObjData;
    }
    private MeshObjData GetMeshObjDataBySkinMeshRenderer(SkinnedMeshRenderer meshRenderer)
    {
        MeshObjData meshObjData = new MeshObjData();
        meshObjData.meshVertices = meshRenderer.sharedMesh.vertices;
        meshObjData.meshTriangles = meshRenderer.sharedMesh.triangles;
        meshObjData.meshUV = meshRenderer.sharedMesh.uv;
        meshObjData.meshBoneWeight = meshRenderer.sharedMesh.boneWeights;
        meshObjData.subMeshCount = meshRenderer.sharedMesh.subMeshCount;
        meshObjData.meshMaterialCount = meshRenderer.sharedMaterials.Length;
        meshObjData.meshBindPoses = meshRenderer.sharedMesh.bindposes;
        meshObjData.meshBounds = meshRenderer.sharedMesh.bounds;
        meshObjData.meshNormals = meshRenderer.sharedMesh.normals;
        meshObjData.meshTangents = meshRenderer.sharedMesh.tangents;

        return meshObjData;
    }

    private MeshObjData GetMeshObjDataByMeshRenderer(MeshRenderer meshRenderer)
    {
        MeshFilter meshFilter = meshRenderer.GetComponent<MeshFilter>();
        MeshObjData meshObjData = new MeshObjData();
        meshObjData.meshVertices = meshFilter.sharedMesh.vertices;
        meshObjData.meshTriangles = meshFilter.sharedMesh.triangles;
        meshObjData.meshUV = meshFilter.sharedMesh.uv;
        meshObjData.meshBoneWeight = meshFilter.sharedMesh.boneWeights;
        meshObjData.subMeshCount = meshFilter.sharedMesh.subMeshCount;
        meshObjData.meshMaterialCount = meshRenderer.sharedMaterials.Length;
        meshObjData.meshBindPoses = meshFilter.sharedMesh.bindposes;
        meshObjData.meshBounds = meshFilter.sharedMesh.bounds;
        meshObjData.meshNormals = meshFilter.sharedMesh.normals;
        meshObjData.meshTangents = meshFilter.sharedMesh.tangents;

        return meshObjData;
    }
    private Texture2D TextureDataConvertToTexture2D(TextureData textureData)
    {
        byte[] data = Convert.FromBase64String(textureData.base64);
        Texture2D texture = new Texture2D(textureData.width, textureData.height, textureData.textureFormat, textureData.isMipMap);
        texture.LoadImage(data);
        return texture;
    }
    private string Texture2DToBase64(Texture2D texture2D)
    {
        Texture2D screenshot = new Texture2D(texture2D.width, texture2D.height, texture2D.format, false);
        RenderTexture renderTexture = new RenderTexture(texture2D.width, texture2D.height, 0);
        Graphics.Blit(texture2D, renderTexture);
        // 备份当前的RenderTexture
        RenderTexture previous = RenderTexture.active;

        // 设置为我们想要截图的RenderTexture
        RenderTexture.active = renderTexture;

        // 读取像素数据
        screenshot.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
        screenshot.Apply();

        // 重置RenderTexture
        RenderTexture.active = previous;
        return System.Convert.ToBase64String(screenshot.EncodeToPNG());
    }

    public string GetChildPath(Transform parent, Transform child, bool includeSelf=true)
    {
        string path = "";
        Transform[] parents = child.GetComponentsInParent<Transform>(true);
        for (int i = includeSelf ? 0 : 1; i < parents.Length - 1; i++)
        {
            if (parent == parents[i])
            {
                break;
            }
            path = parents[i].name + (path == "" ? "" : "/") + path;
        }
        return path;
    }

    [System.Serializable]
    public class GameObjData
    {
        public string name;
        public List<nodeData> nodeDatas;//所有子物体节点信息
        public List<MeshObjData> meshObjDatas;//带有模型的物体信息
        public GameObjData(string name)
        {
            this.name = name;
            nodeDatas = new List<nodeData>();
            meshObjDatas = new List<MeshObjData>();
        }
    }
    [System.Serializable]
    public class MeshObjData//Renderer信息
    {
        public string rootBonePath;//根骨骼路径
        public string nodePath;//节点路径(基于根物体)
        public string rendererType;//renderer类型

        public string shaderName;

        public List<TextureData> textureDatas;

        public Vector3[] meshVertices;
        public Vector2[] meshUV;
        public int[] meshTriangles;
        public BoneWeight[] meshBoneWeight;
        public int subMeshCount;
        public List<string> meshBonesRoot;
        public int meshMaterialCount;
        public Matrix4x4[] meshBindPoses;
        public Bounds meshBounds;
        public Vector3[] meshNormals;
        public Vector4[] meshTangents;
        public MeshObjData()
        {
            textureDatas = new List<TextureData>();
            meshBonesRoot = new List<string>();
        }
    }
    [System.Serializable]
    public struct nodeData
    {
        public string nodeName;
        public string nodePath;//节点路径(基于根物体)
        public Vector3 localPosition;
        public Vector3 localEuler;
        public nodeData(string nodeName,string nodePath, Vector3 localPosition, Vector3 localEuler)
        {
            this.nodeName = nodeName;
            this.nodePath = nodePath;
            this.localPosition = localPosition;
            this.localEuler = localEuler;
        }
    }
    [System.Serializable]
    public struct TextureData//图片信息
    {
        public string name;//图片名称
        public string propertyName;//在材质球里使用的特性名称
        public string base64;
        public int width;
        public int height;
        public TextureFormat textureFormat;
        public bool isMipMap;

        public TextureData(string name, string propertyName, string base64, int width, int height, TextureFormat textureFormat, bool isMipMap)
        {
            this.name = name;
            this.propertyName = propertyName;
            this.base64 = base64;
            this.width = width;
            this.height = height;
            this.textureFormat = textureFormat;
            this.isMipMap = isMipMap;

        }
    }
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值