273 lines
8.7 KiB
C#
273 lines
8.7 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// 把Mesh中的面进行排序,用于处理单个Mesh中alpha渲染的问题
|
|
/// 这个适用于哪些用几块互相独立的面片制作的,用于2D展示的动画模型.
|
|
/// 1.Mesh的不要由SubMesh.
|
|
/// 2.Matrial只有一个
|
|
/// </summary>
|
|
public class AlphaMeshSortScript : MonoBehaviour
|
|
{
|
|
//精度值
|
|
private const int CN_PRECISION_VALUE = 1000;
|
|
private Mesh _oldMesh;
|
|
private Mesh _newMesh;
|
|
private SkinnedMeshRenderer _render;
|
|
private SortedDictionary<int, SubMeshInfo> _newTrisData;
|
|
//0:x,1:y,2:z
|
|
[Header("使用模型坐标系的哪个坐标轴进行排序.(0:X,1:Y,2:Z)")]
|
|
[Range(0, 2)]
|
|
public int _useAxis = 1;
|
|
|
|
//是否优化
|
|
public bool _useOptimize = true;
|
|
|
|
private void OnEnable()
|
|
{
|
|
Restore();
|
|
if (_render != null && _render.sharedMesh != null)
|
|
{
|
|
_oldMesh = _render.sharedMesh;
|
|
CreateNewMesh();
|
|
if (_newMesh != null)
|
|
{
|
|
_render.sharedMesh = _newMesh;
|
|
var mats = new Material[_newMesh.subMeshCount];
|
|
for (int i = 0; i < mats.Length; i++) mats[i] = _render.sharedMaterial;
|
|
_render.sharedMaterials = mats;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
Restore();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
Restore();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 把所有处理恢复
|
|
/// </summary>
|
|
private void Restore()
|
|
{
|
|
_render = GetComponent<SkinnedMeshRenderer>();
|
|
if (_oldMesh != null && _render != null)
|
|
{
|
|
_render.sharedMesh = _oldMesh;
|
|
_render.sharedMaterials = new Material[] { _render.sharedMaterial };
|
|
_oldMesh = null;
|
|
_render = null;
|
|
}
|
|
|
|
if (_newMesh != null)
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
GameObject.Destroy(_newMesh);
|
|
}
|
|
else
|
|
{
|
|
GameObject.DestroyImmediate(_newMesh);
|
|
}
|
|
_newMesh = null;
|
|
}
|
|
}
|
|
|
|
private void CreateNewMesh()
|
|
{
|
|
if (_oldMesh != null)
|
|
{
|
|
var vs = _oldMesh.vertices;
|
|
var tris = _oldMesh.triangles;
|
|
//对使用坐标轴进行排序进行一些矫正
|
|
if (_useAxis < 0) _useAxis = 0;
|
|
else if (_useAxis > 2) _useAxis = 2;
|
|
|
|
//根据顶点位置进行分组
|
|
|
|
_newTrisData = new SortedDictionary<int, SubMeshInfo>(KeyComparer.Default);
|
|
List<int> verKeyList = new List<int>();
|
|
|
|
for (int i = 0; i < vs.Length; i++)
|
|
{
|
|
int k = Mathf.RoundToInt(vs[i][_useAxis] * CN_PRECISION_VALUE);
|
|
verKeyList.Add(k);
|
|
if (!_newTrisData.ContainsKey(k))
|
|
{
|
|
_newTrisData[k] = new SubMeshInfo(k,vs);
|
|
}
|
|
}
|
|
|
|
//对所有的面进行组合
|
|
for (int i = 0; i < tris.Length; i += 3)
|
|
{
|
|
var v1 = verKeyList[tris[i]];
|
|
var v2 = verKeyList[tris[i + 1]];
|
|
var v3 = verKeyList[tris[i + 2]];
|
|
|
|
if (v1 == v2 && v2 == v3)
|
|
{
|
|
_newTrisData[v1].Indexes.Add(tris[i]);
|
|
_newTrisData[v1].Indexes.Add(tris[i + 1]);
|
|
_newTrisData[v1].Indexes.Add(tris[i + 2]);
|
|
}
|
|
}
|
|
|
|
|
|
//Debug.Log("111111111111111111数量:"+ _newTrisData.Count);
|
|
if (_useOptimize)
|
|
{
|
|
//把哪些相邻的不想交的mesh合并起来
|
|
int[] keys = new int[_newTrisData.Count];
|
|
_newTrisData.Keys.CopyTo(keys, 0);
|
|
int lastKey = -9999999;
|
|
for (int i = 0; i < keys.Length; i++)
|
|
{
|
|
var cuValue = _newTrisData[keys[i]];
|
|
cuValue.CalcBounds(_useAxis);
|
|
if (lastKey != -9999999)
|
|
{
|
|
if (!cuValue.IsIntersect(_newTrisData[lastKey]))
|
|
{
|
|
cuValue.Indexes.AddRange(_newTrisData[lastKey].Indexes);
|
|
_newTrisData.Remove(lastKey);
|
|
cuValue.CalcBounds(_useAxis);
|
|
//Debug.Log("AAAAAAAAAAAAAAAAAAAAAAAAA");
|
|
}
|
|
}
|
|
lastKey = keys[i];
|
|
}
|
|
//Debug.Log("222222222222222222数量:" + _newTrisData.Count);
|
|
}
|
|
else
|
|
{
|
|
var e1 = _newTrisData.GetEnumerator();
|
|
while (e1.MoveNext())
|
|
{
|
|
e1.Current.Value.CalcBounds(_useAxis);
|
|
}
|
|
|
|
}
|
|
if (_newTrisData.Count > 20)
|
|
{
|
|
Debug.LogError("创建新的NewMesh失败,原因是创建的SubMesh太多[" + _newTrisData.Count + "],请检查选用的坐标轴是否正确!");
|
|
return;
|
|
}
|
|
|
|
_newMesh = new Mesh();
|
|
_newMesh.hideFlags = HideFlags.DontSave;
|
|
_newMesh.name = _oldMesh.name + "_AlphaSort";
|
|
_newMesh.vertices = vs;
|
|
_newMesh.uv = _oldMesh.uv;
|
|
_newMesh.uv2 = _oldMesh.uv2;
|
|
_newMesh.normals = _oldMesh.normals;
|
|
_newMesh.tangents = _oldMesh.tangents;
|
|
_newMesh.boneWeights = _oldMesh.boneWeights;
|
|
_newMesh.bindposes = _oldMesh.bindposes;
|
|
_newMesh.triangles = new int[0];
|
|
|
|
_newMesh.subMeshCount = _newTrisData.Count;
|
|
int idx = 0;
|
|
var e = _newTrisData.GetEnumerator();
|
|
while (e.MoveNext())
|
|
{
|
|
_newMesh.SetTriangles(e.Current.Value.Indexes, idx);
|
|
idx++;
|
|
}
|
|
_newMesh.RecalculateBounds();
|
|
}
|
|
}
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
if (_newTrisData != null)
|
|
{
|
|
var e = _newTrisData.GetEnumerator();
|
|
while (e.MoveNext())
|
|
{
|
|
e.Current.Value.Draw(transform);
|
|
}
|
|
}
|
|
}
|
|
|
|
#region //私有类
|
|
//比较的算子类
|
|
private class KeyComparer : IComparer<int>
|
|
{
|
|
public static KeyComparer Default = new KeyComparer();
|
|
public int Compare(int x, int y)
|
|
{
|
|
return y - x;
|
|
}
|
|
}
|
|
//子Mesh的数据
|
|
private class SubMeshInfo
|
|
{
|
|
public int Key = 0;
|
|
public List<int> Indexes;
|
|
|
|
private Vector2 _minPoint;
|
|
private Vector2 _maxPoint;
|
|
private Vector3[] _allVs;
|
|
|
|
public SubMeshInfo(int k,Vector3[] vs)
|
|
{
|
|
Key = k;
|
|
Indexes = new List<int>();
|
|
_allVs = vs;
|
|
}
|
|
|
|
public void CalcBounds(int excludeIdx)
|
|
{
|
|
var arr = excludeIdx == 0 ? new int[] { 1, 2 } : (excludeIdx == 1 ? new int[] { 0, 2 } : new int[] { 0, 1 });
|
|
_minPoint = Vector2.zero;
|
|
_maxPoint = Vector2.zero;
|
|
for (int i = 0; i < Indexes.Count;i++)
|
|
{
|
|
var v = _allVs[Indexes[i]];
|
|
if (_minPoint.x > v[arr[0]]) _minPoint.x = v[arr[0]];
|
|
if (_maxPoint.x < v[arr[0]]) _maxPoint.x = v[arr[0]];
|
|
if (_minPoint.y > v[arr[1]]) _minPoint.y = v[arr[1]];
|
|
if (_maxPoint.y < v[arr[1]]) _maxPoint.y = v[arr[1]];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public bool IsIntersect(SubMeshInfo mi)
|
|
{
|
|
//Debug.LogError("self:" + _maxPoint + ":::" + _minPoint + "::mi:" + mi._maxPoint + "::" + mi._minPoint);
|
|
var v1 = _maxPoint - mi._minPoint;
|
|
var v2 = mi._maxPoint - _minPoint;
|
|
// Debug.Log("v1:" + v1 + ";;;v2" + v2);
|
|
var min = Mathf.Min(v1.x, v1.y, v2.x, v2.y);
|
|
//当min小于0的时候,就表示两个面不相交.
|
|
return min > 0;
|
|
}
|
|
|
|
public void Draw(Transform trans)
|
|
{
|
|
var y = (float)Key / (float)CN_PRECISION_VALUE;
|
|
var v1 = trans.localToWorldMatrix.MultiplyPoint(new Vector3(_maxPoint.x, y, _maxPoint.y));
|
|
var v2 = trans.localToWorldMatrix.MultiplyPoint(new Vector3(_maxPoint.x, y, _minPoint.y));
|
|
var v3 = trans.localToWorldMatrix.MultiplyPoint(new Vector3(_minPoint.x, y, _minPoint.y));
|
|
var v4 = trans.localToWorldMatrix.MultiplyPoint(new Vector3(_minPoint.x, y, _maxPoint.y));
|
|
Gizmos.color = new Color(Random.Range(0, 1), Random.Range(0, 1), Random.Range(0, 1));
|
|
Gizmos.DrawLine(v1, v2);
|
|
Gizmos.DrawLine(v2, v3);
|
|
Gizmos.DrawLine(v3, v4);
|
|
Gizmos.DrawLine(v4, v1);
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
|
|
}
|