using System.Collections; using System.Collections.Generic; using UnityEngine; /// /// 把Mesh中的面进行排序,用于处理单个Mesh中alpha渲染的问题 /// 这个适用于哪些用几块互相独立的面片制作的,用于2D展示的动画模型. /// 1.Mesh的不要由SubMesh. /// 2.Matrial只有一个 /// public class AlphaMeshSortScript : MonoBehaviour { //精度值 private const int CN_PRECISION_VALUE = 1000; private Mesh _oldMesh; private Mesh _newMesh; private SkinnedMeshRenderer _render; private SortedDictionary _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(); } /// /// 把所有处理恢复 /// private void Restore() { _render = GetComponent(); 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(KeyComparer.Default); List verKeyList = new List(); 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 { 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 Indexes; private Vector2 _minPoint; private Vector2 _maxPoint; private Vector3[] _allVs; public SubMeshInfo(int k,Vector3[] vs) { Key = k; Indexes = new List(); _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 }