예제 #1
0
        public void TestSmoothWithDuplicate()
        {
            var poly = GetPolygon();

            var options = new ConstraintOptions()
            {
                ConformingDelaunay = true
            };

            var quality = new QualityOptions()
            {
                MinimumAngle = 30.0
            };

            var mesh = poly.Triangulate(options, quality);

            Assert.AreEqual(1, mesh.Vertices
                            .Where(v => v.Type == VertexType.UndeadVertex)
                            .Count());

            quality.MaximumArea = 0.2;

            mesh.Refine(quality, true);

            Assert.AreEqual(1, mesh.Vertices
                            .Where(v => v.Type == VertexType.UndeadVertex)
                            .Count());

            var smoother = new SimpleSmoother();

            // Smooth mesh.
            Assert.IsTrue(smoother.Smooth(mesh, 25) > 0);
        }
예제 #2
0
        // generate mesh
        private TriangleNet.Mesh DxfMesh(Polygon poly)
        {
            // routine to generate a mesh from the contnet of poly
            // Set quality and constraint options.
            var options = new ConstraintOptions()
            {
                ConformingDelaunay = true
            };
            var quality = new QualityOptions()
            {
                MinimumAngle = 15.0, MaximumArea = mds.minimumMeshArea
            };

            // create the mesh
            mesh = (TriangleNet.Mesh)poly.Triangulate(options, quality);

            // make sure there are at least 1000 elements in the mesh
            while (mesh.Triangles.Count < 1000)
            {
                mds.minimumMeshArea = mds.minimumMeshArea / 2;
                quality.MaximumArea = mds.minimumMeshArea;
                mesh = (TriangleNet.Mesh)poly.Triangulate(options, quality);
            }

            // smooth the mesh
            var smoother = new SimpleSmoother();

            smoother.Smooth(mesh);

            return(mesh);
        }
예제 #3
0
        private void Smooth()
        {
            if (mesh == null || settings.ExceptionThrown)
            {
                return;
            }

            if (!mesh.IsPolygon)
            {
                return;
            }

            var smoother = new SimpleSmoother();

            try
            {
                smoother.Smooth(this.mesh);

                statisticView.UpdateStatistic(mesh);

                HandleMeshUpdate();
            }
            catch (Exception ex)
            {
                LockOnException();
                DarkMessageBox.Show("Exception - Smooth", ex.Message, MessageBoxButtons.OK);
            }

            UpdateLog();
        }
예제 #4
0
        public static IMesh CreateMesh()
        {
            // Generate the input geometry.
            var poly = Example3.CreatePolygon(h);

            // Since we want to do CVT smoothing, ensure that the mesh
            // is conforming Delaunay.
            var options = new ConstraintOptions()
            {
                ConformingDelaunay = true
            };

            // Set maximum area quality option (we don't need to set a minimum
            // angle, since smoothing will improve the triangle shapes).
            var quality = new QualityOptions()
            {
                // Given the boundary segment size, we set a maximum
                // area constraint assuming equilateral triangles. The
                // relaxation parameter is chosen to reduce the deviation
                // from this ideal value.
                MaximumArea = (Math.Sqrt(3) / 4 * h * h) * relax
            };

            // Generate mesh using the polygons Triangulate extension method.
            var mesh = poly.Triangulate(options, quality);

            var smoother = new SimpleSmoother();

            // Smooth mesh.
            smoother.Smooth(mesh, 25, .05);

            return(mesh);
        }
