Files
JJBB/Assets/Project/Script/Common/Utilities/Editor/ExtractSceneMeshes.cs
2024-08-23 15:49:34 +08:00

166 lines
7.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Module.Log;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
public class ExtractSceneMeshes
{
[MenuItem("Scene/Extract SceneMesh To SubMeshes")]
public static void Extract()
{
if (EditorUtility.DisplayDialog("逐一导出场景模型", "需要按当前位置逐个导出场景模型?", "确认", "取消"))
{
var vertices = new List<Vector3>();
var uv = new List<Vector2>();
var normal = new List<Vector3>();
var subMeshes = new Dictionary<Material, SubMeshInfo>();
var meshFilters = Object.FindObjectsOfType<MeshFilter>();
for (var i = 0; i < meshFilters.Length; i++)
{
var filter = meshFilters[i];
if (!filter.gameObject.activeInHierarchy)
{
}
else if (filter.sharedMesh == null)
{
LogModule.ErrorLog("Filter has no mesh " + filter.transform.GetHierarchyName());
}
else if (!filter.sharedMesh.isReadable)
{
LogModule.WarningLog("Mesh isn't readable " + filter.sharedMesh.name);
}
else
{
var renderer = filter.GetComponent<MeshRenderer>();
if (renderer == null)
LogModule.WarningLog("Unable to find renderer on " + filter.sharedMesh.name);
else
{
var start = vertices.Count;
// 添加顶点次序
var trs = Matrix4x4.TRS(filter.transform.position, filter.transform.rotation,
filter.transform.localScale);
var meshVertices = filter.sharedMesh.vertices;
var meshUv = filter.sharedMesh.uv;
var meshNormal = filter.sharedMesh.normals;
for (var j = 0; j < meshVertices.Length; j++)
vertices.Add(trs.MultiplyPoint3x4(meshVertices[j]));
for (var j = 0; j < meshNormal.Length; j++)
normal.Add(filter.transform.rotation * meshNormal[j]);
for (var j = 0; j < meshUv.Length; j++)
uv.Add(meshUv[j]);
for (var k = 0; k < filter.sharedMesh.subMeshCount; k++)
{
var matId = Mathf.Min(k, renderer.sharedMaterials.Length - 1);
var material = renderer.sharedMaterials[matId];
if (material != null)
{
SubMeshInfo subMesh;
if (!subMeshes.TryGetValue(material, out subMesh))
{
subMesh = new SubMeshInfo(material, subMeshes.Count);
subMeshes.Add(material, subMesh);
Debug.Log("Add Sub Mesh");
}
var meshTriangle = filter.sharedMesh.GetTriangles(k);
for (var j = 0; j < meshTriangle.Length; j++)
subMesh.AddPoint(meshTriangle[j] + start);
}
}
}
}
}
var sceneName = SceneManager.GetActiveScene().name;
if (string.IsNullOrEmpty(sceneName))
sceneName = "NewScene";
var path = Application.dataPath.MoveUp().Open("SceneMesh").Open(sceneName);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
var subMeshList = subMeshes.Values.ToList();
ObjExtract(vertices, uv, normal, subMeshList, path.Open("SceneMesh.obj"));
foreach (var subMesh in subMeshList)
{
var shader = subMesh.material.shader;
if (shader != null)
{
var texturePath = path.Open(subMesh.materialName);
if (!Directory.Exists(texturePath))
Directory.CreateDirectory(texturePath);
var count = ShaderUtil.GetPropertyCount(shader);
for (var i = 0; i < count; i++)
{
if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
{
var texture =
subMesh.material.GetTexture(ShaderUtil.GetPropertyName(shader, i)) as Texture2D;
if (texture)
{
AssetExtractor.ExtractTextureAtPath(texture, texturePath.Open(texture.name + ".png"));
}
}
}
}
}
AssetDatabase.Refresh();
LogModule.WarningLog("Mesh Exported at " + path);
}
}
public static void ObjExtract(IList<Vector3> vertices, IList<Vector2> uv, IList<Vector3> normal, IList<SubMeshInfo> triangleList, string path)
{
var builder = new StringBuilder();
var sceneName = Path.GetFileNameWithoutExtension(path);
builder.Append("#" + sceneName + ".obj"
+ "\n#" + DateTime.Now.ToLongDateString()
+ "\n#" + DateTime.Now.ToLongTimeString()
+ "\n#-------"
+ "\n\n");
builder.Append("g ").Append(sceneName).Append("\n");
builder.Append("#").Append(sceneName).Append("\n#-------").Append("\n");
foreach (var v in vertices)
builder.Append(string.Format("v {0} {1} {2}\n", -v.x, v.y, v.z));
builder.Append("\n");
foreach (var v in normal)
builder.Append(string.Format("vn {0} {1} {2}\n", -v.x, v.y, v.z));
builder.Append("\n");
foreach (var v in uv)
builder.Append(string.Format("vt {0} {1}\n", v.x, v.y));
foreach (var subMesh in triangleList)
{
builder.Append("\n");
builder.Append("usemtl ").Append(subMesh.materialName).Append("\n");
builder.Append("usemap ").Append(subMesh.materialName).Append("\n");
var triangles = subMesh.triangles;
for (var i = 0; i < triangles.Count; i += 3)
builder.Append(string.Format("f {0}/{0}/{0} {2}/{2}/{2} {1}/{1}/{1}\n",
triangles[i] + 1, triangles[i + 1] + 1, triangles[i + 2] + 1));
}
File.WriteAllText(path, builder.ToString());
}
public class SubMeshInfo
{
public Material material;
public string materialName;
public List<int> triangles;
public SubMeshInfo(Material material, int index)
{
this.material = material;
materialName = index.ToString().PadLeft(3, '0');
triangles = new List<int>();
}
public void AddPoint(int index)
{
triangles.Add(index);
}
}
}