public void Reuse()
 {
     this.Id = 0u;
     V0      = null;
     V1      = null;
     Faces.Clear();
 }
        private EdgeEntry FindEdgeEntry(VertexEntry ve0, VertexEntry ve1)
        {
            foreach (var existing in ve0.Edges)
            {
                if (existing.V1 == ve1)
                {
                    return(existing);
                }
            }

            return(null);
        }
        private void RemoveVertexInternal(VertexEntry vertexEntry, bool cascade)
        {
            if (!cascade)
            {
                if (vertexEntry.Edges.Count > 0)
                {
                    throw new InvalidOperationException("The vertex is still part of some edges.");
                }

                if (vertexEntry.Faces.Count > 0)
                {
                    throw new InvalidOperationException("The vertex is still part of some faces.");
                }
            }
            else
            {
                foreach (var edgeEntry in vertexEntry.Edges)
                {
                    edges.Remove(edgeEntry);
                    if (edgeEntry.V0 == vertexEntry)
                    {
                        edgeEntry.V1.Edges.Remove(edgeEntry);
                    }
                    else
                    {
                        edgeEntry.V0.Edges.Remove(edgeEntry);
                    }

                    EdgePool.Put(edgeEntry);
                }

                foreach (var faceEntry in vertexEntry.Faces)
                {
                    faces.Remove(faceEntry);

                    foreach (var fve in faceEntry.Vertices)
                    {
                        fve.Faces.Remove(faceEntry);
                    }

                    foreach (var fee in faceEntry.Edges)
                    {
                        fee.Faces.Remove(faceEntry);
                    }

                    FacePool.Put(faceEntry);
                }
            }
        }
        private EdgeEntry AddEdgeInternal(VertexEntry ve0, VertexEntry ve1)
        {
            var existing = FindEdgeEntry(ve0, ve1);

            if (existing != null)
            {
                return(existing);
            }

            var newEdge = EdgePool.Get();

            newEdge.Id = edges.Count > 0 ? edges[edges.Count - 1].Id + 1u : 1u;
            newEdge.V0 = ve0;
            newEdge.V1 = ve1;

            edges.Add(newEdge);

            return(newEdge);
        }
