Unity 保存自定义模型数据

自定义数据

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


namespace Custom
{
    [Serializable]
    public class CustomAvatarData
    {
        [Serializable]
        public class MeshData
        {
            public Vector3[] meshVertices;
            public Vector2[] meshUV;
            public int[] meshTriangles;
            public BoneWeight[] meshBoneWeight;
            public int subMeshCount;
            public List<string> meshBonesName = new List<string>();
            public int meshMaterialCount;
            public Matrix4x4[] meshBindPoses;
            public Bounds meshBounds;
            public Vector3[] meshNormals;
            public Vector4[] meshTangents;
        }

        [Serializable]
        public class SkeletonData
        {
            public CustomTransform current;
            public List<string> children = new List<string>();
        }


        [Serializable]
        public class CustomTransform
        {
            public string nodeName;
            public Vector3 position;
            public Quaternion rotation;
        }

        [Serializable]
        public enum Gender
        {
            male,
            female,
        }

        [Serializable]
        public class CustomSkindMeshData
        {
            public Gender gender;
            public MeshData meshData = new MeshData();
            public string SkeletonRoot;
            public List<SkeletonData> skeletonDatas = new List<SkeletonData>();
            public string mainTextureBase64;
            public string normalTextureBase64;
        }
    }
}

保存模型数据

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;

namespace Custom
{
    public class SaveAvatar : MonoBehaviour
    {
        public GameObject root;
        public Material matTemp;
        public string avatarName;
        public CustomAvatarData.Gender gender;

        //public GameObject[] bon;

