Files
2026-03-04 10:03:45 +08:00

1997 lines
48 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using MTAssets.UltimateLODSystem.MeshSimplifier.Internal;
using UnityEngine;
namespace MTAssets.UltimateLODSystem.MeshSimplifier
{
public sealed class MeshSimplifier
{
private const int TriangleEdgeCount = 3;
private const int TriangleVertexCount = 3;
private const double DoubleEpsilon = 0.001;
private const double DenomEpilson = 1E-08;
private static readonly int UVChannelCount = MeshUtils.UVChannelCount;
private SimplificationOptions simplificationOptions = SimplificationOptions.Default;
private bool verbose;
private int subMeshCount;
private int[] subMeshOffsets;
private ResizableArray<Triangle> triangles;
private ResizableArray<Vertex> vertices;
private ResizableArray<Ref> refs;
private ResizableArray<Vector3> vertNormals;
private ResizableArray<Vector4> vertTangents;
private UVChannels<Vector2> vertUV2D;
private UVChannels<Vector3> vertUV3D;
private UVChannels<Vector4> vertUV4D;
private ResizableArray<Color> vertColors;
private ResizableArray<BoneWeight> vertBoneWeights;
private ResizableArray<BlendShapeContainer> blendShapes;
private Matrix4x4[] bindposes;
private readonly double[] errArr = new double[3];
private readonly int[] attributeIndexArr = new int[3];
private readonly HashSet<Triangle> triangleHashSet1 = new HashSet<Triangle>();
private readonly HashSet<Triangle> triangleHashSet2 = new HashSet<Triangle>();
public SimplificationOptions SimplificationOptions
{
get
{
return simplificationOptions;
}
set
{
ValidateOptions(value);
simplificationOptions = value;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public bool PreserveBorderEdges
{
get
{
return simplificationOptions.PreserveBorderEdges;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.PreserveBorderEdges = value;
SimplificationOptions = simplificationOptions;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public bool PreserveUVSeamEdges
{
get
{
return simplificationOptions.PreserveUVSeamEdges;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.PreserveUVSeamEdges = value;
SimplificationOptions = simplificationOptions;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public bool PreserveUVFoldoverEdges
{
get
{
return simplificationOptions.PreserveUVFoldoverEdges;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.PreserveUVFoldoverEdges = value;
SimplificationOptions = simplificationOptions;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public bool PreserveSurfaceCurvature
{
get
{
return simplificationOptions.PreserveSurfaceCurvature;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.PreserveSurfaceCurvature = value;
SimplificationOptions = simplificationOptions;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public bool EnableSmartLink
{
get
{
return simplificationOptions.EnableSmartLink;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.EnableSmartLink = value;
SimplificationOptions = simplificationOptions;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public int MaxIterationCount
{
get
{
return simplificationOptions.MaxIterationCount;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.MaxIterationCount = value;
SimplificationOptions = simplificationOptions;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public double Agressiveness
{
get
{
return simplificationOptions.Agressiveness;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.Agressiveness = value;
SimplificationOptions = simplificationOptions;
}
}
public bool Verbose
{
get
{
return verbose;
}
set
{
verbose = value;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public double VertexLinkDistance
{
get
{
return simplificationOptions.VertexLinkDistance;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.VertexLinkDistance = ((value > double.Epsilon) ? value : double.Epsilon);
SimplificationOptions = simplificationOptions;
}
}
[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
public double VertexLinkDistanceSqr
{
get
{
return simplificationOptions.VertexLinkDistance * simplificationOptions.VertexLinkDistance;
}
set
{
SimplificationOptions simplificationOptions = this.simplificationOptions;
simplificationOptions.VertexLinkDistance = Math.Sqrt(value);
SimplificationOptions = simplificationOptions;
}
}
public Vector3[] Vertices
{
get
{
int length = vertices.Length;
Vector3[] array = new Vector3[length];
Vertex[] data = vertices.Data;
for (int i = 0; i < length; i++)
{
array[i] = (Vector3)data[i].p;
}
return array;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
bindposes = null;
vertices.Resize(value.Length);
Vertex[] data = vertices.Data;
for (int i = 0; i < value.Length; i++)
{
data[i] = new Vertex(i, value[i]);
}
}
}
public int SubMeshCount => subMeshCount;
public int BlendShapeCount
{
get
{
if (blendShapes == null)
{
return 0;
}
return blendShapes.Length;
}
}
public Vector3[] Normals
{
get
{
if (vertNormals == null)
{
return null;
}
return vertNormals.Data;
}
set
{
InitializeVertexAttribute(value, ref vertNormals, "normals");
}
}
public Vector4[] Tangents
{
get
{
if (vertTangents == null)
{
return null;
}
return vertTangents.Data;
}
set
{
InitializeVertexAttribute(value, ref vertTangents, "tangents");
}
}
public Vector2[] UV1
{
get
{
return GetUVs2D(0);
}
set
{
SetUVs(0, value);
}
}
public Vector2[] UV2
{
get
{
return GetUVs2D(1);
}
set
{
SetUVs(1, value);
}
}
public Vector2[] UV3
{
get
{
return GetUVs2D(2);
}
set
{
SetUVs(2, value);
}
}
public Vector2[] UV4
{
get
{
return GetUVs2D(3);
}
set
{
SetUVs(3, value);
}
}
public Vector2[] UV5
{
get
{
return GetUVs2D(4);
}
set
{
SetUVs(4, value);
}
}
public Vector2[] UV6
{
get
{
return GetUVs2D(5);
}
set
{
SetUVs(5, value);
}
}
public Vector2[] UV7
{
get
{
return GetUVs2D(6);
}
set
{
SetUVs(6, value);
}
}
public Vector2[] UV8
{
get
{
return GetUVs2D(7);
}
set
{
SetUVs(7, value);
}
}
public Color[] Colors
{
get
{
if (vertColors == null)
{
return null;
}
return vertColors.Data;
}
set
{
InitializeVertexAttribute(value, ref vertColors, "colors");
}
}
public BoneWeight[] BoneWeights
{
get
{
if (vertBoneWeights == null)
{
return null;
}
return vertBoneWeights.Data;
}
set
{
InitializeVertexAttribute(value, ref vertBoneWeights, "boneWeights");
}
}
public MeshSimplifier()
{
triangles = new ResizableArray<Triangle>(0);
vertices = new ResizableArray<Vertex>(0);
refs = new ResizableArray<Ref>(0);
}
public MeshSimplifier(Mesh mesh)
: this()
{
if (mesh != null)
{
Initialize(mesh);
}
}
private void InitializeVertexAttribute<T>(T[] attributeValues, ref ResizableArray<T> attributeArray, string attributeName)
{
if (attributeValues != null && attributeValues.Length == vertices.Length)
{
if (attributeArray == null)
{
attributeArray = new ResizableArray<T>(attributeValues.Length, attributeValues.Length);
}
else
{
attributeArray.Resize(attributeValues.Length);
}
T[] data = attributeArray.Data;
Array.Copy(attributeValues, 0, data, 0, attributeValues.Length);
return;
}
if (attributeValues != null && attributeValues.Length != 0)
{
Debug.LogErrorFormat("Failed to set vertex attribute '{0}' with {1} length of array, when {2} was needed.", attributeName, attributeValues.Length, vertices.Length);
}
attributeArray = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double VertexError(ref SymmetricMatrix q, double x, double y, double z)
{
return q.m0 * x * x + 2.0 * q.m1 * x * y + 2.0 * q.m2 * x * z + 2.0 * q.m3 * x + q.m4 * y * y + 2.0 * q.m5 * y * z + 2.0 * q.m6 * y + q.m7 * z * z + 2.0 * q.m8 * z + q.m9;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double CurvatureError(ref Vertex vert0, ref Vertex vert1)
{
double magnitude = (vert0.p - vert1.p).Magnitude;
HashSet<Triangle> hashSet = triangleHashSet1;
hashSet.Clear();
GetTrianglesContainingVertex(ref vert0, hashSet);
GetTrianglesContainingVertex(ref vert1, hashSet);
HashSet<Triangle> hashSet2 = triangleHashSet2;
hashSet2.Clear();
GetTrianglesContainingBothVertices(ref vert0, ref vert1, hashSet2);
double num = 0.0;
foreach (Triangle item in hashSet)
{
double num2 = 0.0;
Vector3d lhs = item.n;
foreach (Triangle item2 in hashSet2)
{
Vector3d rhs = item2.n;
double num3 = Vector3d.Dot(ref lhs, ref rhs);
if (num3 > num2)
{
num2 = num3;
}
}
if (num2 > num)
{
num = num2;
}
}
return magnitude * num;
}
private double CalculateError(ref Vertex vert0, ref Vertex vert1, out Vector3d result)
{
SymmetricMatrix q = vert0.q + vert1.q;
bool flag = vert0.borderEdge && vert1.borderEdge;
double num = 0.0;
double num2 = q.Determinant1();
if (num2 != 0.0 && !flag)
{
result = new Vector3d(-1.0 / num2 * q.Determinant2(), 1.0 / num2 * q.Determinant3(), -1.0 / num2 * q.Determinant4());
double num3 = 0.0;
if (simplificationOptions.PreserveSurfaceCurvature)
{
num3 = CurvatureError(ref vert0, ref vert1);
}
num = VertexError(ref q, result.x, result.y, result.z) + num3;
}
else
{
Vector3d p = vert0.p;
Vector3d p2 = vert1.p;
Vector3d vector3d = (p + p2) * 0.5;
double num4 = VertexError(ref q, p.x, p.y, p.z);
double num5 = VertexError(ref q, p2.x, p2.y, p2.z);
double num6 = VertexError(ref q, vector3d.x, vector3d.y, vector3d.z);
if (num4 < num5)
{
if (num4 < num6)
{
num = num4;
result = p;
}
else
{
num = num6;
result = vector3d;
}
}
else if (num5 < num6)
{
num = num5;
result = p2;
}
else
{
num = num6;
result = vector3d;
}
}
return num;
}
private static void CalculateBarycentricCoords(ref Vector3d point, ref Vector3d a, ref Vector3d b, ref Vector3d c, out Vector3 result)
{
Vector3d lhs = b - a;
Vector3d rhs = c - a;
Vector3d lhs2 = point - a;
double num = Vector3d.Dot(ref lhs, ref lhs);
double num2 = Vector3d.Dot(ref lhs, ref rhs);
double num3 = Vector3d.Dot(ref rhs, ref rhs);
double num4 = Vector3d.Dot(ref lhs2, ref lhs);
double num5 = Vector3d.Dot(ref lhs2, ref rhs);
double num6 = num * num3 - num2 * num2;
if (Math.Abs(num6) < 1E-08)
{
num6 = 1E-08;
}
double num7 = (num3 * num4 - num2 * num5) / num6;
double num8 = (num * num5 - num2 * num4) / num6;
double num9 = 1.0 - num7 - num8;
result = new Vector3((float)num9, (float)num7, (float)num8);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector4 NormalizeTangent(Vector4 tangent)
{
Vector3 vector = new Vector3(tangent.x, tangent.y, tangent.z);
vector.Normalize();
return new Vector4(vector.x, vector.y, vector.z, tangent.w);
}
private bool Flipped(ref Vector3d p, int i0, int i1, ref Vertex v0, bool[] deleted)
{
int tcount = v0.tcount;
Ref[] data = refs.Data;
Triangle[] data2 = triangles.Data;
Vertex[] data3 = vertices.Data;
for (int j = 0; j < tcount; j++)
{
Ref obj = data[v0.tstart + j];
if (data2[obj.tid].deleted)
{
continue;
}
int tvertex = obj.tvertex;
int num = data2[obj.tid][(tvertex + 1) % 3];
int num2 = data2[obj.tid][(tvertex + 2) % 3];
if (num == i1 || num2 == i1)
{
deleted[j] = true;
continue;
}
Vector3d lhs = data3[num].p - p;
lhs.Normalize();
Vector3d rhs = data3[num2].p - p;
rhs.Normalize();
if (Math.Abs(Vector3d.Dot(ref lhs, ref rhs)) > 0.999)
{
return true;
}
Vector3d.Cross(ref lhs, ref rhs, out var result);
result.Normalize();
deleted[j] = false;
if (Vector3d.Dot(ref result, ref data2[obj.tid].n) < 0.2)
{
return true;
}
}
return false;
}
private void UpdateTriangles(int i0, int ia0, ref Vertex v, ResizableArray<bool> deleted, ref int deletedTriangles)
{
int tcount = v.tcount;
Triangle[] data = triangles.Data;
Vertex[] data2 = vertices.Data;
for (int j = 0; j < tcount; j++)
{
Ref item = refs[v.tstart + j];
int tid = item.tid;
Triangle triangle = data[tid];
if (triangle.deleted)
{
continue;
}
if (deleted[j])
{
data[tid].deleted = true;
deletedTriangles++;
continue;
}
triangle[item.tvertex] = i0;
if (ia0 != -1)
{
triangle.SetAttributeIndex(item.tvertex, ia0);
}
triangle.dirty = true;
triangle.err0 = CalculateError(ref data2[triangle.v0], ref data2[triangle.v1], out var result);
triangle.err1 = CalculateError(ref data2[triangle.v1], ref data2[triangle.v2], out result);
triangle.err2 = CalculateError(ref data2[triangle.v2], ref data2[triangle.v0], out result);
triangle.err3 = MathHelper.Min(triangle.err0, triangle.err1, triangle.err2);
data[tid] = triangle;
refs.Add(item);
}
}
private void InterpolateVertexAttributes(int dst, int i0, int i1, int i2, ref Vector3 barycentricCoord)
{
if (vertNormals != null)
{
vertNormals[dst] = Vector3.Normalize(vertNormals[i0] * barycentricCoord.x + vertNormals[i1] * barycentricCoord.y + vertNormals[i2] * barycentricCoord.z);
}
if (vertTangents != null)
{
vertTangents[dst] = NormalizeTangent(vertTangents[i0] * barycentricCoord.x + vertTangents[i1] * barycentricCoord.y + vertTangents[i2] * barycentricCoord.z);
}
if (vertUV2D != null)
{
for (int j = 0; j < UVChannelCount; j++)
{
ResizableArray<Vector2> resizableArray = vertUV2D[j];
if (resizableArray != null)
{
resizableArray[dst] = resizableArray[i0] * barycentricCoord.x + resizableArray[i1] * barycentricCoord.y + resizableArray[i2] * barycentricCoord.z;
}
}
}
if (vertUV3D != null)
{
for (int k = 0; k < UVChannelCount; k++)
{
ResizableArray<Vector3> resizableArray2 = vertUV3D[k];
if (resizableArray2 != null)
{
resizableArray2[dst] = resizableArray2[i0] * barycentricCoord.x + resizableArray2[i1] * barycentricCoord.y + resizableArray2[i2] * barycentricCoord.z;
}
}
}
if (vertUV4D != null)
{
for (int l = 0; l < UVChannelCount; l++)
{
ResizableArray<Vector4> resizableArray3 = vertUV4D[l];
if (resizableArray3 != null)
{
resizableArray3[dst] = resizableArray3[i0] * barycentricCoord.x + resizableArray3[i1] * barycentricCoord.y + resizableArray3[i2] * barycentricCoord.z;
}
}
}
if (vertColors != null)
{
vertColors[dst] = vertColors[i0] * barycentricCoord.x + vertColors[i1] * barycentricCoord.y + vertColors[i2] * barycentricCoord.z;
}
if (blendShapes != null)
{
for (int m = 0; m < blendShapes.Length; m++)
{
blendShapes[m].InterpolateVertexAttributes(dst, i0, i1, i2, ref barycentricCoord);
}
}
}
private bool AreUVsTheSame(int channel, int indexA, int indexB)
{
if (vertUV2D != null)
{
ResizableArray<Vector2> resizableArray = vertUV2D[channel];
if (resizableArray != null)
{
Vector2 vector = resizableArray[indexA];
Vector2 vector2 = resizableArray[indexB];
return vector == vector2;
}
}
if (vertUV3D != null)
{
ResizableArray<Vector3> resizableArray2 = vertUV3D[channel];
if (resizableArray2 != null)
{
Vector3 vector3 = resizableArray2[indexA];
Vector3 vector4 = resizableArray2[indexB];
return vector3 == vector4;
}
}
if (vertUV4D != null)
{
ResizableArray<Vector4> resizableArray3 = vertUV4D[channel];
if (resizableArray3 != null)
{
Vector4 vector5 = resizableArray3[indexA];
Vector4 vector6 = resizableArray3[indexB];
return vector5 == vector6;
}
}
return false;
}
private void RemoveVertexPass(int startTrisCount, int targetTrisCount, double threshold, ResizableArray<bool> deleted0, ResizableArray<bool> deleted1, ref int deletedTris)
{
Triangle[] data = triangles.Data;
int length = triangles.Length;
Vertex[] data2 = vertices.Data;
for (int i = 0; i < length; i++)
{
if (data[i].dirty || data[i].deleted || data[i].err3 > threshold)
{
continue;
}
data[i].GetErrors(errArr);
data[i].GetAttributeIndices(attributeIndexArr);
for (int j = 0; j < 3; j++)
{
if (errArr[j] > threshold)
{
continue;
}
int num = (j + 1) % 3;
int num2 = data[i][j];
int num3 = data[i][num];
if (data2[num2].borderEdge != data2[num3].borderEdge || data2[num2].uvSeamEdge != data2[num3].uvSeamEdge || data2[num2].uvFoldoverEdge != data2[num3].uvFoldoverEdge || (simplificationOptions.PreserveBorderEdges && data2[num2].borderEdge) || (simplificationOptions.PreserveUVSeamEdges && data2[num2].uvSeamEdge) || (simplificationOptions.PreserveUVFoldoverEdges && data2[num2].uvFoldoverEdge))
{
continue;
}
CalculateError(ref data2[num2], ref data2[num3], out var result);
deleted0.Resize(data2[num2].tcount);
deleted1.Resize(data2[num3].tcount);
if (Flipped(ref result, num2, num3, ref data2[num2], deleted0.Data) || Flipped(ref result, num3, num2, ref data2[num3], deleted1.Data))
{
continue;
}
int num4 = (j + 2) % 3;
int num5 = data[i][num4];
CalculateBarycentricCoords(ref result, ref data2[num2].p, ref data2[num3].p, ref data2[num5].p, out var result2);
data2[num2].p = result;
data2[num2].q += data2[num3].q;
int num6 = attributeIndexArr[j];
int i2 = attributeIndexArr[num];
int i3 = attributeIndexArr[num4];
InterpolateVertexAttributes(num6, num6, i2, i3, ref result2);
if (data2[num2].uvSeamEdge)
{
num6 = -1;
}
int length2 = refs.Length;
UpdateTriangles(num2, num6, ref data2[num2], deleted0, ref deletedTris);
UpdateTriangles(num2, num6, ref data2[num3], deleted1, ref deletedTris);
int num7 = refs.Length - length2;
if (num7 <= data2[num2].tcount)
{
if (num7 > 0)
{
Ref[] data3 = refs.Data;
Array.Copy(data3, length2, data3, data2[num2].tstart, num7);
}
}
else
{
data2[num2].tstart = length2;
}
data2[num2].tcount = num7;
break;
}
if (startTrisCount - deletedTris <= targetTrisCount)
{
break;
}
}
}
private void UpdateMesh(int iteration)
{
Triangle[] data = triangles.Data;
Vertex[] data2 = vertices.Data;
int num = triangles.Length;
int length = vertices.Length;
if (iteration > 0)
{
int num2 = 0;
for (int i = 0; i < num; i++)
{
if (!data[i].deleted)
{
if (num2 != i)
{
data[num2] = data[i];
data[num2].index = num2;
}
num2++;
}
}
triangles.Resize(num2);
data = triangles.Data;
num = num2;
}
UpdateReferences();
if (iteration != 0)
{
return;
}
Ref[] data3 = refs.Data;
List<int> list = new List<int>(8);
List<int> list2 = new List<int>(8);
int num3 = 0;
for (int j = 0; j < length; j++)
{
data2[j].borderEdge = false;
data2[j].uvSeamEdge = false;
data2[j].uvFoldoverEdge = false;
}
int num4 = 0;
double num5 = double.MaxValue;
double num6 = double.MinValue;
double num7 = simplificationOptions.VertexLinkDistance * simplificationOptions.VertexLinkDistance;
for (int k = 0; k < length; k++)
{
int tstart = data2[k].tstart;
int tcount = data2[k].tcount;
list.Clear();
list2.Clear();
num3 = 0;
for (int l = 0; l < tcount; l++)
{
int tid = data3[tstart + l].tid;
for (int m = 0; m < 3; m++)
{
int n = 0;
int num8;
for (num8 = data[tid][m]; n < num3 && list2[n] != num8; n++)
{
}
if (n == num3)
{
list.Add(1);
list2.Add(num8);
num3++;
}
else
{
int index = n;
int value = list[index] + 1;
list[index] = value;
}
}
}
for (int num9 = 0; num9 < num3; num9++)
{
if (list[num9] != 1)
{
continue;
}
int num8 = list2[num9];
data2[num8].borderEdge = true;
num4++;
if (simplificationOptions.EnableSmartLink)
{
if (data2[num8].p.x < num5)
{
num5 = data2[num8].p.x;
}
if (data2[num8].p.x > num6)
{
num6 = data2[num8].p.x;
}
}
}
}
if (simplificationOptions.EnableSmartLink)
{
BorderVertex[] array = new BorderVertex[num4];
int num10 = 0;
double num11 = num6 - num5;
for (int num12 = 0; num12 < length; num12++)
{
if (data2[num12].borderEdge)
{
int hash = (int)(((data2[num12].p.x - num5) / num11 * 2.0 - 1.0) * 2147483647.0);
array[num10] = new BorderVertex(num12, hash);
num10++;
}
}
Array.Sort(array, 0, num10, BorderVertexComparer.instance);
int num13 = Math.Max((int)(Math.Sqrt(num7) / num11 * 2147483647.0), 1);
for (int num14 = 0; num14 < num10; num14++)
{
int index2 = array[num14].index;
if (index2 == -1)
{
continue;
}
Vector3d p = data2[index2].p;
for (int num15 = num14 + 1; num15 < num10; num15++)
{
int index3 = array[num15].index;
if (index3 == -1)
{
continue;
}
if (array[num15].hash - array[num14].hash > num13)
{
break;
}
Vector3d p2 = data2[index3].p;
double num16 = (p.x - p2.x) * (p.x - p2.x);
double num17 = (p.y - p2.y) * (p.y - p2.y);
double num18 = (p.z - p2.z) * (p.z - p2.z);
if (num16 + num17 + num18 <= num7)
{
array[num15].index = -1;
data2[index2].borderEdge = false;
data2[index3].borderEdge = false;
if (AreUVsTheSame(0, index2, index3))
{
data2[index2].uvFoldoverEdge = true;
data2[index3].uvFoldoverEdge = true;
}
else
{
data2[index2].uvSeamEdge = true;
data2[index3].uvSeamEdge = true;
}
int tcount2 = data2[index3].tcount;
int tstart2 = data2[index3].tstart;
for (int num19 = 0; num19 < tcount2; num19++)
{
Ref obj = data3[tstart2 + num19];
data[obj.tid][obj.tvertex] = index2;
}
}
}
}
UpdateReferences();
}
for (int num20 = 0; num20 < length; num20++)
{
data2[num20].q = default(SymmetricMatrix);
}
for (int num21 = 0; num21 < num; num21++)
{
int v = data[num21].v0;
int v2 = data[num21].v1;
int v3 = data[num21].v2;
Vector3d rhs = data2[v].p;
Vector3d p3 = data2[v2].p;
Vector3d p4 = data2[v3].p;
Vector3d lhs = p3 - rhs;
Vector3d rhs2 = p4 - rhs;
Vector3d.Cross(ref lhs, ref rhs2, out var result);
result.Normalize();
data[num21].n = result;
SymmetricMatrix symmetricMatrix = new SymmetricMatrix(result.x, result.y, result.z, 0.0 - Vector3d.Dot(ref result, ref rhs));
data2[v].q += symmetricMatrix;
data2[v2].q += symmetricMatrix;
data2[v3].q += symmetricMatrix;
}
for (int num22 = 0; num22 < num; num22++)
{
Triangle triangle = data[num22];
data[num22].err0 = CalculateError(ref data2[triangle.v0], ref data2[triangle.v1], out var result2);
data[num22].err1 = CalculateError(ref data2[triangle.v1], ref data2[triangle.v2], out result2);
data[num22].err2 = CalculateError(ref data2[triangle.v2], ref data2[triangle.v0], out result2);
data[num22].err3 = MathHelper.Min(data[num22].err0, data[num22].err1, data[num22].err2);
}
}
private void UpdateReferences()
{
int length = triangles.Length;
int length2 = vertices.Length;
Triangle[] data = triangles.Data;
Vertex[] data2 = vertices.Data;
for (int i = 0; i < length2; i++)
{
data2[i].tstart = 0;
data2[i].tcount = 0;
}
for (int j = 0; j < length; j++)
{
data2[data[j].v0].tcount++;
data2[data[j].v1].tcount++;
data2[data[j].v2].tcount++;
}
int num = 0;
for (int k = 0; k < length2; k++)
{
data2[k].tstart = num;
num += data2[k].tcount;
data2[k].tcount = 0;
}
refs.Resize(num);
Ref[] data3 = refs.Data;
for (int l = 0; l < length; l++)
{
int v = data[l].v0;
int v2 = data[l].v1;
int v3 = data[l].v2;
int tstart = data2[v].tstart;
int num2 = data2[v].tcount++;
int tstart2 = data2[v2].tstart;
int num3 = data2[v2].tcount++;
int tstart3 = data2[v3].tstart;
int num4 = data2[v3].tcount++;
data3[tstart + num2].Set(l, 0);
data3[tstart2 + num3].Set(l, 1);
data3[tstart3 + num4].Set(l, 2);
}
}
private void CompactMesh()
{
int num = 0;
Vertex[] data = vertices.Data;
int length = vertices.Length;
for (int i = 0; i < length; i++)
{
data[i].tcount = 0;
}
Vector3[] array = ((vertNormals != null) ? vertNormals.Data : null);
Vector4[] array2 = ((vertTangents != null) ? vertTangents.Data : null);
Vector2[][] array3 = ((vertUV2D != null) ? vertUV2D.Data : null);
Vector3[][] array4 = ((vertUV3D != null) ? vertUV3D.Data : null);
Vector4[][] array5 = ((vertUV4D != null) ? vertUV4D.Data : null);
Color[] array6 = ((vertColors != null) ? vertColors.Data : null);
BoneWeight[] array7 = ((vertBoneWeights != null) ? vertBoneWeights.Data : null);
BlendShapeContainer[] array8 = ((blendShapes != null) ? blendShapes.Data : null);
int num2 = -1;
subMeshOffsets = new int[subMeshCount];
Triangle[] data2 = triangles.Data;
int length2 = triangles.Length;
for (int j = 0; j < length2; j++)
{
Triangle triangle = data2[j];
if (triangle.deleted)
{
continue;
}
if (triangle.va0 != triangle.v0)
{
int va = triangle.va0;
int v = triangle.v0;
data[va].p = data[v].p;
if (array7 != null)
{
array7[va] = array7[v];
}
triangle.v0 = triangle.va0;
}
if (triangle.va1 != triangle.v1)
{
int va2 = triangle.va1;
int v2 = triangle.v1;
data[va2].p = data[v2].p;
if (array7 != null)
{
array7[va2] = array7[v2];
}
triangle.v1 = triangle.va1;
}
if (triangle.va2 != triangle.v2)
{
int va3 = triangle.va2;
int v3 = triangle.v2;
data[va3].p = data[v3].p;
if (array7 != null)
{
array7[va3] = array7[v3];
}
triangle.v2 = triangle.va2;
}
int num3 = num++;
data2[num3] = triangle;
data2[num3].index = num3;
data[triangle.v0].tcount = 1;
data[triangle.v1].tcount = 1;
data[triangle.v2].tcount = 1;
if (triangle.subMeshIndex > num2)
{
for (int k = num2 + 1; k < triangle.subMeshIndex; k++)
{
subMeshOffsets[k] = num3;
}
subMeshOffsets[triangle.subMeshIndex] = num3;
num2 = triangle.subMeshIndex;
}
}
length2 = num;
for (int l = num2 + 1; l < subMeshCount; l++)
{
subMeshOffsets[l] = length2;
}
triangles.Resize(length2);
data2 = triangles.Data;
num = 0;
for (int m = 0; m < length; m++)
{
Vertex vertex = data[m];
if (vertex.tcount <= 0)
{
continue;
}
data[m].tstart = num;
if (num != m)
{
data[num].index = num;
data[num].p = vertex.p;
if (array != null)
{
array[num] = array[m];
}
if (array2 != null)
{
array2[num] = array2[m];
}
if (array3 != null)
{
for (int n = 0; n < UVChannelCount; n++)
{
Vector2[] array9 = array3[n];
if (array9 != null)
{
array9[num] = array9[m];
}
}
}
if (array4 != null)
{
for (int num4 = 0; num4 < UVChannelCount; num4++)
{
Vector3[] array10 = array4[num4];
if (array10 != null)
{
array10[num] = array10[m];
}
}
}
if (array5 != null)
{
for (int num5 = 0; num5 < UVChannelCount; num5++)
{
Vector4[] array11 = array5[num5];
if (array11 != null)
{
array11[num] = array11[m];
}
}
}
if (array6 != null)
{
array6[num] = array6[m];
}
if (array7 != null)
{
array7[num] = array7[m];
}
if (array8 != null)
{
for (int num6 = 0; num6 < blendShapes.Length; num6++)
{
array8[num6].MoveVertexElement(num, m);
}
}
}
num++;
}
for (int num7 = 0; num7 < length2; num7++)
{
Triangle triangle2 = data2[num7];
triangle2.v0 = data[triangle2.v0].tstart;
triangle2.v1 = data[triangle2.v1].tstart;
triangle2.v2 = data[triangle2.v2].tstart;
data2[num7] = triangle2;
}
length = num;
vertices.Resize(length);
if (array != null)
{
vertNormals.Resize(length, trimExess: true);
}
if (array2 != null)
{
vertTangents.Resize(length, trimExess: true);
}
if (array3 != null)
{
vertUV2D.Resize(length, trimExess: true);
}
if (array4 != null)
{
vertUV3D.Resize(length, trimExess: true);
}
if (array5 != null)
{
vertUV4D.Resize(length, trimExess: true);
}
if (array6 != null)
{
vertColors.Resize(length, trimExess: true);
}
if (array7 != null)
{
vertBoneWeights.Resize(length, trimExess: true);
}
if (array8 != null)
{
for (int num8 = 0; num8 < blendShapes.Length; num8++)
{
array8[num8].Resize(length);
}
}
}
private void CalculateSubMeshOffsets()
{
int num = -1;
subMeshOffsets = new int[subMeshCount];
Triangle[] data = triangles.Data;
int length = triangles.Length;
for (int i = 0; i < length; i++)
{
Triangle triangle = data[i];
if (triangle.subMeshIndex > num)
{
for (int j = num + 1; j < triangle.subMeshIndex; j++)
{
subMeshOffsets[j] = i;
}
subMeshOffsets[triangle.subMeshIndex] = i;
num = triangle.subMeshIndex;
}
}
for (int k = num + 1; k < subMeshCount; k++)
{
subMeshOffsets[k] = length;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void GetTrianglesContainingVertex(ref Vertex vert, HashSet<Triangle> tris)
{
int tcount = vert.tcount;
int tstart = vert.tstart;
for (int i = tstart; i < tstart + tcount; i++)
{
tris.Add(triangles[refs[i].tid]);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void GetTrianglesContainingBothVertices(ref Vertex vert0, ref Vertex vert1, HashSet<Triangle> tris)
{
int tcount = vert0.tcount;
int tstart = vert0.tstart;
for (int i = tstart; i < tstart + tcount; i++)
{
int tid = refs[i].tid;
Triangle item = triangles[tid];
if (vertices[item.v0].index == vert1.index || vertices[item.v1].index == vert1.index || vertices[item.v2].index == vert1.index)
{
tris.Add(item);
}
}
}
public int[][] GetAllSubMeshTriangles()
{
int[][] array = new int[subMeshCount][];
for (int i = 0; i < subMeshCount; i++)
{
array[i] = GetSubMeshTriangles(i);
}
return array;
}
public int[] GetSubMeshTriangles(int subMeshIndex)
{
if (subMeshIndex < 0)
{
throw new ArgumentOutOfRangeException("subMeshIndex", "The sub-mesh index is negative.");
}
if (subMeshOffsets == null)
{
CalculateSubMeshOffsets();
}
if (subMeshIndex >= subMeshOffsets.Length)
{
throw new ArgumentOutOfRangeException("subMeshIndex", "The sub-mesh index is greater than or equals to the sub mesh count.");
}
if (subMeshOffsets.Length != subMeshCount)
{
throw new InvalidOperationException("The sub-mesh triangle offsets array is not the same size as the count of sub-meshes. This should not be possible to happen.");
}
Triangle[] data = triangles.Data;
int length = triangles.Length;
int num = subMeshOffsets[subMeshIndex];
if (num >= length)
{
return new int[0];
}
int num2 = ((subMeshIndex + 1 < subMeshCount) ? subMeshOffsets[subMeshIndex + 1] : length);
int num3 = num2 - num;
if (num3 < 0)
{
num3 = 0;
}
int[] array = new int[num3 * 3];
for (int i = num; i < num2; i++)
{
Triangle triangle = data[i];
int num4 = (i - num) * 3;
array[num4] = triangle.v0;
array[num4 + 1] = triangle.v1;
array[num4 + 2] = triangle.v2;
}
return array;
}
public void ClearSubMeshes()
{
subMeshCount = 0;
subMeshOffsets = null;
triangles.Resize(0);
}
public void AddSubMeshTriangles(int[] triangles)
{
if (triangles == null)
{
throw new ArgumentNullException("triangles");
}
if (triangles.Length % 3 != 0)
{
throw new ArgumentException("The index array length must be a multiple of 3 in order to represent triangles.", "triangles");
}
int subMeshIndex = subMeshCount++;
int length = this.triangles.Length;
int num = triangles.Length / 3;
this.triangles.Resize(this.triangles.Length + num);
Triangle[] data = this.triangles.Data;
for (int i = 0; i < num; i++)
{
int num2 = i * 3;
int v = triangles[num2];
int v2 = triangles[num2 + 1];
int v3 = triangles[num2 + 2];
int num3 = length + i;
data[num3] = new Triangle(num3, v, v2, v3, subMeshIndex);
}
}
public void AddSubMeshTriangles(int[][] triangles)
{
if (triangles == null)
{
throw new ArgumentNullException("triangles");
}
int num = 0;
for (int i = 0; i < triangles.Length; i++)
{
if (triangles[i] == null)
{
throw new ArgumentException($"The index array at index {i} is null.");
}
if (triangles[i].Length % 3 != 0)
{
throw new ArgumentException($"The index array length at index {i} must be a multiple of 3 in order to represent triangles.", "triangles");
}
num += triangles[i].Length / 3;
}
int num2 = this.triangles.Length;
this.triangles.Resize(this.triangles.Length + num);
Triangle[] data = this.triangles.Data;
for (int j = 0; j < triangles.Length; j++)
{
int subMeshIndex = subMeshCount++;
int[] array = triangles[j];
int num3 = array.Length / 3;
for (int k = 0; k < num3; k++)
{
int num4 = k * 3;
int v = array[num4];
int v2 = array[num4 + 1];
int v3 = array[num4 + 2];
int num5 = num2 + k;
data[num5] = new Triangle(num5, v, v2, v3, subMeshIndex);
}
num2 += num3;
}
}
public Vector2[] GetUVs2D(int channel)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (vertUV2D != null && vertUV2D[channel] != null)
{
return vertUV2D[channel].Data;
}
return null;
}
public Vector3[] GetUVs3D(int channel)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (vertUV3D != null && vertUV3D[channel] != null)
{
return vertUV3D[channel].Data;
}
return null;
}
public Vector4[] GetUVs4D(int channel)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (vertUV4D != null && vertUV4D[channel] != null)
{
return vertUV4D[channel].Data;
}
return null;
}
public void GetUVs(int channel, List<Vector2> uvs)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (uvs == null)
{
throw new ArgumentNullException("uvs");
}
uvs.Clear();
if (vertUV2D != null && vertUV2D[channel] != null)
{
Vector2[] data = vertUV2D[channel].Data;
if (data != null)
{
uvs.AddRange(data);
}
}
}
public void GetUVs(int channel, List<Vector3> uvs)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (uvs == null)
{
throw new ArgumentNullException("uvs");
}
uvs.Clear();
if (vertUV3D != null && vertUV3D[channel] != null)
{
Vector3[] data = vertUV3D[channel].Data;
if (data != null)
{
uvs.AddRange(data);
}
}
}
public void GetUVs(int channel, List<Vector4> uvs)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (uvs == null)
{
throw new ArgumentNullException("uvs");
}
uvs.Clear();
if (vertUV4D != null && vertUV4D[channel] != null)
{
Vector4[] data = vertUV4D[channel].Data;
if (data != null)
{
uvs.AddRange(data);
}
}
}
public void SetUVs(int channel, IList<Vector2> uvs)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (uvs != null && uvs.Count > 0)
{
if (vertUV2D == null)
{
vertUV2D = new UVChannels<Vector2>();
}
int count = uvs.Count;
ResizableArray<Vector2> resizableArray = vertUV2D[channel];
if (resizableArray != null)
{
resizableArray.Resize(count);
}
else
{
resizableArray = new ResizableArray<Vector2>(count, count);
vertUV2D[channel] = resizableArray;
}
Vector2[] data = resizableArray.Data;
uvs.CopyTo(data, 0);
}
else if (vertUV2D != null)
{
vertUV2D[channel] = null;
}
if (vertUV3D != null)
{
vertUV3D[channel] = null;
}
if (vertUV4D != null)
{
vertUV4D[channel] = null;
}
}
public void SetUVs(int channel, IList<Vector3> uvs)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (uvs != null && uvs.Count > 0)
{
if (vertUV3D == null)
{
vertUV3D = new UVChannels<Vector3>();
}
int count = uvs.Count;
ResizableArray<Vector3> resizableArray = vertUV3D[channel];
if (resizableArray != null)
{
resizableArray.Resize(count);
}
else
{
resizableArray = new ResizableArray<Vector3>(count, count);
vertUV3D[channel] = resizableArray;
}
Vector3[] data = resizableArray.Data;
uvs.CopyTo(data, 0);
}
else if (vertUV3D != null)
{
vertUV3D[channel] = null;
}
if (vertUV2D != null)
{
vertUV2D[channel] = null;
}
if (vertUV4D != null)
{
vertUV4D[channel] = null;
}
}
public void SetUVs(int channel, IList<Vector4> uvs)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (uvs != null && uvs.Count > 0)
{
if (vertUV4D == null)
{
vertUV4D = new UVChannels<Vector4>();
}
int count = uvs.Count;
ResizableArray<Vector4> resizableArray = vertUV4D[channel];
if (resizableArray != null)
{
resizableArray.Resize(count);
}
else
{
resizableArray = new ResizableArray<Vector4>(count, count);
vertUV4D[channel] = resizableArray;
}
Vector4[] data = resizableArray.Data;
uvs.CopyTo(data, 0);
}
else if (vertUV4D != null)
{
vertUV4D[channel] = null;
}
if (vertUV2D != null)
{
vertUV2D[channel] = null;
}
if (vertUV3D != null)
{
vertUV3D[channel] = null;
}
}
public void SetUVs(int channel, IList<Vector4> uvs, int uvComponentCount)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
if (uvComponentCount < 0 || uvComponentCount > 4)
{
throw new ArgumentOutOfRangeException("uvComponentCount");
}
if (uvs != null && uvs.Count > 0 && uvComponentCount > 0)
{
if (uvComponentCount <= 2)
{
Vector2[] uvs2 = MeshUtils.ConvertUVsTo2D(uvs);
SetUVs(channel, uvs2);
}
else if (uvComponentCount == 3)
{
Vector3[] uvs3 = MeshUtils.ConvertUVsTo3D(uvs);
SetUVs(channel, uvs3);
}
else
{
SetUVs(channel, uvs);
}
return;
}
if (vertUV2D != null)
{
vertUV2D[channel] = null;
}
if (vertUV3D != null)
{
vertUV3D[channel] = null;
}
if (vertUV4D != null)
{
vertUV4D[channel] = null;
}
}
public void SetUVsAuto(int channel, IList<Vector4> uvs)
{
if (channel < 0 || channel >= UVChannelCount)
{
throw new ArgumentOutOfRangeException("channel");
}
int usedUVComponents = MeshUtils.GetUsedUVComponents(uvs);
SetUVs(channel, uvs, usedUVComponents);
}
public BlendShape[] GetAllBlendShapes()
{
if (blendShapes == null)
{
return null;
}
BlendShape[] array = new BlendShape[blendShapes.Length];
for (int i = 0; i < array.Length; i++)
{
array[i] = blendShapes[i].ToBlendShape();
}
return array;
}
public BlendShape GetBlendShape(int blendShapeIndex)
{
if (blendShapes == null || blendShapeIndex < 0 || blendShapeIndex >= blendShapes.Length)
{
throw new ArgumentOutOfRangeException("blendShapeIndex");
}
return blendShapes[blendShapeIndex].ToBlendShape();
}
public void ClearBlendShapes()
{
if (blendShapes != null)
{
blendShapes.Clear();
blendShapes = null;
}
}
public void AddBlendShape(BlendShape blendShape)
{
BlendShapeFrame[] frames = blendShape.Frames;
if (frames == null || frames.Length == 0)
{
throw new ArgumentException("The frames cannot be null or empty.", "blendShape");
}
if (blendShapes == null)
{
blendShapes = new ResizableArray<BlendShapeContainer>(4, 0);
}
BlendShapeContainer item = new BlendShapeContainer(blendShape);
blendShapes.Add(item);
}
public void AddBlendShapes(BlendShape[] blendShapes)
{
if (blendShapes == null)
{
throw new ArgumentNullException("blendShapes");
}
if (this.blendShapes == null)
{
this.blendShapes = new ResizableArray<BlendShapeContainer>(Math.Max(4, blendShapes.Length), 0);
}
for (int i = 0; i < blendShapes.Length; i++)
{
BlendShapeFrame[] frames = blendShapes[i].Frames;
if (frames == null || frames.Length == 0)
{
throw new ArgumentException($"The frames of blend shape at index {i} cannot be null or empty.", "blendShapes");
}
BlendShapeContainer item = new BlendShapeContainer(blendShapes[i]);
this.blendShapes.Add(item);
}
}
public void Initialize(Mesh mesh)
{
if (mesh == null)
{
throw new ArgumentNullException("mesh");
}
Vertices = mesh.vertices;
Normals = mesh.normals;
Tangents = mesh.tangents;
Colors = mesh.colors;
BoneWeights = mesh.boneWeights;
bindposes = mesh.bindposes;
for (int i = 0; i < UVChannelCount; i++)
{
if (simplificationOptions.ManualUVComponentCount)
{
switch (simplificationOptions.UVComponentCount)
{
case 1:
case 2:
{
IList<Vector2> meshUVs2D = MeshUtils.GetMeshUVs2D(mesh, i);
SetUVs(i, meshUVs2D);
break;
}
case 3:
{
IList<Vector3> meshUVs3D = MeshUtils.GetMeshUVs3D(mesh, i);
SetUVs(i, meshUVs3D);
break;
}
case 4:
{
IList<Vector4> meshUVs = MeshUtils.GetMeshUVs(mesh, i);
SetUVs(i, meshUVs);
break;
}
}
}
else
{
IList<Vector4> meshUVs2 = MeshUtils.GetMeshUVs(mesh, i);
SetUVsAuto(i, meshUVs2);
}
}
BlendShape[] meshBlendShapes = MeshUtils.GetMeshBlendShapes(mesh);
if (meshBlendShapes != null && meshBlendShapes.Length != 0)
{
AddBlendShapes(meshBlendShapes);
}
ClearSubMeshes();
int num = mesh.subMeshCount;
int[][] array = new int[num][];
for (int j = 0; j < num; j++)
{
array[j] = mesh.GetTriangles(j);
}
AddSubMeshTriangles(array);
}
public void SimplifyMesh(float quality)
{
quality = Mathf.Clamp01(quality);
int deletedTris = 0;
ResizableArray<bool> deleted = new ResizableArray<bool>(20);
ResizableArray<bool> deleted2 = new ResizableArray<bool>(20);
Triangle[] data = triangles.Data;
int length = triangles.Length;
int num = length;
_ = vertices.Data;
int num2 = Mathf.RoundToInt((float)length * quality);
for (int i = 0; i < simplificationOptions.MaxIterationCount; i++)
{
if (num - deletedTris <= num2)
{
break;
}
if (i % 5 == 0)
{
UpdateMesh(i);
data = triangles.Data;
length = triangles.Length;
_ = vertices.Data;
}
for (int j = 0; j < length; j++)
{
data[j].dirty = false;
}
double num3 = 1E-09 * Math.Pow(i + 3, simplificationOptions.Agressiveness);
if (verbose)
{
Debug.LogFormat("iteration {0} - triangles {1} threshold {2}", i, num - deletedTris, num3);
}
RemoveVertexPass(num, num2, num3, deleted, deleted2, ref deletedTris);
}
CompactMesh();
if (verbose)
{
Debug.LogFormat("Finished simplification with triangle count {0}", triangles.Length);
}
}
public void SimplifyMeshLossless()
{
int deletedTris = 0;
ResizableArray<bool> deleted = new ResizableArray<bool>(0);
ResizableArray<bool> deleted2 = new ResizableArray<bool>(0);
Triangle[] data = triangles.Data;
int length = triangles.Length;
int startTrisCount = length;
_ = vertices.Data;
for (int i = 0; i < 9999; i++)
{
UpdateMesh(i);
data = triangles.Data;
length = triangles.Length;
_ = vertices.Data;
for (int j = 0; j < length; j++)
{
data[j].dirty = false;
}
double threshold = 0.001;
if (verbose)
{
Debug.LogFormat("Lossless iteration {0} - triangles {1}", i, length);
}
RemoveVertexPass(startTrisCount, 0, threshold, deleted, deleted2, ref deletedTris);
if (deletedTris <= 0)
{
break;
}
deletedTris = 0;
}
CompactMesh();
if (verbose)
{
Debug.LogFormat("Finished simplification with triangle count {0}", triangles.Length);
}
}
public Mesh ToMesh()
{
Vector3[] array = Vertices;
Vector3[] normals = Normals;
Vector4[] tangents = Tangents;
Color[] colors = Colors;
BoneWeight[] boneWeights = BoneWeights;
int[][] allSubMeshTriangles = GetAllSubMeshTriangles();
BlendShape[] allBlendShapes = GetAllBlendShapes();
List<Vector2>[] array2 = null;
List<Vector3>[] array3 = null;
List<Vector4>[] array4 = null;
if (vertUV2D != null)
{
array2 = new List<Vector2>[UVChannelCount];
for (int i = 0; i < UVChannelCount; i++)
{
if (vertUV2D[i] != null)
{
List<Vector2> list = new List<Vector2>(array.Length);
GetUVs(i, list);
array2[i] = list;
}
}
}
if (vertUV3D != null)
{
array3 = new List<Vector3>[UVChannelCount];
for (int j = 0; j < UVChannelCount; j++)
{
if (vertUV3D[j] != null)
{
List<Vector3> list2 = new List<Vector3>(array.Length);
GetUVs(j, list2);
array3[j] = list2;
}
}
}
if (vertUV4D != null)
{
array4 = new List<Vector4>[UVChannelCount];
for (int k = 0; k < UVChannelCount; k++)
{
if (vertUV4D[k] != null)
{
List<Vector4> list3 = new List<Vector4>(array.Length);
GetUVs(k, list3);
array4[k] = list3;
}
}
}
return MeshUtils.CreateMesh(array, allSubMeshTriangles, normals, tangents, colors, boneWeights, array2, array3, array4, bindposes, allBlendShapes);
}
public static void ValidateOptions(SimplificationOptions options)
{
if (options.EnableSmartLink && options.VertexLinkDistance < 0.0)
{
throw new ValidateSimplificationOptionsException("VertexLinkDistance", "The vertex link distance cannot be negative when smart linking is enabled.");
}
if (options.MaxIterationCount <= 0)
{
throw new ValidateSimplificationOptionsException("MaxIterationCount", "The max iteration count cannot be zero or negative, since there would be nothing for the algorithm to do.");
}
if (options.Agressiveness <= 0.0)
{
throw new ValidateSimplificationOptionsException("Agressiveness", "The aggressiveness has to be above zero to make sense. Recommended is around 7.");
}
if (options.ManualUVComponentCount && (options.UVComponentCount < 0 || options.UVComponentCount > 4))
{
throw new ValidateSimplificationOptionsException("UVComponentCount", "The UV component count cannot be below 0 or above 4 when manual UV component count is enabled.");
}
}
}
}