模型数据自定义的保存与加载
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;
}
}
}