Beispiel #5
0
    /// <summary>
    ///     Recalculate the normals of a mesh based on an angle threshold. This takes
    ///     into account distinct vertices that have the same position.
    /// </summary>
    /// <param name="mesh"></param>
    /// <param name="angle">
    ///     The smoothing angle. Note that triangles that already share
    ///     the same vertex will be smooth regardless of the angle!
    /// </param>
    /// <param name="ignoreFactor">
    ///     A fraction between 0 and 1.
    ///     Weights smaller than this fraction relative to the largest weight are ignored.
    /// </param>
    public static void RecalculateNormals(this Mesh mesh, float angle, float ignoreFactor)
    {
        var triangles          = mesh.triangles;
        var vertices           = mesh.vertices;
        var triNormals         = new Vector3[triangles.Length / 3]; //Normal of each triangle
        var triNormalsWeighted = new Vector3[triangles.Length / 3]; //Weighted normal of each triangle
        var normals            = new Vector3[vertices.Length];

        angle = angle * Mathf.Deg2Rad;

        var dictionary = new Dictionary <VertexKey, VertexEntry>(vertices.Length);

        //Goes through all the triangles and gathers up data to be used later
        for (var i = 0; i < triangles.Length; i += 3)
        {
            int i1 = triangles[i];
            int i2 = triangles[i + 1];
            int i3 = triangles[i + 2];

            //Calculate the normal of the triangle
            Vector3 p1 = vertices[i2] - vertices[i1];
            Vector3 p2 = vertices[i3] - vertices[i1];

            // By not normalizing the cross product,
            // the face area is pre-multiplied onto the normal for free.
            Vector3 normal   = Vector3.Cross(p1, p2);
            int     triIndex = i / 3;
            triNormalsWeighted[triIndex] = normal;
            triNormals[triIndex]         = normal.normalized;

            VertexEntry entry;
            VertexKey   key;

            //For each of the three points of the triangle
            //  > Add this triangle as part of the triangles they're connected to.

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i1]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i1, triIndex);

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i2]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i2, triIndex);

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i3]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i3, triIndex);
        }

        //Foreach point in space (not necessarily the same vertex index!)
        //{
        //  Foreach triangle T1 that point belongs to
        //  {
        //    Foreach other triangle T2 (including self) that point belongs to and that
        //    meets any of the following:
        //    1) The corresponding vertex is actually the same vertex
        //    2) The angle between the two triangles is less than the smoothing angle
        //    {
        //      > Add to the set of contributing normals
        //    }
        //    > Add the normals in the set together, excluding those smaller than the threshold.
        //    > Normalize the resulting vector to find the average
        //    > Assign the normal to corresponding vertex of T1
        //  }
        //}

        List <Vector3> normalSet = new List <Vector3>();

        foreach (var value in dictionary.Values)
        {
            for (var i = 0; i < value.Count; ++i)
            {
                normalSet.Clear();
                float longest = 0;
                for (var j = 0; j < value.Count; ++j)
                {
                    bool use = false;
                    if (value.VertexIndex[i] == value.VertexIndex[j])
                    {
                        use = true;
                    }
                    else
                    {
                        float dot = Vector3.Dot(
                            triNormals[value.TriangleIndex[i]],
                            triNormals[value.TriangleIndex[j]]);
                        dot = Mathf.Clamp(dot, -0.99999f, 0.99999f);
                        float acos = Mathf.Acos(dot);
                        if (acos <= angle)
                        {
                            use = true;
                        }
                    }
                    if (use)
                    {
                        Vector3 normal = triNormalsWeighted[value.TriangleIndex[j]];
                        normalSet.Add(normal);
                        float length = normal.magnitude;
                        if (length > longest)
                        {
                            longest = length;
                        }
                    }
                }

                var sum       = new Vector3();
                var threshold = longest * ignoreFactor;
                for (int j = 0; j < normalSet.Count; j++)
                {
                    if (normalSet[j].magnitude >= threshold)
                    {
                        sum += normalSet[j];
                    }
                }
                normals[value.VertexIndex[i]] = sum.normalized;
            }
        }

        mesh.normals = normals;
    }