        // Start is called before the first frame update
        void Start()
        {

            

        }

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.S))
            {
                SaveFunc();
            }
        }

        [ContextMenu("SaveFunc")]
        public void SaveFunc()
        {
            var skMesh = CombineSuitsToSkeleton(root, root.GetComponentsInChildren<SkinnedMeshRenderer>());

            CustomAvatarData.CustomSkindMeshData customSkindMeshData = new CustomAvatarData.CustomSkindMeshData();
            customSkindMeshData.gender = this.gender;

            CustomAvatarData.MeshData meshData = new CustomAvatarData.MeshData();
            meshData.meshVertices = skMesh.sharedMesh.vertices;
            meshData.meshTriangles = skMesh.sharedMesh.triangles;
            meshData.meshUV = skMesh.sharedMesh.uv;
            meshData.meshBoneWeight = skMesh.sharedMesh.boneWeights;
            meshData.subMeshCount = skMesh.sharedMesh.subMeshCount;
            foreach (var item in skMesh.bones)
            {
                meshData.meshBonesName.Add(item.gameObject.name);
            }

            meshData.meshMaterialCount = skMesh.sharedMaterials.Length;
            meshData.meshBindPoses = skMesh.sharedMesh.bindposes;
            meshData.meshBounds = skMesh.sharedMesh.bounds;
            meshData.meshNormals = skMesh.sharedMesh.normals;
            meshData.meshTangents = skMesh.sharedMesh.tangents;

            customSkindMeshData.meshData = meshData;

            Texture2D tex = new Texture2D(skMesh.material.mainTexture.width, skMesh.material.mainTexture.height);
            tex = skMesh.material.mainTexture as Texture2D;
            customSkindMeshData.mainTextureBase64 = System.Convert.ToBase64String(tex.EncodeToJPG());
            customSkindMeshData.normalTextureBase64 = System.Convert.ToBase64String((skMesh.material.GetTexture("_BumpMap")as Texture2D).EncodeToJPG());

            for (int i = 0; i < root.transform.childCount; i++)
            {
                if (root.transform.GetChild(i).GetComponent<SkinnedMeshRenderer>())
                {
                    continue;
                }

                var trans = root.transform.GetChild(i).GetComponent<Transform>();

                customSkindMeshData.SkeletonRoot = trans.gameObject.name;


                GetChildInfo(trans, customSkindMeshData);
            }

            //customSkindMeshData.skeletonData.tree.Traverse(customSkindMeshData.skeletonData.tree.Root);

            var json = JsonUtility.ToJson(customSkindMeshData);

            print(Application.dataPath + "/" + avatarName + ".json");

            //File.WriteAllText(Application.dataPath + "/AvatarData/" + avatarName + ".json", json);

            File.WriteAllBytes(Application.dataPath + "/AvatarData/" + avatarName + ".customModel", Encoding.UTF8.GetBytes(json));

            print("Save");
            var skr = gameObject.GetComponent<SkinnedMeshRenderer>();
            if (skr)
            {
                Destroy(skr);
            }
        }


        private void GetChildInfo(Transform trans, CustomAvatarData.CustomSkindMeshData _customSkindMeshData)
        {
            CustomAvatarData.SkeletonData skeleton = new CustomAvatarData.SkeletonData();
            CustomAvatarData.CustomTransform custom = new CustomAvatarData.CustomTransform();
            custom.nodeName = trans.gameObject.name;
            custom.position = trans.localPosition;
            custom.rotation = trans.localRotation;
            skeleton.current = custom;
            for (int i = 0; i < trans.childCount; i++)
            {
                var t = trans.GetChild(i);
                skeleton.children.Add(t.gameObject.name);

                GetChildInfo(t, _customSkindMeshData);
            }

            _customSkindMeshData.skeletonDatas.Add(skeleton);
        }


        SkinnedMeshRenderer CombineSuitsToSkeleton(GameObject skeleton, SkinnedMeshRenderer[] meshes)
        {
            var transforms = new List<Transform>(skeleton.GetComponentsInChildren<Transform>(true));

            var materials = new List<Material>();

            var combineInstances = new List<CombineInstance>();

            var bones = new List<Transform>();


            foreach (SkinnedMeshRenderer smr in meshes)
            {
                materials.AddRange(smr.materials);
                for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++)
                {
                    CombineInstance ci = new CombineInstance();
                    ci.mesh = smr.sharedMesh;
                    ci.subMeshIndex = sub;
                    combineInstances.Add(ci);
                }
                foreach (Transform b in smr.bones)
                {
                    var t = transforms.Find(t => b.name.Equals(t.name));
                    if (t != null)
                    {
                        bones.Add(t);
                    }
                }
            }

            var newMaterial = Instantiate(matTemp);
            var oldUV = new List<Vector2[]>();
            // merge the texture
            var Textures = new List<Texture2D>();
            var normals = new List<Texture2D>();
            foreach (Material m in materials)
            {
                var _tex = m.GetTexture("baseColorTexture") as Texture2D;
                var _text2 = ConvertTexture(_tex);
                Textures.Add(_text2);
                var _tex_n = m.GetTexture("normalTexture") as Texture2D;
               
                if (_tex_n)
                {
                    Texture2D texture2D = new Texture2D(_tex_n.width, _tex_n.height, _tex_n.format, false);
                    //texture2D.SetPixels(normal.GetPixels());
                    Graphics.CopyTexture(_tex_n, texture2D);
                    //File.WriteAllBytes(Application.dataPath + "/" + texture2D.GetInstanceID() + ".png", texture2D.EncodeToPNG());
                    normals.Add(texture2D);
                }
          
               
            }

            Texture2D newDiffuseTex = new Texture2D(512, 512, TextureFormat.RGBA32, true);
            Rect[] uvs = newDiffuseTex.PackTextures(Textures.ToArray(), 0);
            newMaterial.mainTexture = newDiffuseTex;
            newMaterial.EnableKeyword("_SPECULARHIGHLIGHTS_OFF");
            newMaterial.SetFloat("_SpecularHighlights", 0f);

            Texture2D newNormal = new Texture2D(512, 512, TextureFormat.RGBA32, true);
            newNormal.PackTextures(normals.ToArray(), 0);
            newMaterial.SetTexture("_BumpMap", newNormal);

            // reset uv
            Vector2[] uva, uvb;
            for (int j = 0; j < combineInstances.Count; j++)
            {
                uva = (Vector2[])(combineInstances[j].mesh.uv);
                uvb = new Vector2[uva.Length];
                for (int k = 0; k < uva.Length; k++)
                {
                    uvb[k] = new Vector2((uva[k].x * uvs[j].width) + uvs[j].x, (uva[k].y * uvs[j].height) + uvs[j].y);
                }
                oldUV.Add(combineInstances[j].mesh.uv);
                combineInstances[j].mesh.uv = uvb;
            }

            var r = gameObject.AddComponent<SkinnedMeshRenderer>() ?? gameObject.GetComponent<SkinnedMeshRenderer>();
            r.bones = bones.ToArray();
            r.sharedMesh = new Mesh();
            r.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false);
            r.material = newMaterial;

            return r;
        }

        private Texture2D ConvertTexture(Texture2D source)
        {
            byte[] pix = source.GetRawTextureData();
            Texture2D readableText = new Texture2D(source.width, source.height, source.format, false);
            readableText.LoadRawTextureData(pix);
            readableText.Apply();
            return readableText;
        }
    }
}