예제 #5
0
        public static bool Run(bool print = false)
        {
            // Generate the input geometry.
            var poly = CreatePolygon();

            // Define regions (first one defines the area constraint).
            poly.Regions.Add(new RegionPointer(1.5, 0.0, 1, 0.01));
            poly.Regions.Add(new RegionPointer(2.5, 0.0, 2));

            // Set quality and constraint options.
            var options = new ConstraintOptions()
            {
                ConformingDelaunay = true
            };

            var quality = new QualityOptions()
            {
                MinimumAngle = 25.0,
                VariableArea = true
            };

            //quality.UserTest = (t, area) => t.Label == 1 && area > 0.01;

            var mesh = poly.Triangulate(options, quality);

            var smoother = new SimpleSmoother();

            smoother.Smooth(mesh, 5);

            if (print)
            {
                SvgImage.Save(mesh, "example-5.svg", 500);
            }

            return(mesh.Triangles.Count > 0);
        }
        public static void Tessellate(float minAngle, float maxAngle, float meshAreaFactor, float largestTriangleAreaFactor, int smoothIterations, IList <Vector2> vertices, IList <Edge> edges, IList <int> indices)
        {
            if (vertices.Count < 3)
            {
                return;
            }

            largestTriangleAreaFactor = Mathf.Clamp01(largestTriangleAreaFactor);

            var polygon = new Polygon(vertices.Count);

            for (int i = 0; i < vertices.Count; ++i)
            {
                Vector2 position = vertices[i];
                polygon.Add(new Vertex(position.x, position.y, 1));
            }

            for (int i = 0; i < edges.Count; ++i)
            {
                Edge edge = edges[i];
                polygon.Add(new Segment(polygon.Points[edge.index1], polygon.Points[edge.index2]));
            }

            var mesh      = polygon.Triangulate();
            var statistic = new Statistic();

            statistic.Update((UnityEngine.Experimental.U2D.TriangleNet.Mesh)mesh, 1);

            var maxAreaToApply = (double)Mathf.Max((float)statistic.LargestArea * largestTriangleAreaFactor, (float)(statistic.MeshArea * meshAreaFactor));
            var qualityOptions = new QualityOptions()
            {
                SteinerPoints = 0
            };

            if (maxAreaToApply > 0f)
            {
                qualityOptions.MaximumArea = maxAreaToApply;
            }

            qualityOptions.MinimumAngle = minAngle;
            qualityOptions.MaximumAngle = maxAngle;

            mesh.Refine(qualityOptions, false);
            mesh.Renumber();

            if (smoothIterations > 0)
            {
                try
                {
                    var smoother = new SimpleSmoother();
                    smoother.Smooth(mesh, smoothIterations);
                }
                catch (System.Exception)
                {
                    Debug.Log(TextContent.smoothMeshError);
                }
            }

            vertices.Clear();
            edges.Clear();
            indices.Clear();

            foreach (Vertex vertex in mesh.Vertices)
            {
                vertices.Add(new Vector2((float)vertex.X, (float)vertex.Y));
            }

            foreach (ISegment segment in mesh.Segments)
            {
                edges.Add(new Edge(segment.P0, segment.P1));
            }

            foreach (ITriangle triangle in mesh.Triangles)
            {
                int id0 = triangle.GetVertexID(0);
                int id1 = triangle.GetVertexID(1);
                int id2 = triangle.GetVertexID(2);

                if (id0 < 0 || id1 < 0 || id2 < 0 || id0 >= vertices.Count || id1 >= vertices.Count || id2 >= vertices.Count)
                {
                    continue;
                }

                indices.Add(id0);
                indices.Add(id2);
                indices.Add(id1);
            }
        }
예제 #7
0
        public static Mesh RefineRegions()
        {
            // Generate the input geometry.
            var poly = new Polygon();

            var center = new Point(0, 0);

            // Three concentric circles.
            poly.Add(Example2.Circle(1.0, center, 0.1, 1), center);
            poly.Add(Example2.Circle(2.0, center, 0.1, 2));
            poly.Add(Example2.Circle(3.0, center, 0.3, 3));

            // Define regions.
            poly.Regions.Add(new RegionPointer(1.5, 0.0, 1));
            poly.Regions.Add(new RegionPointer(2.5, 0.0, 2));

            // Set quality and constraint options.
            var options = new ConstraintOptions()
            {
                ConformingDelaunay = true
            };
            var quality = new QualityOptions()
            {
                MinimumAngle = 25.0
            };

            // Generate mesh.
            var mesh = (Mesh)poly.Triangulate(options, quality);

            var smoother = new SimpleSmoother();

            // Smooth mesh and re-apply quality options.
            smoother.Smooth(mesh);
            mesh.Refine(quality);

            // Calculate mesh quality
            var statistic = new QualityMeasure();

            statistic.Update(mesh);

            // Use the minimum triangle area for region refinement
            double area = 1.75 * statistic.AreaMinimum;

            foreach (var t in mesh.Triangles)
            {
                // Set area constraint for all triangles in region 1
                if (t.Label == 1)
                {
                    t.Area = area;
                }
            }

            // Use per triangle area constraint for next refinement
            quality.VariableArea = true;

            // Refine mesh to meet area constraint.
            mesh.Refine(quality);

            // Smooth once again.
            smoother.Smooth(mesh);

            return(mesh);
        }
