166 lines
7.3 KiB
C#
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);
|
|
}
|
|
}
|
|
} |