Beispiel #6
0
        public static void RecalculateNormals(this Mesh mesh, float angle)
        {
            var triangles = mesh.GetTriangles(0);
            var vertices = mesh.vertices;
            var triNormals = new Vector3[triangles.Length / 3]; //Holds the normal of each triangle
            var normals = new Vector3[vertices.Length];

            angle = angle * Mathf.Deg2Rad;

            var dictionary = new Dictionary<VertexKey, VertexEntry>(vertices.Length);

            //Goes through all the triangles and gathers up data to be used later
            for (var i = 0; i < triangles.Length; i += 3) {
                int i1 = triangles[i];
                int i2 = triangles[i + 1];
                int i3 = triangles[i + 2];

                //Calculate the normal of the triangle
                Vector3 p1 = vertices[i2] - vertices[i1];
                Vector3 p2 = vertices[i3] - vertices[i1];
                Vector3 normal = Vector3.Cross(p1, p2).normalized;
                int triIndex = i / 3;
                triNormals[triIndex] = normal;

                VertexEntry entry;
                VertexKey key;

                //For each of the three points of the triangle
                //  > Add this triangle as part of the triangles they're connected to.

                if (!dictionary.TryGetValue(key = new VertexKey(vertices[i1]), out entry)) {
                    entry = new VertexEntry();
                    dictionary.Add(key, entry);
                }
                entry.Add(i1, triIndex);

                if (!dictionary.TryGetValue(key = new VertexKey(vertices[i2]), out entry)) {
                    entry = new VertexEntry();
                    dictionary.Add(key, entry);
                }
                entry.Add(i2, triIndex);

                if (!dictionary.TryGetValue(key = new VertexKey(vertices[i3]), out entry)) {
                    entry = new VertexEntry();
                    dictionary.Add(key, entry);
                }
                entry.Add(i3, triIndex);
            }

            //Foreach point in space (not necessarily the same vertex index!)
            //{
            //  Foreach triangle T1 that point belongs to
            //  {
            //    Foreach other triangle T2 (including self) that point belongs to and that
            //    meets any of the following:
            //    1) The corresponding vertex is actually the same vertex
            //    2) The angle between the two triangles is less than the smoothing angle
            //    {
            //      > Add to temporary Vector3
            //    }
            //    > Normalize temporary Vector3 to find the average
            //    > Assign the normal to corresponding vertex of T1
            //  }
            //}

            foreach (var value in dictionary.Values) {
                for (var i = 0; i < value.Count; ++i) {
                    var sum = new Vector3();
                    for (var j = 0; j < value.Count; ++j) {
                        if (value.VertexIndex[i] == value.VertexIndex[j]) {
                            sum += triNormals[value.TriangleIndex[j]];
                        } else {
                            float dot = Vector3.Dot(
                                triNormals[value.TriangleIndex[i]],
                                triNormals[value.TriangleIndex[j]]);
                            dot = Mathf.Clamp(dot, -0.999999f, 0.999999f);
                            float acos = Mathf.Acos(dot);
                            if (acos <= angle) {
                                sum += triNormals[value.TriangleIndex[j]];
                            }
                        }
                    }

                    normals[value.VertexIndex[i]] = sum.normalized;
                }
            }

            mesh.normals = normals;
        }
    /// <summary>
    ///     Recalculate the normals of a mesh based on an angle threshold. This takes
    ///     into account distinct vertices that have the same position.
    /// </summary>
    /// <param name="mesh"></param>
    /// <param name="angle">
    ///     The smoothing angle. Note that triangles that already share
    ///     the same vertex will be smooth regardless of the angle!
    /// </param>
    public static void RecalculateNormals(this Mesh mesh, float angle)
    {
        var triangles  = mesh.GetTriangles(0);
        var vertices   = mesh.vertices;
        var triNormals = new Vector3[triangles.Length / 3]; //Holds the normal of each triangle
        var normals    = new Vector3[vertices.Length];

        angle = angle * Mathf.Deg2Rad;

        var dictionary = new Dictionary <VertexKey, VertexEntry>(vertices.Length);

        //Goes through all the triangles and gathers up data to be used later
        for (var i = 0; i < triangles.Length; i += 3)
        {
            int i1 = triangles[i];
            int i2 = triangles[i + 1];
            int i3 = triangles[i + 2];

            //Calculate the normal of the triangle
            Vector3 p1       = vertices[i2] - vertices[i1];
            Vector3 p2       = vertices[i3] - vertices[i1];
            Vector3 normal   = Vector3.Cross(p1, p2).normalized;
            int     triIndex = i / 3;
            triNormals[triIndex] = normal;

            VertexEntry entry;
            VertexKey   key;

            //For each of the three points of the triangle
            //  > Add this triangle as part of the triangles they're connected to.

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i1]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i1, triIndex);

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i2]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i2, triIndex);

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i3]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i3, triIndex);
        }

        //Foreach point in space (not necessarily the same vertex index!)
        //{
        //  Foreach triangle T1 that point belongs to
        //  {
        //    Foreach other triangle T2 (including self) that point belongs to and that
        //    meets any of the following:
        //    1) The corresponding vertex is actually the same vertex
        //    2) The angle between the two triangles is less than the smoothing angle
        //    {
        //      > Add to temporary Vector3
        //    }
        //    > Normalize temporary Vector3 to find the average
        //    > Assign the normal to corresponding vertex of T1
        //  }
        //}

        foreach (var value in dictionary.Values)
        {
            for (var i = 0; i < value.Count; ++i)
            {
                var sum = new Vector3();
                for (var j = 0; j < value.Count; ++j)
                {
                    if (value.VertexIndex[i] == value.VertexIndex[j])
                    {
                        sum += triNormals[value.TriangleIndex[j]];
                    }
                    else
                    {
                        float dot = Vector3.Dot(
                            triNormals[value.TriangleIndex[i]],
                            triNormals[value.TriangleIndex[j]]);
                        dot = Mathf.Clamp(dot, -0.99999f, 0.99999f);
                        float acos = Mathf.Acos(dot);
                        if (acos <= angle)
                        {
                            sum += triNormals[value.TriangleIndex[j]];
                        }
                    }
                }

                normals[value.VertexIndex[i]] = sum.normalized;
            }
        }

        mesh.normals = normals;
    }
