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
}