public static void RandomiseTriangleOrder(Mesh mesh)
        {
            var OldTriangles = new List <int> (mesh.triangles);
            var NewTriangles = new List <int> ();

            using (var Progress = new ScopedProgressBar("Randomising triangle order"))
            {
                var OriginalTriangleCount = OldTriangles.Count;

                //	move a random set of indexes to the new list
                while (OldTriangles.Count > 0)
                {
                    var TriangleIndex = Random.Range(0, OldTriangles.Count);
                    TriangleIndex -= TriangleIndex % 3;
                    if (TriangleIndex % 3 != 0)
                    {
                        throw new System.Exception("Picked triangle index not at triangle start");
                    }
                    NewTriangles.Add(OldTriangles [TriangleIndex + 0]);
                    NewTriangles.Add(OldTriangles [TriangleIndex + 1]);
                    NewTriangles.Add(OldTriangles [TriangleIndex + 2]);
                    OldTriangles.RemoveRange(TriangleIndex, 3);
                    Progress.SetProgress("Shuffling", NewTriangles.Count, OriginalTriangleCount, 100);
                }
            }

            mesh.triangles = NewTriangles.ToArray();
        }
    static public List <Vector2> ExtractPoints(Texture Image)
    {
        //	find the middle of the white pixels
        var Texture2    = SaveTextureToPng.GetTexture2D(Image, false);
        var Pixels      = Texture2.GetPixels();
        var MatchColour = Color.white;

        System.Func <Color, Color, float> GetColourMatchScore = (Source, Match) =>
        {
            var Distance = Source.GetHSVDistance(Match);
            return(1 - Distance);
        };

        System.Func <int, int, float> GetWhiteScore = (x, y) =>
        {
            var i      = x + y * Texture2.width;
            var Colour = Pixels[i];
            return(GetColourMatchScore(Colour, MatchColour));
        };

        float?BestScore = null;
        int   BestX = 0, BestY = 0;

        using (var Progress = new ScopedProgressBar("Extracting pixel scores"))
        {
            var NotifyRate = 1;
            var maxi       = Texture2.height * Texture2.width;
            for (int y = 0; y < Texture2.height; y++)
            {
                for (int x = 0; x < Texture2.width; x++)
                {
                    var i = x + y * Texture2.width;
                    if (x == 0)
                    {
                        Progress.SetProgress("Extracting pixels", i, maxi, NotifyRate);
                    }
                    var Score = GetWhiteScore(x, y);
                    if (!BestScore.HasValue || Score > BestScore.Value && Score > 0)
                    {
                        BestScore = Score;
                        BestX     = x;
                        BestY     = y;
                    }
                }
            }
        }

        //	convert best to uv
        var Bestu  = BestX / (float)Texture2.width;
        var Bestv  = BestY / (float)Texture2.height;
        var Points = new List <Vector2>();

        Points.Add(new Vector2(Bestu, Bestv));

        return(Points);
    }
        public static void SetMeshUV0ToTriangleIndex(Mesh mesh)
        {
            var m = mesh;

            var TriangleIndexes = m.triangles;

                        #if UNITY_EDITOR
            if (TriangleIndexes.Length != m.vertexCount)
            {
                var DialogResult = EditorUtility.DisplayDialog("Error", "Assigning triangle indexes to attributes probably won't work as expected for meshes sharing vertexes.", "Continue", "Cancel");
                if (!DialogResult)
                {
                    throw new System.Exception("Aborted assignment of UV triangle indexes");
                }
            }
                        #endif

            using (var Progress = new ScopedProgressBar("Setting UVs")) {
                var Uvs = new Vector2[m.vertexCount];
                {
                    var v2 = new Vector2();                             //	avoid allocs
                    for (int t = 0; t < TriangleIndexes.Length; t += 3)
                    {
                        if (t % 100 == 0)
                        {
                            Progress.SetProgress("Setting UV of triangle", t / 3, TriangleIndexes.Length / 3);
                        }

                        for (int i = 0; i < 3; i++)
                        {
                            var iv = TriangleIndexes [t + i];
                            v2.x     = t / 3;
                            v2.y     = i;
                            Uvs [iv] = v2;
                        }
                    }
                }
                m.uv = Uvs;
                m.UploadMeshData(true);
                                #if UNTIY_EDITOR
                AssetDatabase.SaveAssets();
                                #endif
            }
        }
        public static void SetMeshUV2ToRandomPerTriangle(MenuCommand menuCommand)
        {
            var mf = menuCommand.context as MeshFilter;
            var m  = mf.sharedMesh;

            var TriangleIndexes = m.triangles;

            if (TriangleIndexes.Length != m.vertexCount)
            {
                var DialogResult = EditorUtility.DisplayDialog("Error", "Assigning triangle indexes to attributes probably won't work as expected for meshes sharing vertexes.", "Continue", "Cancel");
                if (!DialogResult)
                {
                    throw new System.Exception("Aborted assignment of UV triangle indexes");
                }
            }

            using (var Progress = new ScopedProgressBar("Setting UVs")) {
                var Uvs = new Vector3[m.vertexCount];
                {
                    var random3 = new Vector3(0, 0, 0);
                    for (int t = 0; t < TriangleIndexes.Length; t += 3)
                    {
                        Progress.SetProgress("Setting UV of triangle", t / 3, TriangleIndexes.Length / 3, 100);

                        float tTime = t / (float)TriangleIndexes.Length;
                        random3.x = Mathf.PerlinNoise(tTime, 0.0f);
                        random3.y = Mathf.PerlinNoise(0.0f, tTime);
                        random3.z = Random.Range(0.0f, 1.0f);

                        Uvs [TriangleIndexes [t + 0]] = random3;
                        Uvs [TriangleIndexes [t + 1]] = random3;
                        Uvs [TriangleIndexes [t + 2]] = random3;
                    }
                }
                m.SetUVs(2, new List <Vector3>(Uvs));
                m.UploadMeshData(true);
                AssetDatabase.SaveAssets();
            }
        }
        public static void SetMeshUV1ToTriangleBarycentricCoords(MenuCommand menuCommand)
        {
            var mf = menuCommand.context as MeshFilter;
            var m  = mf.sharedMesh;

            var TriangleIndexes = m.triangles;

            if (TriangleIndexes.Length != m.vertexCount)
            {
                var DialogResult = EditorUtility.DisplayDialog("Error", "Assigning triangle indexes to attributes probably won't work as expected for meshes sharing vertexes.", "Continue", "Cancel");
                if (!DialogResult)
                {
                    throw new System.Exception("Aborted assignment of UV triangle indexes");
                }
            }

            using (var Progress = new ScopedProgressBar("Setting UVs")) {
                var Uvs = new Vector3[m.vertexCount];
                {
                    var barya = new Vector3(1, 0, 0);
                    var baryb = new Vector3(0, 1, 0);
                    var baryc = new Vector3(0, 0, 1);
                    for (int t = 0; t < TriangleIndexes.Length; t += 3)
                    {
                        Progress.SetProgress("Setting UV of triangle", t / 3, TriangleIndexes.Length / 3, 100);

                        Uvs [TriangleIndexes [t + 0]] = barya;
                        Uvs [TriangleIndexes [t + 1]] = baryb;
                        Uvs [TriangleIndexes [t + 2]] = baryc;
                    }
                }
                m.SetUVs(1, new List <Vector3>(Uvs));
                m.UploadMeshData(true);
                AssetDatabase.SaveAssets();
            }
        }
        public static void UnshareTrianglesOfMesh(ref Mesh mesh)
        {
            var OldTriangles = mesh.triangles;
            var OldPositions = mesh.vertices;
            var OldNormals   = mesh.normals;
            var OldUv1s      = mesh.uv;
            var OldUv2s      = mesh.uv2;
            var OldUv3s      = mesh.uv3;
            var OldColourfs  = mesh.colors;
            var OldColour32s = mesh.colors32;

            List <Vector3> NewPositons     = NullIfEmpty(OldPositions) != null ? new List <Vector3> () : null;
            List <Vector3> NewNormals      = NullIfEmpty(OldNormals) != null ? new List <Vector3> () : null;
            List <Vector2> NewUv1s         = NullIfEmpty(OldUv1s) != null ? new List <Vector2> () : null;
            List <Vector2> NewUv2s         = NullIfEmpty(OldUv2s) != null ? new List <Vector2> () : null;
            List <Vector2> NewUv3s         = NullIfEmpty(OldUv3s) != null ? new List <Vector2> () : null;
            List <Color>   NewColourfs     = NullIfEmpty(OldColourfs) != null ? new List <Color> () : null;
            List <Color32> NewColour32s    = NullIfEmpty(OldColour32s) != null ? new List <Color32> () : null;
            List <int>     TriangleIndexes = new List <int> ();

            bool PromptShown = false;

            System.Func <Vertex, Vertex, Vertex, bool> PushTriangle = (a, b, c) => {
                //	hit limits
                if (TriangleIndexes.Count >= 65000 && !PromptShown)
                {
                                        #if UNITY_EDITOR
                    var DialogResult = EditorUtility.DisplayDialogComplex("Error", "Hit vertex limit with " + (TriangleIndexes.Count / 3) + " triangles (" + TriangleIndexes.Count + " vertexes.", "Stop Here", "Abort", "Overflow");
                                        #else
                    var DialogResult = 1;
                                        #endif
                    PromptShown = true;

                    //	stop
                    if (DialogResult == 0)
                    {
                        return(false);
                    }
                    else if (DialogResult == 2)                         //	continue/overflow
                    {
                    }
                    else if (DialogResult == 1)                         //	abort
                    {
                        throw new System.Exception("Aborted export");
                    }
                    else
                    {
                        throw new System.Exception("unknown dialog result " + DialogResult);
                    }
                }

                if (NewPositons != null)
                {
                    NewPositons.Add(a.position);
                    NewPositons.Add(b.position);
                    NewPositons.Add(c.position);
                }
                if (NewNormals != null)
                {
                    NewNormals.Add(a.normal);
                    NewNormals.Add(b.normal);
                    NewNormals.Add(c.normal);
                }
                if (NewUv1s != null)
                {
                    NewUv1s.Add(a.uv1);
                    NewUv1s.Add(b.uv1);
                    NewUv1s.Add(c.uv1);
                }
                if (NewUv2s != null)
                {
                    NewUv2s.Add(a.uv2);
                    NewUv2s.Add(b.uv2);
                    NewUv2s.Add(c.uv2);
                }
                if (NewUv3s != null)
                {
                    NewUv3s.Add(a.uv3);
                    NewUv3s.Add(b.uv3);
                    NewUv3s.Add(c.uv3);
                }
                if (NewColourfs != null)
                {
                    NewColourfs.Add(a.colourf);
                    NewColourfs.Add(b.colourf);
                    NewColourfs.Add(c.colourf);
                }
                if (NewColour32s != null)
                {
                    NewColour32s.Add(a.colour32);
                    NewColour32s.Add(b.colour32);
                    NewColour32s.Add(c.colour32);
                }

                TriangleIndexes.Add(TriangleIndexes.Count);
                TriangleIndexes.Add(TriangleIndexes.Count);
                TriangleIndexes.Add(TriangleIndexes.Count);

                return(true);
            };

            using (var Progress = new ScopedProgressBar("Splitting mesh"))
            {
                var va = new Vertex();
                var vb = new Vertex();
                var vc = new Vertex();

                for (int t = 0; t < OldTriangles.Length; t += 3)
                {
                    Progress.SetProgress("Adding triangle", t / 3, OldTriangles.Length / 3, 100);

                    var ia = OldTriangles [t];
                    var ib = OldTriangles [t + 1];
                    var ic = OldTriangles [t + 2];

                    SafeSet(ref va.position, OldPositions, ia);
                    SafeSet(ref vb.position, OldPositions, ib);
                    SafeSet(ref vc.position, OldPositions, ic);

                    SafeSet(ref va.normal, OldNormals, ia);
                    SafeSet(ref vb.normal, OldNormals, ib);
                    SafeSet(ref vc.normal, OldNormals, ic);

                    SafeSet(ref va.uv1, OldUv1s, ia);
                    SafeSet(ref vb.uv1, OldUv1s, ib);
                    SafeSet(ref vc.uv1, OldUv1s, ic);

                    SafeSet(ref va.uv2, OldUv2s, ia);
                    SafeSet(ref vb.uv2, OldUv2s, ib);
                    SafeSet(ref vc.uv2, OldUv2s, ic);

                    SafeSet(ref va.uv3, OldUv3s, ia);
                    SafeSet(ref vb.uv3, OldUv3s, ib);
                    SafeSet(ref vc.uv3, OldUv3s, ic);

                    SafeSet(ref va.colourf, OldColourfs, ia);
                    SafeSet(ref vb.colourf, OldColourfs, ib);
                    SafeSet(ref vc.colourf, OldColourfs, ic);

                    SafeSet(ref va.colour32, OldColour32s, ia);
                    SafeSet(ref vb.colour32, OldColour32s, ib);
                    SafeSet(ref vc.colour32, OldColour32s, ic);

                    if (!PushTriangle(va, vb, vc))
                    {
                        break;
                    }
                }
            }

            var OldBounds = mesh.bounds;

            mesh.Clear();
            if (NewPositons != null)
            {
                mesh.SetVertices(NewPositons);
            }
            if (NewNormals != null)
            {
                mesh.SetNormals(NewNormals);
            }
            if (NewUv1s != null)
            {
                mesh.SetUVs(0, NewUv1s);
            }
            if (NewUv2s != null)
            {
                mesh.SetUVs(1, NewUv2s);
            }
            if (NewUv3s != null)
            {
                mesh.SetUVs(1, NewUv3s);
            }
            if (NewColourfs != null)
            {
                mesh.SetColors(NewColourfs);
            }
            if (NewColour32s != null)
            {
                mesh.SetColors(NewColour32s);
            }
            if (TriangleIndexes != null)
            {
                mesh.SetIndices(TriangleIndexes.ToArray(), MeshTopology.Triangles, 0);
            }
            mesh.bounds = OldBounds;
            mesh.UploadMeshData(false);
        }