using System.Collections.Generic;
using Module.Log;
using UnityEngine;
using UnityEditor;
///
/// 用于将分散成多块的大模型,分解成小模型以减少顶点运算量
///
public static class LargeMeshSplit
{
public const float splitDistanceSqr = 1f * 1f;
[MenuItem("GameObject/Split Mesh", false, 16)]
public static void SplitMeshAndGameObject()
{
var gameObjects = Selection.gameObjects;
if (gameObjects.Length <= 0)
LogModule.ErrorLog("未选取GameObject!");
else
{
var targetList = new List();
for (var i = 0; i < gameObjects.Length; i++)
{
var list = EditorCommonUtility.GetGameObjects(gameObjects[i].transform);
for (var j = 0; j < list.Count; j++)
if (!targetList.Contains(list[j]))
targetList.Add(list[j]);
}
for (var i = 0; i < targetList.Count; i++)
{
var meshFilter = targetList[i].GetComponent();
if (meshFilter != null)
SplitForOneMeshRenderer(meshFilter);
}
}
}
public static void SplitForOneMeshRenderer(MeshFilter oldFilter)
{
var oldMesh = oldFilter.sharedMesh;
if (oldMesh.subMeshCount > 1)
LogModule.WarningLog(string.Format("{0}模型具有一个以上的SubMesh", oldFilter.gameObject.name));
else
{
var oldVerticles = oldMesh.vertices;
var triangleList = new List();
var trianglePoints = oldMesh.triangles;
for (var i = 0; i < trianglePoints.Length; i += 3)
{
var point0 = new PointRecord(trianglePoints[i], oldVerticles[trianglePoints[i]]);
var point1 = new PointRecord(trianglePoints[i + 1], oldVerticles[trianglePoints[i + 1]]);
var point2 = new PointRecord(trianglePoints[i + 2], oldVerticles[trianglePoints[i + 2]]);
var triangle = new TriangleRecord(point0, point1, point2);
triangleList.Add(triangle);
}
var meshList = new List();
var outerId = 0;
while (outerId < triangleList.Count)
{
// 添加每个区域的第一个三角形
var pointBlock = new MeshPointBlock();
meshList.Add(pointBlock);
pointBlock.triangleList.Add(triangleList[outerId]);
outerId++;
var innerId = outerId;
// 扫描同第一个三角形连接的全部三角形
while (innerId < triangleList.Count)
{
var innerTriangle = triangleList[innerId];
// 如果连接成功,则将面板提升到outerId位置,然后innerId从outerId下一个位置开始扫描
if (pointBlock.IsTriangleLinked(innerTriangle))
{
var temp = innerTriangle;
triangleList[innerId] = triangleList[outerId];
triangleList[outerId] = temp;
innerId = outerId;
outerId++;
pointBlock.triangleList.Add(innerTriangle);
}
innerId++;
}
}
if (meshList.Count < 2)
LogModule.DebugLog(string.Format("无需处理GameObject {0}", oldFilter.gameObject.name));
else
{
LogModule.WarningLog(string.Format("分解模型物体{0}为{1}份", oldFilter.gameObject.name, meshList.Count));
var oldUv = oldMesh.uv;
var oldNormals = oldMesh.normals;
var oldTangeant = oldMesh.tangents;
var oldRenderer = oldFilter.GetComponent();
for (var i = 0; i < meshList.Count; i++)
{
var pointBlock = meshList[i];
var pointReflections = pointBlock.GetPointReflections();
var mesh = new Mesh();
var verticles = new Vector3[pointReflections.Count];
var uv = new Vector2[pointReflections.Count];
var normals = new Vector3[pointReflections.Count];
// 注:模型可能没有Tangeant参数,因此特别处理
var tangeants = new Vector4[oldTangeant.Length > 0 ? pointReflections.Count : 0];
var triangles = new int[pointBlock.triangleList.Count * 3];
for (var j = 0; j < verticles.Length; j++)
{
var index = pointReflections[j];
verticles[j] = oldVerticles[index];
uv[j] = oldUv[index];
normals[j] = oldNormals[index];
if (tangeants.Length > 0)
tangeants[j] = oldTangeant[index];
}
for (var j = 0; j < pointBlock.triangleList.Count; j++)
{
var triangle = pointBlock.triangleList[j];
var index = j * 3;
triangles[index] = pointReflections.IndexOf(triangle.points[0].index);
triangles[index + 1] = pointReflections.IndexOf(triangle.points[1].index);
triangles[index + 2] = pointReflections.IndexOf(triangle.points[2].index);
}
mesh.vertices = verticles;
mesh.uv = uv;
mesh.normals = normals;
mesh.tangents = tangeants;
mesh.triangles = triangles;
var clone = new GameObject(oldFilter.gameObject.name + string.Format("_{0}", i));
var meshFilter = clone.AddComponent();
meshFilter.mesh = mesh;
var meshRenderer = clone.AddComponent();
meshRenderer.sharedMaterials = oldRenderer.sharedMaterials;
//meshRenderer.sharedMaterials = new Material[oldRenderer.sharedMaterials.Length];
//for (var j = 0; j < oldRenderer.sharedMaterials.Length; j++)
// meshRenderer.sharedMaterials[j] = oldRenderer.sharedMaterials[j];
meshRenderer.shadowCastingMode = oldRenderer.shadowCastingMode;
meshRenderer.receiveShadows = oldRenderer.receiveShadows;
clone.transform.SetParent(oldFilter.transform.parent, false);
clone.transform.localPosition = oldFilter.transform.localPosition;
clone.transform.localRotation = oldFilter.transform.localRotation;
clone.transform.localScale = oldFilter.transform.localScale;
}
oldFilter.gameObject.SetActive(false);
}
}
}
public class MeshPointBlock
{
public List triangleList;
public MeshPointBlock()
{
triangleList = new List();
}
public bool IsTriangleLinked(TriangleRecord other)
{
var result = false;
for (var i = 0; i < triangleList.Count; i++)
{
if (triangleList[i].IsTriangleLinked(other))
{
result = true;
break;
}
}
return result;
}
public List GetPointReflections()
{
// 映射新的顶点列表index到旧的顶点列表中
var pointList = new List();
for (var i = 0; i < triangleList.Count; i++)
{
var triangle = triangleList[i];
for (var j = 0; j < triangle.points.Length; j++)
{
if (pointList.IndexOf(triangle.points[j].index) < 0)
pointList.Add(triangle.points[j].index);
}
}
return pointList;
}
}
public class TriangleRecord
{
public readonly PointRecord[] points;
public TriangleRecord(PointRecord point0, PointRecord point1, PointRecord point2)
{
points = new PointRecord[3];
points[0] = point0;
points[1] = point1;
points[2] = point2;
}
public bool IsTriangleLinked(TriangleRecord other)
{
var result = false;
for (var i = 0; i < points.Length; i++)
{
for (var j = 0; j < other.points.Length; j++)
{
if (points[i].index == other.points[j].index ||
(points[i].position - other.points[j].position).sqrMagnitude < splitDistanceSqr)
{
result = true;
break;
}
}
if (result)
break;
}
return result;
}
}
public struct PointRecord
{
public readonly int index;
public readonly Vector3 position;
public PointRecord(int index, Vector3 position)
{
this.index = index;
this.position = position;
}
}
}