Beispiel #8
0
        public static void RecalculateNormals(Mesh mesh, float angle)
        {
            var triangles = mesh.triangles;

            var vertices = mesh.vertices;
            var weights  = mesh.boneWeights == null || mesh.boneWeights.Length == 0 ?
                           mesh.vertices.Select(v => new BoneWeight()).ToArray() : mesh.boneWeights;

            var triNormals = new Vector3[triangles.Length / 3];
            var normals    = new Vector3[vertices.Length];

            angle = angle * Mathf.Deg2Rad;

            var dictionary = new Dictionary <VertexKey, VertexEntry>(vertices.Length);

            for (var i = 0; i < triangles.Length; i += 3)
            {
                var i1 = triangles[i];
                var i2 = triangles[i + 1];
                var i3 = triangles[i + 2];

                var p1       = vertices[i2] - vertices[i1];
                var p2       = vertices[i3] - vertices[i1];
                var normal   = Vector3.Cross(p1, p2).normalized;
                int triIndex = i / 3;
                triNormals[triIndex] = normal;

                VertexEntry entry;
                VertexKey   key;

                if (!dictionary.TryGetValue(key = new VertexKey(vertices[i1], weights[i1]), out entry))
                {
                    entry = new VertexEntry();
                    dictionary.Add(key, entry);
                }
                entry.Add(i1, triIndex);

                if (!dictionary.TryGetValue(key = new VertexKey(vertices[i2], weights[i2]), out entry))
                {
                    entry = new VertexEntry();
                    dictionary.Add(key, entry);
                }
                entry.Add(i2, triIndex);

                if (!dictionary.TryGetValue(key = new VertexKey(vertices[i3], weights[i3]), out entry))
                {
                    entry = new VertexEntry();
                    dictionary.Add(key, entry);
                }
                entry.Add(i3, triIndex);
            }
            foreach (var value in dictionary.Values)
            {
                for (var i = 0; i < value.Count; ++i)
                {
                    var sum = new Vector3();
                    for (var j = 0; j < value.Count; ++j)
                    {
                        if (value.VertexIndex[i] == value.VertexIndex[j])
                        {
                            sum += triNormals[value.TriangleIndex[j]];
                        }
                        else
                        {
                            float dot = Vector3.Dot(
                                triNormals[value.TriangleIndex[i]],
                                triNormals[value.TriangleIndex[j]]);
                            dot = Mathf.Clamp(dot, -0.99999f, 0.99999f);
                            float acos = Mathf.Acos(dot);
                            if (acos <= angle)
                            {
                                sum += triNormals[value.TriangleIndex[j]];
                            }
                        }
                    }

                    normals[value.VertexIndex[i]] = sum.normalized;
                }
            }

            mesh.normals = normals;
        }
 public EdgeEntry(uint id, VertexEntry v0, VertexEntry v1) : this()
 {
     this.Id = id;
     this.V0 = v0;
     this.V1 = v1;
 }
    /// <summary>
    ///     Recalculate the normals of a mesh based on an angle threshold. This takes
    ///     into account distinct vertices that have the same position.
    /// </summary>
    /// <param name="mesh"></param>
    /// <param name="angleSameMaterial">
    ///     The smoothing angle. Note that triangles that already share the same vertex will be smooth regardless of the angle!
    ///     If the vertex is not shared then triangle with normals within this angle and with the same material, are smoothed
    /// </param>
    /// <param name="angleDifferentMaterial">
    ///     See angleSameMaterial. But this is if the triangles are of different materials.
    /// </param>
    /// <param name="normalLock">
    ///		If provided, then for each normal in normals[], this says whether or not the vertex for this normal should
    ///		be locked to that provided by normals[]. Otherwise, if false, that normal will be recalculated.
    /// </param>
    /// <param name="providedNormals">
    ///		Paired with normalLock to decide whether we should calculate the normal
    /// </param>
    public static void RecalculateNormals(this Mesh mesh, float angleSameMaterial, float angleDifferentMaterial, bool[] normalLock, Vector3[] providedNormals)
    {
        const float kEpsilon                 = 0.0001f;
        bool        warnedAboutDegenTris     = false;
        bool        warnedAboutZeroSumNormal = false;

        angleSameMaterial      = angleSameMaterial * Mathf.Deg2Rad;
        angleDifferentMaterial = angleDifferentMaterial * Mathf.Deg2Rad;

        if (providedNormals == null)
        {
            // If we were not given provided normals, then we don't do normal lock checking
            normalLock = null;
        }

        var vertices = mesh.vertices;
        var normals  = new Vector3[vertices.Length];
        var pointInSpaceToRefTrisDictionary = new Dictionary <VertexKey, VertexEntry>(vertices.Length);

        if (normalLock != null)
        {
            // Make sure all the arrays are the expected length
            Assert.True(normalLock.Length == providedNormals.Length);
            Assert.True(normalLock.Length == vertices.Length);
        }

        int numSubmeshes      = mesh.subMeshCount;
        int numTotalTriangles = 0;

        for (int submeshIndex = 0; submeshIndex < numSubmeshes; ++submeshIndex)
        {
            int[] triangles = mesh.GetTriangles(submeshIndex);
            numTotalTriangles += triangles.Length / 3;
        }

        var triNormals = new Vector3[numTotalTriangles];           //Holds the normal of each triangle
        int triOffset  = 0;

        for (int submesh_index = 0; submesh_index < numSubmeshes; ++submesh_index)
        {
            int[] triangles = mesh.GetTriangles(submesh_index);

            // Goes through all the triangles and gathers up data to be used later
            for (var i = 0; i < triangles.Length; i += 3)
            {
                int i1 = triangles[i + 0];
                int i2 = triangles[i + 1];
                int i3 = triangles[i + 2];

                int i1_tri_id = 0;
                int i2_tri_id = 0;
                int i3_tri_id = 0;

                //Calculate the normal of the triangle
                Vector3 p1     = vertices[i2] - vertices[i1];
                Vector3 p2     = vertices[i3] - vertices[i1];
                Vector3 normal = Vector3.Cross(p1, p2).normalized;
                if (normal.magnitude < kEpsilon)
                {
                    // Prevent a bad triangle from generating a bad normal
                    if (!warnedAboutDegenTris)
                    {
                        warnedAboutDegenTris = true;
                        Debug.LogWarningFormat("Degenerate triangles found during RecalculateNormals ({0})", mesh.name);
                    }
                    normal = Vector3.forward;
                }
                int triIndex = (i / 3) + triOffset;
                triNormals[triIndex] = normal;

                VertexEntry entry;
                VertexKey   key;

                // For our purposes, each submesh is for a different material
                // But if we should ever have a material represented multiple times
                // in submeshes, then we need to adjust this as needed.
                int materialIndex = submesh_index;

                //For each of the three points of the triangle
                //  Add this triangle as part of the triangles they're connected to.

                // NOTE!!!! We pass false here for triangleIsPortal, because we assume that by the time this gets called, there are no portal triangles in the mesh.
                //  This is not necessarily the case if debugAddPortalsToRenderGeometry is true.  If we want to support that, we will need some way to feed the flag
                //  of whether each triangle is from a portal or not through the UnityEngine.Mesh and into this function somehow. -MFlavin 3/1/2017
                if (!pointInSpaceToRefTrisDictionary.TryGetValue(key = new VertexKey(vertices[i1]), out entry))
                {
                    entry = new VertexEntry();
                    pointInSpaceToRefTrisDictionary.Add(key, entry);
                }
                entry.Add(i1, i1_tri_id, triIndex, materialIndex, false);

                if (!pointInSpaceToRefTrisDictionary.TryGetValue(key = new VertexKey(vertices[i2]), out entry))
                {
                    entry = new VertexEntry();
                    pointInSpaceToRefTrisDictionary.Add(key, entry);
                }
                entry.Add(i2, i2_tri_id, triIndex, materialIndex, false);

                if (!pointInSpaceToRefTrisDictionary.TryGetValue(key = new VertexKey(vertices[i3]), out entry))
                {
                    entry = new VertexEntry();
                    pointInSpaceToRefTrisDictionary.Add(key, entry);
                }
                entry.Add(i3, i3_tri_id, triIndex, materialIndex, false);
            }

            triOffset += triangles.Length / 3;
        }

        //Foreach point in space (not necessarily the same vertex index!)
        //{
        //  Foreach triangle T1 that point belongs to
        //  {
        //    Foreach other triangle T2 (including self) that point belongs to and that
        //    meets any of the following:
        //    1) The corresponding vertex is actually the same vertex
        //    2) The angle between the two triangles is less than the smoothing angle
        //    {
        //      > Add to temporary Vector3
        //    }
        //    > Normalize temporary Vector3 to find the average
        //    > Assign the normal to corresponding vertex of T1
        //  }
        //}
        foreach (var refTriangles in pointInSpaceToRefTrisDictionary.Values)
        {
            for (var i = 0; i < refTriangles.Count; ++i)
            {
                var sum = new Vector3();

                int materialI      = refTriangles.MaterialIndex[i];
                int vertexIndexI   = refTriangles.VertexIndex[i];
                int triangleIndexI = refTriangles.TriangleIndex[i];

                for (var j = 0; j < refTriangles.Count; ++j)
                {
                    int materialJ      = refTriangles.MaterialIndex[j];
                    int vertexIndexJ   = refTriangles.VertexIndex[j];
                    int triangleIndexJ = refTriangles.TriangleIndex[j];

                    if (vertexIndexI == vertexIndexJ)
                    {
                        // This is the same vertex, it is going to be shared no matter what because
                        // the indices point to the same normal.
                        sum += triNormals[triangleIndexJ];
                    }
                    else
                    {
                        float dot = Vector3.Dot(triNormals[triangleIndexI], triNormals[triangleIndexJ]);
                        dot = Mathf.Clamp(dot, -0.99999f, 0.99999f);
                        float acos           = Mathf.Acos(dot);
                        float smoothingAngle = (materialI == materialJ) ? angleSameMaterial : angleDifferentMaterial;
                        if (acos <= smoothingAngle)
                        {
                            // Within the angle, factor it in
                            sum += triNormals[triangleIndexJ];
                        }
                    }
                }

                if (sum.magnitude <= kEpsilon)
                {
                    // Prevent a bad normal from being created
                    if (!warnedAboutZeroSumNormal)
                    {
                        warnedAboutZeroSumNormal = true;
                        Debug.LogWarningFormat("Zero-sum normal found during RecalculateNormals ({0})", mesh.name);
                    }
                    sum = Vector3.forward;
                }

                if (normalLock != null && normalLock[vertexIndexI])
                {
                    // we must take the provided normal
                    normals[vertexIndexI] = providedNormals[vertexIndexI];
                }
                else
                {
                    normals[vertexIndexI] = sum.normalized;
                }
            }
        }

        mesh.normals = normals;
    }