예제 #8
0
    // Use this for initialization
    void Start( )
    {
        var p = new Polygon();

        p.Add(CosSegements(-Size, -Size, Size, -Size, partsNum, 1));
        p.Add(CosSegements(Size, -Size, Size, Size, partsNum, 2));
        p.Add(CosSegements(Size, Size, -Size, Size, partsNum, 3));
        p.Add(CosSegements(-Size, Size, -Size, -Size, partsNum, 4));

        //var polygon = FileProcessor.Read("Assets/Plugins/Data/box_with_a_hole.poly");

        var options = new ConstraintOptions()
        {
            ConformingDelaunay = true
        };
        var quality = new QualityOptions()
        {
            MinimumAngle = 25F, MaximumArea = 0.1F
        };

        var triMesh = (TriangleNet.Mesh)p.Triangulate(options, quality);

        var smoothing = new SimpleSmoother();

        smoothing.Smooth(triMesh);

        triMesh.Refine(quality);

        triMesh.Renumber( );

        int boneIndex0 = 0;
        var bindposes  = new List <Matrix4x4>();
        var bones      = new List <Transform>();

        var fBoneWeights = new List <BoneWeight>();

        var vertexLookup = new Dictionary <Point, Rigidbody>();

        Root = new GameObject( );
        Root.transform.parent        = transform;
        Root.transform.localRotation = Quaternion.identity;

        var voronoi = new StandardVoronoi(triMesh);

        var triAreas = triMesh.Triangles.Sum(t => t.Area());

        Debug.Log("Tri Areas : " + triAreas);

        Debug.Log("Vor Count : " + voronoi.Faces.Count);
        float SumArea = 0F;

        foreach (var face in voronoi.Faces)
        {
            var origins = face.GetAllVertices();
            //var origins = face.EnumerateEdges().Select(e => (Point) e.Origin);

            if (origins.Count() > 0)
            {
                SumArea += origins.Area( );
                var obj = GameObject.CreatePrimitive(PrimitiveType.Sphere);//new GameObject();
                obj.transform.localScale = Vector3.one * 0.005F;
                var renderer = obj.GetComponent <MeshRenderer> ( );
                if (renderer)
                {
                    renderer.enabled = false;
                }

                //obj.GetComponent<SphereCollider> ( ).enabled = false;

                var center        = face.generator;// origins.MassCenter();
                var worldPosition = transform.TransformPoint(new Vector3(( float )center.x, ( float )center.y, 0));
                obj.transform.position = worldPosition;
                obj.transform.parent   = Root.transform;
                bones.Add(obj.transform);
                bindposes.Add(obj.transform.worldToLocalMatrix * transform.localToWorldMatrix);

                var weight = new BoneWeight();

                weight.boneIndex0 = boneIndex0;
                weight.weight0    = 1.0F;
                fBoneWeights.Add(weight);


                var rigidbody = obj.AddComponent <Rigidbody>();
                rigidbody.useGravity    = false;
                rigidbody.interpolation = RigidbodyInterpolation.Interpolate;
                rigidbody.mass          = origins.Area( ) * KGSM;
                rigidbody.drag          = 4;
                rigidbody.angularDrag   = 2;


                rigidbody.constraints ^= RigidbodyConstraints.FreezeRotation;

                //if ( center.y > 1.9 )                    rigidbody.isKinematic = true;
                if (center.y == Size)
                {
                    rigid_Up.Add(rigidbody);
                }
                else if (center.y == -Size)
                {
                    rigid_Down.Add(rigidbody);
                }
                else if (center.x == Size)
                {
                    rigid_Right.Add(rigidbody);
                }
                else if (center.x == -Size)
                {
                    rigid_Left.Add(rigidbody);
                }
                else
                {
                    others.Add(rigidbody);
                }

                All.Add(rigidbody);

                vertexLookup.Add(center, rigidbody);

                boneIndex0++;
            }

            //SkinnedMeshRenderer.BakeMesh
        }

        foreach (var edge in triMesh.Edges)
        {
            var v0       = triMesh.Vertices.ElementAt(edge.P0);
            var v1       = triMesh.Vertices.ElementAt(edge.P1);
            var pt_0     = new Vector2((float)v0.x, (float)v0.y);
            var pt_1     = new Vector2((float)v1.x, (float)v1.y);
            var distance = Vector2.Distance(pt_0, pt_1);

            var rigid_0 = vertexLookup[v0];
            var rigid_1 = vertexLookup[v1];

            var spring = rigid_0.gameObject.AddComponent <SpringJoint>();
            spring.connectedBody = rigid_1;
            spring.minDistance   = distance * .96F;
            spring.maxDistance   = distance * 1.00F;
            spring.spring        = 8F;
            spring.damper        = 0F;
            spring.autoConfigureConnectedAnchor = false;
            spring.enableCollision     = false;
            spring.connectedAnchor     = spring.anchor = Vector3.zero;
            spring.axis                = Vector3.back;
            spring.tolerance           = 0.01F;
            spring.enablePreprocessing = false;
        }

        var vertices = triMesh.Vertices.Select(v => new Vector3((float)v.x, (float)v.y, 0)).ToArray();

        var triangles = triMesh.Triangles.SelectMany(t => t.vertices.Select(v => v.id)).ToArray();//.Reverse()

        var normals = triMesh.Vertices.Select(v => transform.forward);

        var bounds = triMesh.bounds;
        var l      = bounds.Left;
        var b      = bounds.Bottom;
        var w      = bounds.Width;
        var h      = bounds.Height;
        var uvs    = triMesh.Vertices.Select(v => new Vector2(-(float)((v.x - l) / w), (float)((v.y - b) / h))).ToArray();

        Debug.Log(string.Format("Vertices : {0}, Edge : {1}, Segments : {2}, Triangles : {3}, Holes : {4}",
                                triMesh.Vertices.Count, triMesh.Edges.Count( ), triMesh.Segments.Count, triMesh.Triangles.Count, triMesh.Holes.Count));

        var skinnedRenderer = GetComponent <SkinnedMeshRenderer>();

        //var meshFilter = GetComponent<MeshFilter>();
        //if ( !meshFilter )
        //{
        //    meshFilter = gameObject.AddComponent<MeshFilter> ( );
        //}
        var uniMesh = new Mesh();

        uniMesh.vertices  = vertices;
        uniMesh.triangles = triangles;
        uniMesh.uv        = uvs;
        uniMesh.normals   = normals.ToArray( );

        uniMesh.boneWeights = fBoneWeights.ToArray( );
        uniMesh.bindposes   = bindposes.ToArray( );

        skinnedRenderer.sharedMesh = uniMesh;
        skinnedRenderer.bones      = bones.ToArray( );
        skinnedRenderer.rootBone   = Root.transform;

        //GetComponent<MeshCollider> ( ).sharedMesh = uniMesh;
    }