加载模型数据

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

namespace Custom
{
    public class LoadAvatar : MonoBehaviour
    {

        public RuntimeAnimatorController animatorController;
        public Avatar avatarMale;
        public Avatar avatarFemale;
        public Material matTemp;
        public string avatarName;

        // Start is called before the first frame update
        void Start()
        {
            StartCoroutine(GetRequest("http://192.168.1.112:9666/MyAvatar3.customModel"));
        }

        // Update is called once per frame
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.L))
            {
                List<CustomAvatarData.MeshData> ml = new List<CustomAvatarData.MeshData>();

                //var json = File.ReadAllText(Application.dataPath + "/AvatarData/" + avatarName + ".json");
                var json = File.ReadAllBytes(Application.dataPath + "/AvatarData/" + avatarName + ".customModel");
                var jObject = JsonUtility.FromJson<CustomAvatarData.CustomSkindMeshData>(Encoding.UTF8.GetString(json));

                GenerateChildren(jObject.SkeletonRoot, jObject.skeletonDatas, transform);

                var anim = gameObject.AddComponent<Animator>();
                anim.runtimeAnimatorController = animatorController;
                if (jObject.gender.Equals(CustomAvatarData.Gender.male))
                {
                    anim.avatar = avatarMale;
                }
                else
                {
                    anim.avatar = avatarFemale;
                }


                ml.Add(jObject.meshData);
                CombineSuitsToSkeleton(this.gameObject, ml.ToArray(), jObject.mainTextureBase64, jObject.normalTextureBase64);
            }
        }


        IEnumerator GetRequest(string uri)
        {
            using (UnityWebRequest webRequest = UnityWebRequest.Get(uri))
            {
                // Request and wait for the desired page.
                yield return webRequest.SendWebRequest();

                string[] pages = uri.Split('/');
                int page = pages.Length - 1;

                switch (webRequest.result)
                {
                    case UnityWebRequest.Result.ConnectionError:
                    case UnityWebRequest.Result.DataProcessingError:
                        Debug.LogError(pages[page] + ": Error: " + webRequest.error);
                        break;
                    case UnityWebRequest.Result.ProtocolError:
                        Debug.LogError(pages[page] + ": HTTP Error: " + webRequest.error);
                        break;
                    case UnityWebRequest.Result.Success:
                        Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.data);

                        List<CustomAvatarData.MeshData> ml = new List<CustomAvatarData.MeshData>();

                        var jObject = JsonUtility.FromJson<CustomAvatarData.CustomSkindMeshData>(Encoding.UTF8.GetString(webRequest.downloadHandler.data));

                        GenerateChildren(jObject.SkeletonRoot, jObject.skeletonDatas, transform);

                        var anim = gameObject.AddComponent<Animator>();
                        anim.runtimeAnimatorController = animatorController;
                        if (jObject.gender.Equals(CustomAvatarData.Gender.male))
                        {
                            anim.avatar = avatarMale;
                        }
                        else
                        {
                            anim.avatar = avatarFemale;
                        }


                        ml.Add(jObject.meshData);
                        CombineSuitsToSkeleton(this.gameObject, ml.ToArray(), jObject.mainTextureBase64, jObject.normalTextureBase64);
                        break;
                }
            }
        }

        private void GenerateChildren(string currentName, List<CustomAvatarData.SkeletonData> _skeletonDatas, Transform _parent)
        {
            foreach (var skeleton in _skeletonDatas)
            {
                if (skeleton.current.nodeName.Equals(currentName))
                {
                    GameObject newGameObject = new GameObject(currentName);
                    newGameObject.transform.SetParent(_parent);
                    newGameObject.transform.localPosition = skeleton.current.position;
                    newGameObject.transform.localRotation = skeleton.current.rotation;

                    foreach (var child in skeleton.children)
                    {
                        foreach (var skeleton2 in _skeletonDatas)
                        {
                            if (skeleton2.current.nodeName.Equals(child))
                            {
                                GenerateChildren(skeleton2.current.nodeName, _skeletonDatas, newGameObject.transform);
                            }
                        }
                    }

                    break;
                }
            }
        }

        private SkinnedMeshRenderer CombineSuitsToSkeleton(GameObject skeleton, CustomAvatarData.MeshData[] meshes, string txtureBase64,string nomalBase64)
        {
            var transforms = new List<Transform>(skeleton.GetComponentsInChildren<Transform>(true));

            var materials = new List<Material>();

            var combineInstances = new List<CombineInstance>();

            var bones = new List<Transform>();


            foreach (var smr in meshes)
            {
                List<Material> mats = new List<Material>();
                for (int i = 0; i < smr.meshMaterialCount; i++)
                {
                    Material mat = Instantiate(matTemp);
                    Texture2D texture = new Texture2D(2, 2);
                    texture.LoadImage(Convert.FromBase64String(txtureBase64));
                    Texture2D normal = new Texture2D(2, 2);
                    print(nomalBase64);
                    normal.LoadImage(Convert.FromBase64String(nomalBase64));
                    mat.mainTexture = texture;
                    mat.SetTexture("_BumpMap", normal);
                    mats.Add(mat);
                }

                materials.AddRange(mats);

                for (int sub = 0; sub < smr.subMeshCount; sub++)
                {
                    Mesh ms = new Mesh();
                    ms.vertices = smr.meshVertices;
                    ms.triangles = smr.meshTriangles;
                    ms.boneWeights = smr.meshBoneWeight;
                    ms.uv = smr.meshUV;
                    ms.bindposes = smr.meshBindPoses;
                    ms.bounds = smr.meshBounds;
                    ms.normals = smr.meshNormals;
                    ms.tangents = smr.meshTangents;

                    CombineInstance ci = new CombineInstance();
                    ci.mesh = ms;
                    ci.subMeshIndex = sub;
                    combineInstances.Add(ci);
                }
                foreach (var b in smr.meshBonesName)
                {
                    var t = transforms.Find(t => b.Equals(t.name));
                    if (t != null)
                    {
                        bones.Add(t);
                    }
                }
            }

            print(materials.Count);

            var newMaterial = Instantiate(matTemp);
            var oldUV = new List<Vector2[]>();
            // merge the texture
            var Textures = new List<Texture2D>();
            var normals = new List<Texture2D>();
            foreach (Material m in materials)
            {
                Textures.Add(m.GetTexture("_MainTex") as Texture2D);
                normals.Add(m.GetTexture("_BumpMap") as Texture2D);
            }

            Texture2D newDiffuseTex = new Texture2D(512, 512, TextureFormat.RGBA32, true);
            Rect[] uvs = newDiffuseTex.PackTextures(Textures.ToArray(), 0);
            newMaterial.mainTexture = newDiffuseTex;
            newMaterial.EnableKeyword("_SPECULARHIGHLIGHTS_OFF");
            newMaterial.SetFloat("_SpecularHighlights", 0f);

            Texture2D normalTex = new Texture2D(512, 512, TextureFormat.RGBA32, true);
            normalTex.PackTextures(normals.ToArray(), 0);
            newMaterial.SetTexture("_BumpMap", normalTex);

            // reset uv
            Vector2[] uva, uvb;
            for (int j = 0; j < combineInstances.Count; j++)
            {
                uva = (Vector2[])(combineInstances[j].mesh.uv);
                uvb = new Vector2[uva.Length];
                for (int k = 0; k < uva.Length; k++)
                {
                    uvb[k] = new Vector2((uva[k].x * uvs[j].width) + uvs[j].x, (uva[k].y * uvs[j].height) + uvs[j].y);
                }
                oldUV.Add(combineInstances[j].mesh.uv);
                combineInstances[j].mesh.uv = uvb;
            }

            var r = skeleton.AddComponent<SkinnedMeshRenderer>() ?? skeleton.GetComponent<SkinnedMeshRenderer>();
            r.bones = bones.ToArray();
            r.sharedMesh = new Mesh();
            r.sharedMesh.CombineMeshes(combineInstances.ToArray(), true, false);
            r.material = newMaterial;
            r.rootBone = transform.GetChild(0).GetChild(0);

            return r;
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值