Beispiel #11
0
    public static void Optimize(this BrickMeshInfo mesh, float angle)
    {
        if (mesh == null || mesh.Vertices.Count == 0)
        {
            return;
        }

        var triangles  = mesh.Triangles;
        var vertices   = mesh.Vertices;
        var colors     = mesh.ColorIndices;
        var triNormals = new Vector3[triangles.Count / 3]; //Holds the normal of each triangle

        //Debug.Log(string.Format("Start optimize {0}: vtCnt:{1}, triCnt:{2}, colorCnt:{3}",
        //    mesh.name, vertices.Count, triangles.Count, colors.Count));

        angle = angle * Mathf.Deg2Rad;

        var dictionary = new Dictionary <VertexKey, VertexEntry>(vertices.Count);

        // Set vertex index dictionary
        var vtIndices = new Dictionary <int, VertexIndexEnry>(vertices.Count);

        for (int i = 0; i < vertices.Count; ++i)
        {
            vtIndices.Add(i, new VertexIndexEnry(i));
        }

        // Goes through all the triangles and gathers up data to be used later
        for (var i = 0; i < triangles.Count; i += 3)
        {
            int i1 = triangles[i];
            int i2 = triangles[i + 1];
            int i3 = triangles[i + 2];

            int color1 = colors[i1];
            int color2 = colors[i2];
            int color3 = colors[i3];

            //Calculate the normal of the triangle
            Vector3 p1       = vertices[i2] - vertices[i1];
            Vector3 p2       = vertices[i3] - vertices[i1];
            Vector3 normal   = Vector3.Cross(p1, p2).normalized;
            int     triIndex = i / 3;
            triNormals[triIndex] = normal;

            VertexEntry entry;
            VertexKey   key;

            //For each of the three points of the triangle
            //  > Add this triangle as part of the triangles they're connected to.

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i1]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i1, triIndex, color1);

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i2]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i2, triIndex, color2);

            if (!dictionary.TryGetValue(key = new VertexKey(vertices[i3]), out entry))
            {
                entry = new VertexEntry();
                dictionary.Add(key, entry);
            }
            entry.Add(i3, triIndex, color3);
        }

        bool isShrinkNeeded = false;

        // Shrink vertcies index dictionary
        foreach (var value in dictionary.Values)
        {
            for (var i = 0; i < value.Count; ++i)
            {
                for (var j = i + 1; j < value.Count; ++j)
                {
                    if (value.vertexIndex[i] == value.vertexIndex[j])
                    {
                        continue;
                    }

                    if (value.colorIndex[i] != value.colorIndex[j])
                    {
                        continue;
                    }

                    float dot = Vector3.Dot(
                        triNormals[value.triangleIndex[i]],
                        triNormals[value.triangleIndex[j]]);
                    dot = Mathf.Clamp(dot, -0.99999f, 0.99999f);
                    float acos = Mathf.Acos(dot);

                    if (acos <= angle)
                    {
                        var srcIndex    = value.vertexIndex[j];
                        var targetIndex = value.vertexIndex[i];

                        //Debug.Log(string.Format("Mark replace: {0} to {1}", srcIndex, targetIndex));

                        vtIndices[srcIndex].replaceFlag  = true;
                        vtIndices[srcIndex].replaceIndex = targetIndex;

                        isShrinkNeeded = true;
                    }
                }
            }
        }

        if (isShrinkNeeded)
        {
            List <Vector3> shrinkedVertices = new List <Vector3>();
            List <short>   shrinkedColors   = new List <short>();

            var vtKeys = vtIndices.Keys.ToList();

            int serialIndex = 0;
            foreach (var key in vtKeys)
            {
                if (vtIndices[key].replaceFlag)
                {
                    int firstReplaceIndex = vtIndices[key].replaceIndex;
                    int finalReplaceIndex = firstReplaceIndex;
                    while (vtIndices[finalReplaceIndex].replaceFlag)
                    {
                        finalReplaceIndex = vtIndices[finalReplaceIndex].replaceIndex;
                        if (finalReplaceIndex == firstReplaceIndex)
                        {
                            //Debug.Log(string.Format("Cancle Replace: {0} with {1}", vtIndices[key].replaceIndex, firstReplaceIndex));
                            vtIndices[key].replaceFlag = false;
                            break;
                        }
                    }

                    if (vtIndices[key].replaceFlag)
                    {
                        //Debug.Log(string.Format("Replace: {0} to {1}", vtIndices[key].replaceIndex, finalReplaceIndex));
                        vtIndices[key].replaceIndex = finalReplaceIndex;
                        continue;
                    }
                }

                shrinkedVertices.Add(vertices[key]);
                shrinkedColors.Add(colors[key]);

                vtIndices[key].validPos = serialIndex++;
            }

            for (var i = 0; i < triangles.Count; i++)
            {
                var oriIndex    = triangles[i];
                var resultIndex = vtIndices[oriIndex].replaceFlag ?
                                  vtIndices[vtIndices[oriIndex].replaceIndex].validPos : vtIndices[oriIndex].validPos;
                triangles[i] = resultIndex;
            }

            //Debug.Log(string.Format("Reduced vertices of {0} : {1} to {2}", mesh.name, vertices.Count, shrinkedVertices.Count));

            mesh.Vertices     = shrinkedVertices;
            mesh.ColorIndices = shrinkedColors;
        }
    }