예제 #9
0
    public PolyGraph(
        int width, int height, int sparcity, int padding,
        int smoothingSteps, ICornerMode cornerMode)
    {
        this.width  = width;
        this.height = height;

        edgeIdCounter   = 0;
        cornerIdCounter = 0;

        faces   = new Dictionary <int, PolyFace>();
        corners = new Dictionary <int, PolyCorner>();
        edges   = new Dictionary <int, PolyEdge>();

        Mesh faceMesh;

        // Randomly generate a delaunay trianglulation to use as faces for the PolyGraph.
        {
            Polygon  polygon = new Polygon();
            Vertex[] bounds  = new Vertex[4] {
                new Vertex(0, 0),
                new Vertex(0, height),
                new Vertex(width, height),
                new Vertex(width, 0)
            };

            PoissonDiscSampler sampler = new PoissonDiscSampler(
                width - 2 * padding, height - 2 * padding, sparcity);


            SimpleSmoother smoother = new SimpleSmoother();

            for (int i = 0; i < 4; i++)
            {
                polygon.Add(new Segment(
                                bounds[i],
                                bounds[(i + 1) % 4],
                                1
                                ), 0);
            }

            foreach (UnityEngine.Vector2 sample in sampler.Samples())
            {
                polygon.Add(new Vertex(sample.x + padding, sample.y + padding));
            }

            faceMesh = (Mesh)polygon.Triangulate(
                new ConstraintOptions()
            {
                ConformingDelaunay = true
            });

            smoother.Smooth(faceMesh, smoothingSteps);
        }

        // Compose and add faces to face dictionary.


        foreach (Vertex vertex in faceMesh.Vertices)
        {
            int xInt = Convert.ToInt32(vertex.x);
            int yInt = Convert.ToInt32(vertex.y);

            bool x0Border = xInt == 0;
            bool x1Border = xInt == width;
            bool y0Border = yInt == 0;
            bool y1Border = yInt == height;

            PolyFace face;

            if (x0Border | x1Border | y0Border | y1Border)
            {
                Vertex borderVertex = new Vertex();
                borderVertex.x = vertex.x;
                borderVertex.y = vertex.y;

                if (x0Border)
                {
                    vertex.x += padding / 2;
                }
                if (x1Border)
                {
                    vertex.x -= padding / 2;
                }
                if (y0Border)
                {
                    vertex.y += padding / 2;
                }
                if (y1Border)
                {
                    vertex.y -= padding / 2;
                }

                PolyCorner borderCorner = new PolyCorner(cornerIdCounter++, borderVertex);
                face = new PolyFace(vertex);
                face.borderCorner = borderCorner;

                if ((x0Border?1:0) + (x1Border?1:0) + (y0Border?1:0) + (y1Border?1:0) == 2)
                {
                    face.isFaceBorderCorner = true;
                }

                borderCorner.surroundingFaces.Add(face);
                face.surroundingCorners.Add(borderCorner);

                corners.Add(borderCorner.id, borderCorner);
            }
            else
            {
                face = new PolyFace(vertex);
            }

            faces.Add(face.id, face);
        }

        foreach (Triangle triangle in faceMesh.triangles)
        {
            // Compose corner dicitonary from remaining faces.
            PolyCorner corner = new PolyCorner(cornerIdCounter++, triangle, cornerMode);

            foreach (Vertex faceVertex in triangle.vertices)
            {
                PolyFace face = faces[faceVertex.id];

                face.surroundingCorners.Add(corner);
                corner.surroundingFaces.Add(face);
            }
            corners.Add(corner.id, corner);
        }

        // Compose and add edges to edge dictionary.
        foreach (TriangleNet.Geometry.Edge meshEdge in faceMesh.Edges)
        {
            // Add pointers between corners faces and edges.
            PolyFace face0 = faces[meshEdge.P0];
            PolyFace face1 = faces[meshEdge.P1];

            face0.neighbouringFaces.Add(face1);
            face1.neighbouringFaces.Add(face0);

            PolyEdge edge = new PolyEdge(edgeIdCounter++, face0, face1);
            edges.Add(edge.id, edge);

            face0.surroundingEdges.Add(edge);
            face1.surroundingEdges.Add(edge);

            foreach (PolyCorner corner in face0.surroundingCorners)
            {
                if (face1.surroundingCorners.Contains(corner))
                {
                    edge.surroundingCorners.Add(corner);
                    corner.surroundingEdges.Add(edge);
                }
            }

            if (edge.surroundingCorners.Count == 1)
            {
                PolyCorner faceCorner0 = face0.borderCorner;
                PolyCorner faceCorner1 = face1.borderCorner;

                Vertex f0 = faceCorner0.vertex;
                Vertex f1 = faceCorner1.vertex;

                Vertex v0 = edge.surroundingCorners[0].vertex;

                Vertex f = f1 - f0;
                Vertex v = v0 - f0;

                Vertex projvf = (((f * v) / Math.Pow(f.Magnitude(), 2)) * f);

                PolyCorner corner = new PolyCorner(cornerIdCounter++, projvf + f0);

                edge.surroundingCorners.Add(corner);
                corner.surroundingEdges.Add(edge);

                corner.surroundingFaces.Add(face1);
                corner.surroundingFaces.Add(face0);

                face0.surroundingCorners.Add(corner);
                face1.surroundingCorners.Add(corner);


                corners.Add(corner.id, corner);

                PolyEdge faceEdge0 = new PolyEdge(edgeIdCounter++, face0);
                PolyEdge faceEdge1 = new PolyEdge(edgeIdCounter++, face1);

                edges.Add(faceEdge0.id, faceEdge0);
                edges.Add(faceEdge1.id, faceEdge1);

                faceEdge0.surroundingCorners.Add(faceCorner0);
                faceEdge0.surroundingCorners.Add(corner);

                faceCorner0.surroundingEdges.Add(faceEdge0);

                faceEdge1.surroundingCorners.Add(faceCorner1);
                faceEdge1.surroundingCorners.Add(corner);

                faceCorner1.surroundingEdges.Add(faceEdge1);
            }
        }

        foreach (KeyValuePair <int, PolyEdge> kvp in edges)
        {
            PolyEdge edge = kvp.Value;
            edge.vertex =
                (edge.surroundingCorners[0].vertex
                 + edge.surroundingCorners[1].vertex) / 2;
        }

        ConstraintOptions options = new ConstraintOptions()
        {
            ConformingDelaunay = false
        };

        foreach (KeyValuePair <int, PolyFace> kvp in faces)
        {
            PolyFace face = kvp.Value;
            face.GenerateMeshData(options);
        }
    }
    // Use this for initialization
    void Start()
    {
        //var geometry = FileReader.ReadPolyFile("Assets/Plugins/Data/superior.poly");

        var p = new Polygon();

        //p.Add ( ClacSegments ( -2, -2, 2, -2, 1 ) );
        //p.Add ( ClacSegments ( 2, -2, 2, 2, 2 ) );
        //p.Add ( ClacSegments ( 2, 2, -2, 2, 3 ) );
        //p.Add ( ClacSegments ( -2, 2, -2, -2, 4 ) );

        p.Add(ClacSegments(-3, -3, 3, -3, 1));
        p.Add(ClacSegments(3, -3, 3, 3, 2));
        p.Add(ClacSegments(3, 3, -3, 3, 3));
        p.Add(ClacSegments(-3, 3, -3, -3, 4));

        // Add the outer box contour with boundary marker 1.
        // p.Add ( new Contour ( new Vertex [ 4 ]
        //{
        //   new Vertex(-3,-3, 1),
        //   new Vertex(3, -3, 1),
        //   new Vertex(3, 3, 1),
        //   new Vertex(-3, 3, 1)
        //}, 1 ) );

        // p.Add ( new Contour ( new Vertex [ 4 ]
        //{
        // new Vertex(-2.9,-2.9, 1),
        // new Vertex(2.9, -2.9, 1),
        // new Vertex(2.9, 2.9, 1),
        // new Vertex(-2.9, 2.9, 1)
        //}, 1 ) );

        // Add the inner box contour with boundary marker 2.
        p.Add(new Contour(new Vertex [4]
        {
            new Vertex(1.0, 1.0, 2),
            new Vertex(2.0, 1.0, 2),
            new Vertex(2.0, 2.0, 2),
            new Vertex(1.0, 2.0, 2)
        }, 5)
              , new Point(1.5, 1.5)); // Make it a hole.

        //var polygon = FileProcessor.Read("Assets/Plugins/Data/box_with_a_hole.poly");

        var options = new ConstraintOptions()
        {
            ConformingDelaunay = true
        };
        var quality = new QualityOptions()
        {
            MinimumAngle = 25F, MaximumArea = 0.04F
        };

        var triMesh = (TriangleNet.Mesh)p.Triangulate(options, quality);

        var smoothing = new SimpleSmoother();

        smoothing.Smooth(triMesh);

        triMesh.Refine(quality, true);

        triMesh.Renumber( );

        //var bounds = new Rectangle(-1.0, -1.0, 2.0, 2.0);

        //var triMesh = GenericMesher.StructuredMesh(bounds, 20, 20);

        var vertices  = triMesh.Vertices.Select(v => new Vector3((float)v.x, (float)v.y, 0)).ToArray();
        var triangles = triMesh.Triangles.SelectMany(t => t.vertices.Select(v => v.id)).ToArray();//.Reverse()
        var normals   = triMesh.Vertices.Select(v => transform.forward).ToArray();

        var bounds = triMesh.bounds;
        var l      = bounds.Left;
        var b      = bounds.Bottom;
        var w      = bounds.Width;
        var h      = bounds.Height;
        var uvs    = triMesh.Vertices.Select(v => new Vector2(-(float)((v.x - l) / w), (float)((v.y - b) / h))).ToArray();

        var skinnedRenderer = GetComponent <SkinnedMeshRenderer>();
        var uniMesh         = new Mesh( );

        uniMesh.vertices  = vertices;
        uniMesh.triangles = triangles;
        uniMesh.uv        = uvs;
        uniMesh.normals   = normals;

        skinnedRenderer.sharedMesh = uniMesh;

        var cloth = GetComponent <Cloth>();

        if (!cloth)
        {
            cloth = gameObject.AddComponent <Cloth> ( );
        }

        var coes = new List <ClothSkinningCoefficient>();

        foreach (var v in vertices)
        {
            coes.Add(new ClothSkinningCoefficient( )
            {
                maxDistance = 10, collisionSphereDistance = 0.1F
            });
        }

        cloth.coefficients = coes.ToArray( );

        ClothSphereColliderPair pair = new ClothSphereColliderPair(sphereFirst, null);

        cloth.sphereColliders = new ClothSphereColliderPair [] { pair };

        //cloth.externalAcceleration = new Vector3 ( 0, -10, 0 );

        cloth.stretchingStiffness = 0.9F;
        cloth.bendingStiffness    = 0.1F;

        cloth.collisionMassScale = 0.1F;
        cloth.friction           = 1F;

        cloth.SetEnabledFading(true);
        cloth.sleepThreshold = 0.1F;

        cloth.damping = 0.2F;
    }
    // Use this for initialization
    void Start()
    {
        var p = new Polygon();

        //Add the outer box contour with boundary marker 1.
        p.Add(new Contour(new Vertex [4]
        {
            new Vertex(-3, -3, 1),
            new Vertex(3, -3, 1),
            new Vertex(3, 3, 1),
            new Vertex(-3, 3, 1)
        }, 1));

        var options = new ConstraintOptions()
        {
            ConformingDelaunay = true
        };
        var quality = new QualityOptions()
        {
            MinimumAngle = 25F, MaximumArea = 0.04F
        };

        var triMesh = (TriangleNet.Mesh)p.Triangulate(options, quality);

        var smoothing = new SimpleSmoother();

        smoothing.Smooth(triMesh);

        triMesh.Refine(quality, true);

        triMesh.Renumber( );

        var vertices  = triMesh.Vertices.Select(v => new Vector3((float)v.x, (float)v.y, 0)).ToArray();
        var triangles = triMesh.Triangles.SelectMany(t => t.vertices.Select(v => v.id)).ToArray();//.Reverse()
        var normals   = triMesh.Vertices.Select(v => transform.forward).ToArray();

        var bounds = triMesh.bounds;
        var l      = bounds.Left;
        var b      = bounds.Bottom;
        var w      = bounds.Width;
        var h      = bounds.Height;
        var uvs    = triMesh.Vertices.Select(v => new Vector2(-(float)((v.x - l) / w), (float)((v.y - b) / h))).ToArray();

        //SkinnedMeshRenderer
        var skinnedRenderer = GetComponent <SkinnedMeshRenderer>();
        var uniMesh         = new Mesh( );

        uniMesh.vertices  = vertices;
        uniMesh.triangles = triangles;
        uniMesh.uv        = uvs;
        uniMesh.normals   = normals;


        //Bones

        int boneIndex0 = 0;
        var bindposes  = new List <Matrix4x4>();
        var bones      = new List <Transform>();

        var fBoneWeights = new List <BoneWeight>();

        Root = new GameObject( );
        Root.transform.parent        = transform;
        Root.transform.localRotation = Quaternion.identity;

        var handler = new GameObject();

        handler.name                    = "Handler";
        handler.transform.parent        = Root.transform;
        handler.transform.localRotation = Quaternion.identity;


        foreach (var vertex in triMesh.Vertices)                        //.Where(v=>v.y > 2.9F) )
        {
            var obj = GameObject.CreatePrimitive(PrimitiveType.Sphere); //new GameObject();

            obj.transform.localScale = Vector3.one * 0.1F;
            var renderer = obj.GetComponent <MeshRenderer> ( );
            if (renderer)
            {
                renderer.enabled = false;
            }
            var worldPosition = transform.TransformPoint(new Vector3(( float )vertex.x, ( float )vertex.y, 0));
            obj.transform.position = worldPosition;
            if (vertex.y > 2.9F)
            {
                obj.name             = "HERE";
                obj.transform.parent = handler.transform;
            }
            else
            {
                obj.transform.parent = Root.transform;
            }

            bones.Add(obj.transform);
            bindposes.Add(obj.transform.worldToLocalMatrix * transform.localToWorldMatrix);

            var weight = new BoneWeight();

            weight.boneIndex0 = boneIndex0;
            weight.weight0    = 1.0F;
            fBoneWeights.Add(weight);

            boneIndex0++;
        }

        uniMesh.boneWeights = fBoneWeights.ToArray( );
        uniMesh.bindposes   = bindposes.ToArray( );

        skinnedRenderer.sharedMesh = uniMesh;
        skinnedRenderer.bones      = bones.ToArray( );
        skinnedRenderer.rootBone   = Root.transform;

        //Cloth

        var cloth = GetComponent <Cloth>();

        if (!cloth)
        {
            cloth = gameObject.AddComponent <Cloth> ( );
        }

        var coes = new List <ClothSkinningCoefficient>();

        foreach (var v in vertices)
        {
            if (v.y < 2.9F)
            {
                coes.Add(new ClothSkinningCoefficient( )
                {
                    maxDistance = 10, collisionSphereDistance = 0.1F
                });
            }
            else
            {
                coes.Add(new ClothSkinningCoefficient( )
                {
                    maxDistance = 0, collisionSphereDistance = 0.1F
                });
            }
        }

        cloth.coefficients = coes.ToArray( );

        ClothSphereColliderPair pair = new ClothSphereColliderPair(sphereFirst, null);

        cloth.sphereColliders = new ClothSphereColliderPair [] { pair };

        //cloth.externalAcceleration = new Vector3 ( 0, -10, 0 );

        cloth.stretchingStiffness = 0.9F;
        cloth.bendingStiffness    = 0.1F;

        cloth.collisionMassScale = 0.1F;
        cloth.friction           = 1F;

        cloth.SetEnabledFading(true);
        cloth.sleepThreshold = 0.1F;

        cloth.damping = 0.2F;
    }