378 lines
11 KiB
C#
378 lines
11 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
namespace UltimateGameTools
|
|
{
|
|
namespace MeshSimplifier
|
|
{
|
|
/// <summary>
|
|
/// Class that will take a Mesh as input and will build internal data to identify which vertices are repeated due to
|
|
/// different vertex data (UV, vertex colors etc).
|
|
/// </summary>
|
|
[Serializable]
|
|
public class MeshUniqueVertices
|
|
{
|
|
#region Public types
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Public types
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <summary>
|
|
/// A list of vertex indices. We use this in order to be able to serialize a list of lists.
|
|
/// </summary>
|
|
[Serializable]
|
|
public class ListIndices
|
|
{
|
|
public ListIndices()
|
|
{
|
|
m_listIndices = new List<int>();
|
|
}
|
|
|
|
public List<int> m_listIndices;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Our serializable version of Unity's BoneWeight
|
|
/// </summary>
|
|
[Serializable]
|
|
public class SerializableBoneWeight
|
|
{
|
|
public SerializableBoneWeight(BoneWeight boneWeight)
|
|
{
|
|
_boneIndex0 = boneWeight.boneIndex0;
|
|
_boneIndex1 = boneWeight.boneIndex1;
|
|
_boneIndex2 = boneWeight.boneIndex2;
|
|
_boneIndex3 = boneWeight.boneIndex3;
|
|
|
|
_boneWeight0 = boneWeight.weight0;
|
|
_boneWeight1 = boneWeight.weight1;
|
|
_boneWeight2 = boneWeight.weight2;
|
|
_boneWeight3 = boneWeight.weight3;
|
|
}
|
|
|
|
public BoneWeight ToBoneWeight()
|
|
{
|
|
BoneWeight boneWeight = new BoneWeight();
|
|
|
|
boneWeight.boneIndex0 = _boneIndex0;
|
|
boneWeight.boneIndex1 = _boneIndex1;
|
|
boneWeight.boneIndex2 = _boneIndex2;
|
|
boneWeight.boneIndex3 = _boneIndex3;
|
|
|
|
boneWeight.weight0 = _boneWeight0;
|
|
boneWeight.weight1 = _boneWeight1;
|
|
boneWeight.weight2 = _boneWeight2;
|
|
boneWeight.weight3 = _boneWeight3;
|
|
|
|
return boneWeight;
|
|
}
|
|
|
|
public int _boneIndex0;
|
|
public int _boneIndex1;
|
|
public int _boneIndex2;
|
|
public int _boneIndex3;
|
|
|
|
public float _boneWeight0;
|
|
public float _boneWeight1;
|
|
public float _boneWeight2;
|
|
public float _boneWeight3;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Vertex that is has a unique position in space.
|
|
/// </summary>
|
|
public class UniqueVertex
|
|
{
|
|
// Overrides from Object
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
UniqueVertex uniqueVertex = obj as UniqueVertex;
|
|
return (uniqueVertex.m_nFixedX == m_nFixedX) && (uniqueVertex.m_nFixedY == m_nFixedY) && (uniqueVertex.m_nFixedZ == m_nFixedZ);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return m_nFixedX + (m_nFixedY << 2) + (m_nFixedZ << 4);
|
|
}
|
|
|
|
// Constructor
|
|
|
|
public UniqueVertex(Vector3 v3Vertex)
|
|
{
|
|
FromVertex(v3Vertex);
|
|
}
|
|
|
|
// Public methods
|
|
|
|
public Vector3 ToVertex()
|
|
{
|
|
return new Vector3(FixedToCoord(m_nFixedX), FixedToCoord(m_nFixedY), FixedToCoord(m_nFixedZ));
|
|
}
|
|
|
|
// Comparison operators
|
|
|
|
public static bool operator ==(UniqueVertex a, UniqueVertex b)
|
|
{
|
|
return a.Equals(b);
|
|
}
|
|
|
|
public static bool operator !=(UniqueVertex a, UniqueVertex b)
|
|
{
|
|
return !a.Equals(b);
|
|
}
|
|
|
|
// Private methods/vars
|
|
|
|
private void FromVertex(Vector3 vertex)
|
|
{
|
|
m_nFixedX = CoordToFixed(vertex.x);
|
|
m_nFixedY = CoordToFixed(vertex.y);
|
|
m_nFixedZ = CoordToFixed(vertex.z);
|
|
}
|
|
|
|
private int CoordToFixed(float fCoord)
|
|
{
|
|
int nInteger = Mathf.FloorToInt(fCoord);
|
|
int nRemainder = Mathf.FloorToInt((fCoord - nInteger) * fDecimalMultiplier);
|
|
|
|
return nInteger << 16 | nRemainder;
|
|
}
|
|
|
|
private float FixedToCoord(int nFixed)
|
|
{
|
|
float fRemainder = (nFixed & 0xFFFF) / fDecimalMultiplier;
|
|
float fInteger = nFixed >> 16;
|
|
|
|
return fInteger + fRemainder;
|
|
}
|
|
|
|
// Private vars
|
|
|
|
private int m_nFixedX, m_nFixedY, m_nFixedZ;
|
|
private const float fDecimalMultiplier = 100000.0f;
|
|
}
|
|
|
|
#endregion
|
|
#region Public properties
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Public properties
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <summary>
|
|
/// For each submesh, a list of faces. ListIndices has 3 indices for each face.
|
|
/// Each index is a vertex in ListVertices.
|
|
/// </summary>
|
|
public ListIndices[] SubmeshesFaceList
|
|
{
|
|
get
|
|
{
|
|
return m_aFaceList;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Our list of vertices. Vertices are unique, so no vertex shares the same position in space.
|
|
/// </summary>
|
|
public List<Vector3> ListVertices
|
|
{
|
|
get
|
|
{
|
|
return m_listVertices;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Our list of vertices in world space.
|
|
/// Vertices are unique, so no vertex shares the same position in space.
|
|
/// </summary>
|
|
public List<Vector3> ListVerticesWorld
|
|
{
|
|
get
|
|
{
|
|
return m_listVerticesWorld;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Our list of vertex bone weights
|
|
/// </summary>
|
|
public List<SerializableBoneWeight> ListBoneWeights
|
|
{
|
|
get
|
|
{
|
|
return m_listBoneWeights;
|
|
}
|
|
}
|
|
|
|
#endregion // Public properties
|
|
#region Public methods
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Public methods
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <summary>
|
|
/// Takes a Mesh as input and will build a new list of faces and vertices. The vertex list will
|
|
/// have no vertices sharing position in 3D space. The input mesh may have them, since often
|
|
/// a vertex will have different mapping coordinates for each of the faces that share it.
|
|
/// </summary>
|
|
/// <param name="sourceMesh"></param>
|
|
/// <param name="av3VerticesWorld"</param>
|
|
public void BuildData(Mesh sourceMesh, Vector3[] av3VerticesWorld)
|
|
{
|
|
Vector3[] av3Vertices = sourceMesh.vertices;
|
|
BoneWeight[] aBoneWeights = sourceMesh.boneWeights;
|
|
|
|
Dictionary<UniqueVertex, RepeatedVertexList> dicUniqueVertex2RepeatedVertexList = new Dictionary<UniqueVertex, RepeatedVertexList>();
|
|
|
|
m_listVertices = new List<Vector3>();
|
|
m_listVerticesWorld = new List<Vector3>();
|
|
m_listBoneWeights = new List<SerializableBoneWeight>();
|
|
m_aFaceList = new ListIndices[sourceMesh.subMeshCount];
|
|
|
|
for (int nSubMesh = 0; nSubMesh < sourceMesh.subMeshCount; nSubMesh++)
|
|
{
|
|
m_aFaceList[nSubMesh] = new ListIndices();
|
|
int[] anFaces = sourceMesh.GetTriangles(nSubMesh); //索引
|
|
|
|
for (int i = 0; i < anFaces.Length; i++)
|
|
{
|
|
UniqueVertex vertex = new UniqueVertex(av3Vertices[anFaces[i]]);
|
|
|
|
if (dicUniqueVertex2RepeatedVertexList.ContainsKey(vertex))
|
|
{
|
|
dicUniqueVertex2RepeatedVertexList[vertex].Add(new RepeatedVertex(i / 3, anFaces[i]));
|
|
m_aFaceList[nSubMesh].m_listIndices.Add(dicUniqueVertex2RepeatedVertexList[vertex].UniqueIndex);
|
|
}
|
|
else
|
|
{
|
|
int nNewUniqueIndex = m_listVertices.Count;
|
|
dicUniqueVertex2RepeatedVertexList.Add(vertex, new RepeatedVertexList(nNewUniqueIndex, new RepeatedVertex(i / 3, anFaces[i])));
|
|
m_listVertices.Add(av3Vertices[anFaces[i]]);
|
|
m_listVerticesWorld.Add(av3VerticesWorld[anFaces[i]]);
|
|
m_aFaceList[nSubMesh].m_listIndices.Add(nNewUniqueIndex);
|
|
|
|
if(aBoneWeights != null && aBoneWeights.Length > 0)
|
|
{
|
|
m_listBoneWeights.Add(new SerializableBoneWeight(aBoneWeights[anFaces[i]]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug.Log("In: " + av3Vertices.Length + " vertices. Out: " + m_listVertices.Count + " vertices.");
|
|
}
|
|
|
|
#endregion // Public methods
|
|
#region Private types
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Private types
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <summary>
|
|
/// Vertex that has the same position in space as another one, but different vertex data (UV, color...).
|
|
/// </summary>
|
|
private class RepeatedVertex
|
|
{
|
|
// Public properties
|
|
|
|
/// <summary>
|
|
/// Face it belongs to. This will be the same index in the source mesh as in the internal created face list.
|
|
/// </summary>
|
|
public int FaceIndex
|
|
{
|
|
get
|
|
{
|
|
return _nFaceIndex;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Position in the original vertex array.
|
|
/// </summary>
|
|
public int OriginalVertexIndex
|
|
{
|
|
get
|
|
{
|
|
return _nOriginalVertexIndex;
|
|
}
|
|
}
|
|
|
|
// Constructor
|
|
|
|
public RepeatedVertex(int nFaceIndex, int nOriginalVertexIndex)
|
|
{
|
|
_nFaceIndex = nFaceIndex;
|
|
_nOriginalVertexIndex = nOriginalVertexIndex;
|
|
}
|
|
|
|
// Private vars
|
|
|
|
private int _nFaceIndex;
|
|
private int _nOriginalVertexIndex;
|
|
}
|
|
|
|
/// <summary>
|
|
/// List of vertices that have the same position in space but different vertex data (UV, color...).
|
|
/// </summary>
|
|
private class RepeatedVertexList
|
|
{
|
|
// Public properties
|
|
|
|
/// <summary>
|
|
/// Unique vertex index in our array for this list.
|
|
/// </summary>
|
|
public int UniqueIndex
|
|
{
|
|
get
|
|
{
|
|
return m_nUniqueIndex;
|
|
}
|
|
}
|
|
|
|
// Public methods
|
|
|
|
public RepeatedVertexList(int nUniqueIndex, RepeatedVertex repeatedVertex)
|
|
{
|
|
m_nUniqueIndex = nUniqueIndex;
|
|
m_listRepeatedVertices = new List<RepeatedVertex>();
|
|
m_listRepeatedVertices.Add(repeatedVertex);
|
|
}
|
|
|
|
public void Add(RepeatedVertex repeatedVertex)
|
|
{
|
|
m_listRepeatedVertices.Add(repeatedVertex);
|
|
}
|
|
|
|
// Private vars
|
|
|
|
private int m_nUniqueIndex;
|
|
private List<RepeatedVertex> m_listRepeatedVertices;
|
|
}
|
|
|
|
#endregion // Private types
|
|
#region Private vars
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Private vars
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
[SerializeField]
|
|
private List<Vector3> m_listVertices;
|
|
[SerializeField]
|
|
private List<Vector3> m_listVerticesWorld;
|
|
[SerializeField]
|
|
private List<SerializableBoneWeight> m_listBoneWeights;
|
|
[SerializeField]
|
|
private ListIndices[] m_aFaceList;
|
|
|
|
#endregion // Private vars
|
|
}
|
|
}
|
|
} |