public Mesh CreateMeshFromPoints(bool combine) { if (spriteRenderer != null && points.Length > 2) { int pointNum = points.Length; if (combine && combineMesh != null) { pointNum = points.Length + combineMesh.vertices.Length; } //Create triangle.NET geometry TriangleNet.Geometry.InputGeometry geometry = new TriangleNet.Geometry.InputGeometry(pointNum); geometry.AddPolygon(points); if (combine && combineMesh != null) { geometry.AddPolygon(combineMesh.vertices.Select(x => (Vector2)x).ToArray()); } //Triangulate TriangleNet.Mesh triangleMesh = new TriangleNet.Mesh(); triangleMesh.Triangulate(geometry); //transform vertices points = new Vector2[triangleMesh.Vertices.Count]; Vector3[] vertices = new Vector3[triangleMesh.Vertices.Count]; Vector3[] normals = new Vector3[triangleMesh.Vertices.Count]; int n = 0; foreach(TriangleNet.Data.Vertex v in triangleMesh.Vertices) { points[n] = new Vector2((float)v.X, (float)v.Y); vertices[n] = new Vector3((float)v.X, (float)v.Y, 0); normals[n]=new Vector3(0,0,-1); n++; } //transform triangles int[] triangles = triangleMesh.Triangles.ToUnityMeshTriangleIndices(); mesh.Clear(); mesh = new Mesh(); mesh.vertices = vertices; mesh.triangles = triangles; mesh.uv = genUV(mesh.vertices); mesh.normals = normals; return mesh; } else { return null; } }
public override InputGeometry Generate(double param0, double param1, double param2) { // Number of points on the outer circle int n = GetParamValueInt(0, param0); int count, npoints; double radius = GetParamValueInt(1, param1); // Step size on the outer circle double h = 2 * Math.PI * radius / n; // Current radius and step size double r, dphi; InputGeometry input = new InputGeometry(n + 1); // Inner cirlce (radius = 1) r = 1; npoints = (int)(2 * Math.PI * r / h); dphi = 2 * Math.PI / npoints; for (int i = 0; i < npoints; i++) { input.AddPoint(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 1); input.AddSegment(i, (i + 1) % npoints, 1); } count = input.Count; // Center cirlce r = (radius + 1) / 2.0; npoints = (int)(2 * Math.PI * r / h); dphi = 2 * Math.PI / npoints; for (int i = 0; i < npoints; i++) { input.AddPoint(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 2); input.AddSegment(count + i, count + (i + 1) % npoints, 2); } count = input.Count; // Outer cirlce r = radius; npoints = (int)(2 * Math.PI * r / h); dphi = 2 * Math.PI / npoints; for (int i = 0; i < npoints; i++) { input.AddPoint(r * Math.Cos(i * dphi), r * Math.Sin(i * dphi), 3); input.AddSegment(count + i, count + (i + 1) % npoints, 3); } input.AddHole(0, 0); // Regions: |++++++|++++++|---| // r 1 0 input.AddRegion((r + 3.0) / 4.0, 0, 1); input.AddRegion((3 * r + 1.0) / 4.0, 0, 2); return input; }
public void HandleMeshImport(InputGeometry geometry, Mesh mesh) { // Previous mesh stats lbNumVert2.Text = "-"; lbNumTri2.Text = "-"; lbNumSeg2.Text = "-"; }
public Mesh CreateMeshFromPoints(bool combine) { if (spriteRenderer != null && points.Length > 2) { int pointNum = points.Length; if (combine && combineMesh != null) { pointNum = points.Length + combineMesh.vertices.Length; } //Create triangle.NET geometry TriangleNet.Geometry.InputGeometry geometry = new TriangleNet.Geometry.InputGeometry(pointNum); geometry.AddPolygon(points); if (combine && combineMesh != null) { geometry.AddPolygon(combineMesh.vertices.Select(x => (Vector2)x).ToArray()); } //Triangulate TriangleNet.Mesh triangleMesh = new TriangleNet.Mesh(); triangleMesh.Triangulate(geometry); //transform vertices points = new Vector2[triangleMesh.Vertices.Count]; Vector3[] vertices = new Vector3[triangleMesh.Vertices.Count]; Vector2[] uvs = new Vector2[triangleMesh.Vertices.Count]; Vector3[] normals = new Vector3[triangleMesh.Vertices.Count]; int n = 0; foreach (TriangleNet.Data.Vertex v in triangleMesh.Vertices) { points[n] = new Vector2((float)v.X, (float)v.Y); vertices[n] = new Vector3((float)v.X, (float)v.Y, 0); normals[n] = new Vector3(0, 0, -1); n++; } //transform triangles int[] triangles = triangleMesh.Triangles.ToUnityMeshTriangleIndices(); mesh.Clear(); mesh = new Mesh(); mesh.vertices = vertices; mesh.triangles = triangles; mesh.uv = genUV(mesh.vertices); mesh.normals = normals; return(mesh); } else { return(null); } }
/// <summary> /// Rebuild the input geometry. /// </summary> private InputGeometry Rebuild() { InputGeometry geometry = new InputGeometry(mesh.vertices.Count); foreach (var vertex in mesh.vertices.Values) { geometry.AddPoint(vertex.x, vertex.y, vertex.mark); } foreach (var segment in mesh.subsegs.Values) { geometry.AddSegment(segment.P0, segment.P1, segment.Boundary); } foreach (var hole in mesh.holes) { geometry.AddHole(hole.x, hole.y); } foreach (var region in mesh.regions) { geometry.AddRegion(region.point.x, region.point.y, region.id); } return geometry; }
/// <summary> /// Add a polygon ring to the geometry and make it a hole. /// </summary> /// <remarks> /// WARNING: This works for convex polygons, but not for non-convex regions in general. /// </remarks> /// <param name="points">List of points which make up the hole.</param> /// <param name="mark">Common boundary mark for all segments of the hole.</param> public static void AddRingAsHole(this InputGeometry geometry, IEnumerable<TriangleNet.Geometry.Point> points, int mark = 0) { // Save the current number of points. int N = geometry.Count; int m = 0; foreach (var pt in points) { geometry.AddPoint(pt.X, pt.Y, pt.Boundary, pt.Attributes); m++; } for (int i = 0; i < m; i++) { geometry.AddSegment(N + i, N + ((i + 1) % m), mark); } //a lényeg az hogy kell egy a lyukon lévő pont,hogy jelezze hogy az egy lyuk poligon... a legegyszerübb trükk a következő, az egybefüggő (akár konkáv) poligont háromszögesítem, ezzel nincs gond, ezután kiválasztok egy testzőleges háromszöget, és veszem annak a középpontját..ez már tuti hogy a nagy poligon belső pontja TriangleNetMesh mesh = new TriangleNetMesh(); var inputGeometry = new InputGeometry(); inputGeometry.AddRing(points); mesh.Triangulate(inputGeometry); var firstTriangle = new List<Triangle>(mesh.Triangles)[0]; double x = 0.0; double y = 0.0; for (int iii = 0; iii < 3; iii++) { var vertex = firstTriangle.GetVertex(iii); x += vertex.X; y += vertex.Y; } geometry.AddHole(x / 3, y / 3); }
public WaterSurfacePolygon(List<Point> points) { mesh = new TriangleNet.Mesh(); mesh.Behavior.Quality = true; this.points = points; triangleNormals = new List<Point>(); trianglePlaneEquationDs = new List<double>(); InputGeometry geomtery = new InputGeometry(); for (int i = 0; i < points.Count; i++) { Point p = points[i]; if (i == 0) { minX = maxX = p.X; minY = maxY = p.Y; minZ = maxZ = p.Z; } else { minX = Math.Min(p.X, minX); maxX = Math.Max(p.X, maxX); minY = Math.Min(p.Y, minY); maxY = Math.Max(p.Y, maxY); minZ = Math.Min(p.Z, minZ); maxZ = Math.Max(p.Z, maxZ); } geomtery.AddPoint(p.X, p.Y, 0, p.Z); //add segments if (i > 0) { geomtery.AddSegment(i - 1, i, 0); } if (i == points.Count - 1) { geomtery.AddSegment(i, 0, 0); } } mesh.Triangulate(geomtery); triangles = new List<TriangleNet.Data.Triangle>(); foreach (TriangleNet.Data.Triangle tr in mesh.Triangles) { if (tr.P0 < points.Count && tr.P1 < points.Count && tr.P2 < points.Count) { triangles.Add(tr); } } calculateNormalsAndDs(); }
public static void Write(InputGeometry geometry, string filename) { using (StreamWriter writer = new StreamWriter(filename)) { WritePoints(writer, geometry.Points, geometry.Count); WriteSegments(writer, geometry.Segments); WriteHoles(writer, geometry.Holes); } }
private static Mesh buildMesh(Dictionary<Point, Color> pointIndex) { InputGeometry g = new InputGeometry(); foreach (var value in pointIndex) { g.AddPoint(value.Key.X, value.Key.Y); } Mesh m = new Mesh(); m.Triangulate(g); return m; }
/// <summary> /// Reads a mesh from .node, .poly or .ele files. /// </summary> public static void Read(string filename, out InputGeometry geometry, out List<ITriangle> triangles) { triangles = null; FileReader.Read(filename, out geometry); //string path = Path.ChangeExtension(filename, ".ele"); //if (File.Exists(path) && geometry != null) //{ // triangles = FileReader.ReadEleFile(path); //} }
private Mesh TriangulateMesh() { if (verts.Count > 2) { var tnMesh = new TriangleNet.Mesh(); var input = new TriangleNet.Geometry.InputGeometry(); var localVertices = verts.Select(v => spriteRenderer.transform.InverseTransformPoint(v.position)).ToArray(); for (int i = 0; i < verts.Count; i++) { verts[i].index = i; input.AddPoint(verts[i].position.x, verts[i].position.y); } foreach (var seg in segments) { if (!seg.IsDeleted()) { input.AddSegment(seg.first.index, seg.second.index); } } foreach (var hole in holes) { input.AddHole(hole.x, hole.y); } tnMesh.Triangulate(input); try { Mesh mesh = new Mesh(); mesh.vertices = localVertices; mesh.triangles = tnMesh.Triangles.ToUnityMeshTriangleIndices(); mesh.uv = genUV(mesh.vertices); mesh.RecalculateBounds(); mesh.RecalculateNormals(); return(mesh); } catch { Debug.LogError("Mesh topology was wrong. Make sure you dont have intersecting edges."); throw; } } else { return(null); } }
/// <summary> /// Reads geometry information from .node or .poly files. /// </summary> public static void Read(string filename, out InputGeometry geometry) { geometry = null; //string path = Path.ChangeExtension(filename, ".poly"); //if (File.Exists(path)) //{ // geometry = FileReader.ReadPolyFile(path); //} //else //{ // path = Path.ChangeExtension(filename, ".node"); // geometry = FileReader.ReadNodeFile(path); //} }
/// <summary> /// Reads geometry information from .node or .poly files. /// </summary> public static void Read(string filename, out InputGeometry geometry) { geometry = null; string path = Path.ChangeExtension(filename, ".poly"); if (File.Exists(path)) { geometry = FileReader.ReadPolyFile(path); } else { path = Path.ChangeExtension(filename, ".node"); geometry = FileReader.ReadNodeFile(path); } }
private static InputGeometry GetGeometryFor(IEnumerable <Vector2> circuit) { var result = new TriangleNet.Geometry.InputGeometry(circuit.Count()); foreach (var v in circuit) { result.AddPoint(v.x, v.y); } for (int i = 0; i < result.Count - 1; i++) { result.AddSegment(i, i + 1, 1); } result.AddSegment(result.Count - 1, 0, 1); return(result); }
/// <summary> /// Copy input geometry data. /// </summary> public void SetInputGeometry(InputGeometry data) { // Clear unused buffers this.Segments = null; this.Triangles = null; this.MeshEdges = null; this.VoronoiPoints = null; this.VoronoiEdges = null; int n = data.Count; int i = 0; this.NumberOfRegions = data.Regions.Count; this.NumberOfInputPoints = n; // Copy points this.Points = new float[2 * n]; foreach (var pt in data.Points) { this.Points[2 * i] = (float)pt.X; this.Points[2 * i + 1] = (float)pt.Y; i++; } // Copy segments n = data.Segments.Count; if (n > 0) { var segments = new List<uint>(2 * n); foreach (var seg in data.Segments) { segments.Add((uint)seg.P0); segments.Add((uint)seg.P1); } this.Segments = segments.ToArray(); } this.Bounds = new BoundingBox( (float)data.Bounds.Xmin, (float)data.Bounds.Xmax, (float)data.Bounds.Ymin, (float)data.Bounds.Ymax); }
public override InputGeometry Generate(double param0, double param1, double param2) { int n = GetParamValueInt(0, param0); int m = n / 2; InputGeometry input = new InputGeometry(n + 1); double ro, r = 10; double step = 2 * Math.PI / m; // Inner ring for (int i = 0; i < m; i++) { input.AddPoint(r * Math.Cos(i * step), r * Math.Sin(i * step)); input.AddSegment(i, (i + 1) % m); } r = 1.5 * r; step = 2 * Math.PI / n; double offset = step / 2; // Outer ring for (int i = 0; i < n; i++) { ro = r; if (i % 2 == 0) { ro = r + r * Util.Random.NextDouble() * (param1 / 100); } input.AddPoint(ro * Math.Cos(i * step + offset), ro * Math.Sin(i * step + offset)); input.AddSegment(m + i, m + ((i + 1) % n)); } input.AddHole(0, 0); return input; }
public override InputGeometry Generate(double param0, double param1, double param2) { int numPoints = GetParamValueInt(0, param0); numPoints = (numPoints / 10) * 10; if (numPoints < 5) { numPoints = 5; } double exp = (param1 + 10) / 100; InputGeometry input = new InputGeometry(numPoints); int i = 0, cNum = 2 * (int)Math.Floor(Math.Sqrt(numPoints)); double r, phi, radius = 100, step = 2 * Math.PI / cNum; // Distrubute points equally on circle border for (; i < cNum; i++) { // Add a little error r = Util.Random.NextDouble(); input.AddPoint((radius + r) * Math.Cos(i * step), (radius + r) * Math.Sin(i * step)); } for (; i < numPoints; i++) { // Use sqrt(rand) to get normal distribution right. r = Math.Pow(Util.Random.NextDouble(), exp) * radius; phi = Util.Random.NextDouble() * Math.PI * 2; input.AddPoint(r * Math.Cos(phi), r * Math.Sin(phi)); } return input; }
public override InputGeometry Generate(double param0, double param1, double param2) { int numPoints = GetParamValueInt(0, param0); numPoints = (numPoints / 10) * 10; if (numPoints < 5) { numPoints = 5; } InputGeometry input = new InputGeometry(numPoints); int width = GetParamValueInt(1, param1); int height = GetParamValueInt(2, param2); for (int i = 0; i < numPoints; i++) { input.AddPoint(Util.Random.NextDouble() * width, Util.Random.NextDouble() * height); } return input; }
/// <summary> /// Read vertex information of the given line. /// </summary> /// <param name="data">The input geometry.</param> /// <param name="index">The current vertex index.</param> /// <param name="line">The current line.</param> /// <param name="attributes">Number of point attributes</param> /// <param name="marks">Number of point markers (0 or 1)</param> static void ReadVertex(InputGeometry data, int index, string[] line, int attributes, int marks) { float x = float.Parse(line[1], nfi); float y = float.Parse(line[2], nfi); int mark = 0; float[] attribs = attributes == 0 ? null : new float[attributes]; // Read the vertex attributes. for (int j = 0; j < attributes; j++) { if (line.Length > 3 + j) { attribs[j] = float.Parse(line[3 + j]); } } // Read a vertex marker. if (marks > 0 && line.Length > 3 + attributes) { mark = int.Parse(line[3 + attributes]); } data.AddPoint(x, y, mark, attribs); }
/// <summary> /// Read the vertices from memory. /// </summary> /// <param name="data">The input data.</param> private void TransferNodes(InputGeometry data) { List<Vertex> points = data.points; this.invertices = points.Count; this.mesh_dim = 2; if (this.invertices < 3) { logger.Error("Input must have at least three input vertices.", "MeshReader.TransferNodes()"); throw new Exception("Input must have at least three input vertices."); } this.nextras = points[0].attributes == null ? 0 : points[0].attributes.Length; foreach (Vertex vertex in points) { vertex.hash = this.hash_vtx++; vertex.id = vertex.hash; this.vertices.Add(vertex.hash, vertex); } this.bounds = data.Bounds; }
/// <summary> /// Reconstructs a mesh from raw input data. /// </summary> public void Load(InputGeometry input, List<ITriangle> triangles) { if (input == null || triangles == null) { throw new ArgumentException("Invalid input (argument is null)."); } // Clear all data structures / reset hash seeds this.ResetData(); if (input.HasSegments) { behavior.Poly = true; this.holes.AddRange(input.Holes); } //if (input.EdgeMarkers != null) //{ // behavior.UseBoundaryMarkers = true; //} //if (input.TriangleAreas != null) //{ // behavior.VarArea = true; //} // TODO: remove if (!behavior.Poly) { // Be careful not to allocate space for element area constraints that // will never be assigned any value (other than the default -1.0). behavior.VarArea = false; // Be careful not to add an extra attribute to each element unless the // input supports it (PSLG in, but not refining a preexisting mesh). behavior.useRegions = false; } behavior.useRegions = input.Regions.Count > 0; TransferNodes(input); // Read and reconstruct a mesh. hullsize = DataReader.Reconstruct(this, input, triangles.ToArray()); // Calculate the number of edges. edges = (3 * triangles.Count + hullsize) / 2; }
/// <summary> /// Create the segments of a triangulation, including PSLG segments and edges /// on the convex hull. /// </summary> /// <param name="segmentlist"></param> /// <param name="segmentmarkerlist"></param> /// <param name="numberofsegments"></param> private void FormSkeleton(InputGeometry input) { Vertex endpoint1, endpoint2; int end1, end2; int boundmarker; this.insegments = 0; if (behavior.Poly) { // If the input vertices are collinear, there is no triangulation, // so don't try to insert segments. if (triangles.Count == 0) { return; } // If segments are to be inserted, compute a mapping // from vertices to triangles. if (input.HasSegments) { MakeVertexMap(); } boundmarker = 0; // Read and insert the segments. foreach (var seg in input.segments) { this.insegments++; end1 = seg.P0; end2 = seg.P1; boundmarker = seg.Boundary; if ((end1 < 0) || (end1 >= invertices)) { if (Behavior.Verbose) { logger.Warning("Invalid first endpoint of segment.", "Mesh.FormSkeleton().1"); } } else if ((end2 < 0) || (end2 >= invertices)) { if (Behavior.Verbose) { logger.Warning("Invalid second endpoint of segment.", "Mesh.FormSkeleton().2"); } } else { // TODO: Is using the vertex ID reliable??? // It should be. The ID gets appropriately set in TransferNodes(). // Find the vertices numbered 'end1' and 'end2'. endpoint1 = vertices[end1]; endpoint2 = vertices[end2]; if ((endpoint1.x == endpoint2.x) && (endpoint1.y == endpoint2.y)) { if (Behavior.Verbose) { logger.Warning("Endpoints of segments are coincident.", "Mesh.FormSkeleton()"); } } else { InsertSegment(endpoint1, endpoint2, boundmarker); } } } } if (behavior.Convex || !behavior.Poly) { // Enclose the convex hull with subsegments. MarkHull(); } }
private void RecalculateVertices() { if (points.Count < 2) { return; } vertexPositionColorArray = null; var lineColor = Color.Red; #region clipper List<IntPoint> clipperPath = new List<IntPoint>(points.Count); foreach (var point in points) { clipperPath.Add(new IntPoint(point.X * ClipperScale, point.Y * ClipperScale)); } List<List<IntPoint>> clipperSolution = new List<List<IntPoint>>(); ClipperOffset clipperOffset = new ClipperOffset(); clipperOffset.AddPath(clipperPath, JoinType.jtRound, EndType.etOpenRound); clipperOffset.Execute(ref clipperSolution, lineThickness / 2.0f * ClipperScale); #endregion #region triangle.net InputGeometry InputGeometry = new InputGeometry(); Mesh TriangleMesh = new Mesh(); for (int iii = 0; iii < clipperSolution.Count; iii++) { var trianglePath = clipperSolution[iii].Select(p => new TrianglePoint(p.X / (float)ClipperScale, p.Y / (float)ClipperScale)).ToList(); if (iii == 0) { InputGeometry.AddRing(trianglePath); } else { InputGeometry.AddRingAsHole(trianglePath); } } #endregion if (InputGeometry.Count > 0) { TriangleMesh.Triangulate(InputGeometry); vertexPositionColorArray = TriangleMesh.GetTriangleList().Select(v => new VertexPositionColor(new Vector3((float)v.X, (float)v.Y, 0.0f), lineColor)).ToArray(); vertexBuffer = new VertexBuffer(GraphicsDevice, VertexPositionColor.VertexDeclaration, vertexPositionColorArray.Length, BufferUsage.WriteOnly); vertexBuffer.SetData<VertexPositionColor>(vertexPositionColorArray); } }
public void SubdivideMesh(int divisions) { if (spriteRenderer != null && points.Length > 2) { // Unparent the skin temporarily before adding the mesh Transform polygonParent = spriteRenderer.transform.parent; spriteRenderer.transform.parent = null; // Reset the rotation before creating the mesh so the UV's will align properly Quaternion localRotation = spriteRenderer.transform.localRotation; spriteRenderer.transform.localRotation = Quaternion.identity; // Reset the scale before creating the mesh so the UV's will align properly Vector3 localScale = spriteRenderer.transform.localScale; spriteRenderer.transform.localScale = Vector3.one; //Create triangle.NET geometry TriangleNet.Geometry.InputGeometry geometry = new TriangleNet.Geometry.InputGeometry(points.Length); //Add vertices foreach (Vector2 point in points) { geometry.AddPoint(point.x, point.y); } int N = geometry.Count; int end = 0; //Add vertices foreach (Vector2 point in points) { geometry.AddPoint(point.x, point.y); end++; } for (int i = 0; i < end; i++) { geometry.AddSegment(N + i, N + ((i + 1) % end)); } //Triangulate and subdivide the mesh TriangleNet.Mesh triangleMesh = new TriangleNet.Mesh(); if (divisions > 0) { triangleMesh.behavior.MinAngle = 10; } triangleMesh.Triangulate(geometry); if (divisions > 0) { if (divisions > 1) { triangleMesh.Refine(true); } TriangleNet.Tools.Statistic stat = new TriangleNet.Tools.Statistic(); stat.Update(triangleMesh, 1); // Refine by area if (divisions > 2) { triangleMesh.Refine(stat.LargestArea / 8); } try { triangleMesh.Smooth(); } catch { //Debug.Log("Cannot subdivide"); } triangleMesh.Renumber(); } //transform vertices points = new Vector2[triangleMesh.Vertices.Count]; Vector3[] vertices = new Vector3[triangleMesh.Vertices.Count]; Vector2[] uvs = new Vector2[triangleMesh.Vertices.Count]; Vector3[] normals = new Vector3[triangleMesh.Vertices.Count]; int n = 0; foreach (TriangleNet.Data.Vertex v in triangleMesh.Vertices) { points[n] = new Vector2((float)v.X, (float)v.Y); vertices[n] = new Vector3((float)v.X, (float)v.Y, 0); normals[n] = new Vector3(0, 0, -1); n++; } //transform triangles int[] triangles = new int[triangleMesh.Triangles.Count * 3]; n = 0; foreach (TriangleNet.Data.Triangle t in triangleMesh.Triangles) { triangles[n++] = t.P1; triangles[n++] = t.P0; triangles[n++] = t.P2; } mesh.Clear(); mesh = new Mesh(); mesh.vertices = vertices; mesh.triangles = triangles; mesh.uv = genUV(mesh.vertices); mesh.normals = normals; mesh.RecalculateNormals(); mesh.RecalculateBounds(); // Reset the rotations of the object spriteRenderer.transform.localRotation = localRotation; spriteRenderer.transform.localScale = localScale; spriteRenderer.transform.parent = polygonParent; meshCreated = true; } }
/// <summary> /// Get a list of triangles which will fill the area described by the slice /// </summary> public IEnumerable<Triangle> Triangles() { TriangleNet.Behavior behavior = new TriangleNet.Behavior(); behavior.ConformingDelaunay = true; foreach (var poly in IndividualPolygons()) { PolyNode node = polyTree.GetFirst(); InputGeometry geometry = new InputGeometry(); while (node != null) { var offset = geometry.Points.Count(); var index = 0; foreach (IntPoint point in node.Contour) { geometry.AddPoint(point.X, point.Y); if (index > 0) { geometry.AddSegment(index - 1 + offset, index + offset); } index++; } geometry.AddSegment(index - 1 + offset, offset); if (node.IsHole) { // To describe a hole, AddHole must be called with a location inside the hole. IntPoint last = new IntPoint(0, 0); bool lastKnown = false; double longest = 0; IntPoint longestAlong = new IntPoint(0, 0); IntPoint from = new IntPoint(0, 0); foreach (IntPoint point in node.Contour) { if (lastKnown) { IntPoint along = new IntPoint(point.X - last.X, point.Y - last.Y); double length = Math.Sqrt(along.X * along.X + along.Y * along.Y); if (length > longest) { longest = length; longestAlong = along; from = last; } } last = point; lastKnown = true; } if (longest > 0) { double perpendicularX = ((double)longestAlong.Y * (double)scale * 0.001d) / longest; double perpendicularY = -((double)longestAlong.X * (double)scale * 0.001d) / longest; geometry.AddHole(perpendicularX + from.X + longestAlong.X / 2.0d, perpendicularY + from.Y + longestAlong.Y / 2.0d); } else { } } node = node.GetNext(); } if (geometry.Points.Count() > 0) { var mesh = new TriangleNet.Mesh(behavior); mesh.Triangulate(geometry); mesh.Renumber(); foreach (Triangle t in this.GetMeshTriangles(mesh)) { yield return t; } } } }
public static void Tessellate(List<Vector2> vertices, List<IndexedEdge> indexedEdges, List<Hole> holes, List<int> indices, float tessellationAmount) { if(tessellationAmount <= 0f) { return; } indices.Clear(); if(vertices.Count >= 3) { InputGeometry inputGeometry = new InputGeometry(vertices.Count); for(int i = 0; i < vertices.Count; ++i) { Vector2 vertex = vertices[i]; inputGeometry.AddPoint(vertex.x,vertex.y); } for(int i = 0; i < indexedEdges.Count; ++i) { IndexedEdge edge = indexedEdges[i]; inputGeometry.AddSegment(edge.index1,edge.index2); } for(int i = 0; i < holes.Count; ++i) { Vector2 hole = holes[i].vertex; inputGeometry.AddHole(hole.x,hole.y); } TriangleNet.Mesh triangleMesh = new TriangleNet.Mesh(); TriangleNet.Tools.Statistic statistic = new TriangleNet.Tools.Statistic(); triangleMesh.Triangulate(inputGeometry); triangleMesh.Behavior.MinAngle = 20.0; triangleMesh.Behavior.SteinerPoints = -1; triangleMesh.Refine(true); statistic.Update(triangleMesh,1); triangleMesh.Refine(statistic.LargestArea / tessellationAmount); triangleMesh.Renumber(); vertices.Clear(); indexedEdges.Clear(); foreach(TriangleNet.Data.Vertex vertex in triangleMesh.Vertices) { vertices.Add(new Vector2((float)vertex.X,(float)vertex.Y)); } foreach(TriangleNet.Data.Segment segment in triangleMesh.Segments) { indexedEdges.Add(new IndexedEdge(segment.P0,segment.P1)); } foreach (TriangleNet.Data.Triangle triangle in triangleMesh.Triangles) { if(triangle.P0 >= 0 && triangle.P0 < vertices.Count && triangle.P0 >= 0 && triangle.P1 < vertices.Count && triangle.P0 >= 0 && triangle.P2 < vertices.Count) { indices.Add(triangle.P0); indices.Add(triangle.P2); indices.Add(triangle.P1); } } } }
void frmGenerator_InputGenerated(object sender, EventArgs e) { this.input = sender as InputGeometry; if (input != null) { settings.CurrentFile = "tmp-" + DateTime.Now.ToString("HH-mm-ss"); HandleNewInput(); } }
public Mesh TriangulateMesh(Vector3[] Vertices) { if (Vertices.Length < 3) { return(null); } geometry = new InputGeometry(); foreach (Vector3 Vert in Vertices) { geometry.AddPoint(Vert.x, Vert.y); } List <Point> points = new List <Point>(); for (float offsetX = -distance; offsetX < distance; offsetX += boxDistance) { for (float offsetY = -verticalDistance; offsetY < verticalDistance; offsetY += boxDistance) { Vector2 offset = new Vector2(offsetX, offsetY) + Vector2.one * boxDistance * 0.5f; float radians = Random.Range(0, 2 * Mathf.PI); float length = Random.Range(0, circleDistance); Vector2 pos = new Vector2(Mathf.Cos(radians), Mathf.Sin(radians)) * length; pos += offset; } } meshRepresentation = new TriangleNet.Mesh(); meshRepresentation.Triangulate(geometry); //generate mesh based on triangulation Dictionary <int, float> zOffsets = new Dictionary <int, float>(); foreach (KeyValuePair <int, TriangleNet.Data.Vertex> pair in meshRepresentation.vertices) { zOffsets.Add(pair.Key, Random.Range(-zOffset, zOffset)); } int triangleIndex = 0; List <Vector3> vertices = new List <Vector3>(meshRepresentation.triangles.Count * 3); List <int> triangleIndices = new List <int>(meshRepresentation.triangles.Count * 3); foreach (KeyValuePair <int, TriangleNet.Data.Triangle> pair in meshRepresentation.triangles) { TriangleNet.Data.Triangle triangle = pair.Value; TriangleNet.Data.Vertex vertex0 = triangle.GetVertex(0); TriangleNet.Data.Vertex vertex1 = triangle.GetVertex(1); TriangleNet.Data.Vertex vertex2 = triangle.GetVertex(2); Vector3 p0 = new Vector3(vertex0.x, vertex0.y, zOffsets[vertex0.id]); Vector3 p1 = new Vector3(vertex1.x, vertex1.y, zOffsets[vertex1.id]); Vector3 p2 = new Vector3(vertex2.x, vertex2.y, zOffsets[vertex2.id]); vertices.Add(p0); vertices.Add(p1); vertices.Add(p2); triangleIndices.Add(triangleIndex + 2); triangleIndices.Add(triangleIndex + 1); triangleIndices.Add(triangleIndex); triangleIndex += 3; } mesh = new Mesh(); mesh.name = "Triangulated Terrain"; mesh.vertices = vertices.ToArray(); mesh.triangles = triangleIndices.ToArray(); return(mesh); }
public static List<SampleTri> BuildMesh(Dictionary<Point, Pixel> pointIndex) { InputGeometry g = new InputGeometry(); foreach (var value in pointIndex) { g.AddPoint(value.Key.X, value.Key.Y); } Mesh m = new Mesh(); m.Triangulate(g); List<SampleTri> sampleMesh = new List<SampleTri>(); Dictionary<ITriangle, SampleTri> table = new Dictionary<ITriangle, SampleTri>(); Dictionary<Point, Sample> sampleTable = new Dictionary<Point, Sample>(); foreach (var mTri in m.Triangles) { SampleTri tri = new SampleTri(mTri); for (int i = 0; i < 3; i++) tri.TriangleNeighbours.Add(mTri.GetNeighbor(i)); sampleMesh.Add(tri); table.Add(mTri, tri); if (sampleTable.ContainsKey(tri.U.Point)) tri.U = sampleTable[tri.U.Point]; else sampleTable[tri.U.Point] = tri.U; if (sampleTable.ContainsKey(tri.V.Point)) tri.V = sampleTable[tri.V.Point]; else sampleTable[tri.V.Point] = tri.V; if (sampleTable.ContainsKey(tri.W.Point)) tri.W = sampleTable[tri.W.Point]; else sampleTable[tri.W.Point] = tri.W; } foreach (var tri in sampleMesh) { foreach (var triangleNeighbour in tri.TriangleNeighbours) { if (triangleNeighbour != null) tri.SampleTriNeighbours.Add(table[triangleNeighbour]); } tri.U.Triangles.Add(tri); tri.V.Triangles.Add(tri); tri.W.Triangles.Add(tri); tri.U.Color = pointIndex[tri.U.Point]; tri.V.Color = pointIndex[tri.V.Point]; tri.W.Color = pointIndex[tri.W.Point]; tri.CenterColor = tri.U.Color; } return sampleMesh; }
/// <summary> /// Triangulate given input data. /// </summary> /// <param name="input"></param> public void Triangulate(InputGeometry input) { ResetData(); behavior.Poly = input.HasSegments; //behavior.useSegments = input.HasSegments; //if (input.EdgeMarkers != null) //{ // behavior.UseBoundaryMarkers = true; //} // TODO: remove if (!behavior.Poly) { // Be careful not to allocate space for element area constraints that // will never be assigned any value (other than the default -1.0). behavior.VarArea = false; // Be careful not to add an extra attribute to each element unless the // input supports it (PSLG in, but not refining a preexisting mesh). behavior.useRegions = false; } behavior.useRegions = input.Regions.Count > 0; steinerleft = behavior.SteinerPoints; TransferNodes(input); hullsize = Delaunay(); // Triangulate the vertices. // Ensure that no vertex can be mistaken for a triangular bounding // box vertex in insertvertex(). infvertex1 = null; infvertex2 = null; infvertex3 = null; if (behavior.useSegments) { // Segments will be introduced next. checksegments = true; // Insert PSLG segments and/or convex hull segments. FormSkeleton(input); } if (behavior.Poly && (triangles.Count > 0)) { // Copy holes foreach (var item in input.holes) { holes.Add(item); } // Copy regions foreach (var item in input.regions) { regions.Add(item); } //dummytri.neighbors[2].triangle = dummytri; // Carve out holes and concavities. Carver c = new Carver(this); c.CarveHoles(); } else { // Without a PSLG, there can be no holes or regional attributes // or area constraints. The following are set to zero to avoid // an accidental free() later. // // TODO: - holes.Clear(); regions.Clear(); } if (behavior.Quality && (triangles.Count > 0)) { quality.EnforceQuality(); // Enforce angle and area constraints. } // Calculate the number of edges. edges = (3 * triangles.Count + hullsize) / 2; }
private void WriteGeometry(InputGeometry geometry) { stream.WriteLine("#!G{0}", this.iteration++); }
public void SubdivideMesh(int divisions) { if (spriteRenderer != null && points.Length > 2) { // Unparent the skin temporarily before adding the mesh Transform polygonParent = spriteRenderer.transform.parent; spriteRenderer.transform.parent = null; // Reset the rotation before creating the mesh so the UV's will align properly Quaternion localRotation = spriteRenderer.transform.localRotation; spriteRenderer.transform.localRotation = Quaternion.identity; // Reset the scale before creating the mesh so the UV's will align properly Vector3 localScale = spriteRenderer.transform.localScale; spriteRenderer.transform.localScale = Vector3.one; //Create triangle.NET geometry TriangleNet.Geometry.InputGeometry geometry = new TriangleNet.Geometry.InputGeometry(points.Length); //Add vertices foreach (Vector2 point in points) { geometry.AddPoint(point.x,point.y); } int N = geometry.Count; int end = 0; //Add vertices foreach (Vector2 point in points) { geometry.AddPoint(point.x,point.y); end++; } for (int i = 0; i < end; i++) { geometry.AddSegment(N + i, N + ((i + 1) % end)); } //Triangulate and subdivide the mesh TriangleNet.Mesh triangleMesh = new TriangleNet.Mesh(); if (divisions > 0) { triangleMesh.behavior.MinAngle = 10; } triangleMesh.Triangulate(geometry); if (divisions > 0) { if (divisions > 1) triangleMesh.Refine(true); TriangleNet.Tools.Statistic stat = new TriangleNet.Tools.Statistic(); stat.Update(triangleMesh, 1); // Refine by area if (divisions > 2) triangleMesh.Refine (stat.LargestArea / 8); try { triangleMesh.Smooth(); } catch { //Debug.Log("Cannot subdivide"); } triangleMesh.Renumber(); } //transform vertices points = new Vector2[triangleMesh.Vertices.Count]; Vector3[] vertices = new Vector3[triangleMesh.Vertices.Count]; Vector3[] normals = new Vector3[triangleMesh.Vertices.Count]; int n = 0; foreach(TriangleNet.Data.Vertex v in triangleMesh.Vertices) { points[n] = new Vector2((float)v.X, (float)v.Y); vertices[n] = new Vector3((float)v.X, (float)v.Y, 0); normals[n] = new Vector3(0, 0, -1); n++; } //transform triangles int[] triangles = new int[triangleMesh.Triangles.Count*3]; n = 0; foreach (TriangleNet.Data.Triangle t in triangleMesh.Triangles) { triangles[n++] = t.P1; triangles[n++] = t.P0; triangles[n++] = t.P2; } mesh.Clear(); mesh = new Mesh(); mesh.vertices = vertices; mesh.triangles = triangles; mesh.uv = genUV(mesh.vertices); mesh.normals = normals; mesh.RecalculateNormals(); mesh.RecalculateBounds(); // Reset the rotations of the object spriteRenderer.transform.localRotation = localRotation; spriteRenderer.transform.localScale = localScale; spriteRenderer.transform.parent = polygonParent; meshCreated = true; } }
public void CreateSubdividedMesh(Vector2[] vertsToCopy, Transform transform, int smoothLevel) { Sprite spr = transform.GetComponent <SpriteRenderer>().sprite; Rect rec = spr.rect; Vector3 bound = transform.renderer.bounds.max - transform.renderer.bounds.min; TextureImporter textureImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(spr)) as TextureImporter; //Create triangle.NET geometry TriangleNet.Geometry.InputGeometry geometry = new TriangleNet.Geometry.InputGeometry(vertsToCopy.Length); //Add vertices foreach (Vector2 p in vertsToCopy) { geometry.AddPoint(p.x, p.y); } //Add segments for (int i = 0; i < vertsToCopy.Length - 1; i++) { geometry.AddSegment(i, i + 1); } geometry.AddSegment(vertsToCopy.Length - 1, 0); //Triangulate, refine and smooth TriangleNet.Mesh triangleNetMesh = new TriangleNet.Mesh(); triangleNetMesh.behavior.MinAngle = 10; triangleNetMesh.Triangulate(geometry); if (smoothLevel > 1) { triangleNetMesh.Refine(true); } TriangleNet.Tools.Statistic statistic = new TriangleNet.Tools.Statistic(); statistic.Update(triangleNetMesh, 1); // Refine by setting a custom maximum area constraint. if (smoothLevel > 2) { triangleNetMesh.Refine(statistic.LargestArea / 8); } try { triangleNetMesh.Smooth(); } catch { //Debug.LogWarning("unable to smooth"); } triangleNetMesh.Renumber(); //transform vertices Vector3[] vertices = new Vector3[triangleNetMesh.Vertices.Count]; Vector2[] uvs = new Vector2[triangleNetMesh.Vertices.Count]; Vector3[] normals = new Vector3[triangleNetMesh.Vertices.Count]; int idx = 0; foreach (TriangleNet.Data.Vertex v in triangleNetMesh.Vertices) { vertices[idx] = new Vector3((float)v.X, (float)v.Y, 0); normals[idx] = new Vector3(0, 0, -1); Vector2 newUv = new Vector2(((float)v.X / bound.x) + 0.5f, ((float)v.Y / bound.y) + 0.5f); newUv.x *= rec.width / spr.texture.width; newUv.y *= rec.height / spr.texture.height; //Debug.Log(spr.textureRectOffset); newUv.x += (rec.x) / spr.texture.width; newUv.y += (rec.y) / spr.texture.height; SpriteMetaData[] smdArray = textureImporter.spritesheet; Vector2 pivot = new Vector2(.0f, .0f);; for (int i = 0; i < smdArray.Length; i++) { if (smdArray[i].name == spr.name) { switch (smdArray[i].alignment) { case (0): smdArray[i].pivot = Vector2.zero; break; case (1): smdArray[i].pivot = new Vector2(0f, 1f) - new Vector2(.5f, .5f); break; case (2): smdArray[i].pivot = new Vector2(0.5f, 1f) - new Vector2(.5f, .5f); break; case (3): smdArray[i].pivot = new Vector2(1f, 1f) - new Vector2(.5f, .5f); break; case (4): smdArray[i].pivot = new Vector2(0f, .5f) - new Vector2(.5f, .5f); break; case (5): smdArray[i].pivot = new Vector2(1f, .5f) - new Vector2(.5f, .5f); break; case (6): smdArray[i].pivot = new Vector2(0f, 0f) - new Vector2(.5f, .5f); break; case (7): smdArray[i].pivot = new Vector2(0.5f, 0f) - new Vector2(.5f, .5f); break; case (8): smdArray[i].pivot = new Vector2(1f, 0f) - new Vector2(.5f, .5f); break; case (9): smdArray[i].pivot -= new Vector2(.5f, .5f); break; } pivot = smdArray[i].pivot; } } if (textureImporter.spriteImportMode == SpriteImportMode.Single) { pivot = textureImporter.spritePivot - new Vector2(.5f, .5f); } newUv.x += ((pivot.x) * rec.width) / spr.texture.width; newUv.y += ((pivot.y) * rec.height) / spr.texture.height; uvs[idx] = newUv; idx++; } //transform triangles int[] triangles = new int[triangleNetMesh.Triangles.Count * 3]; idx = 0; foreach (TriangleNet.Data.Triangle t in triangleNetMesh.Triangles) { triangles[idx++] = t.P1; triangles[idx++] = t.P0; triangles[idx++] = t.P2; } finalVertices = vertices; finalTriangles = triangles; finalUvs = uvs; finalNormals = normals; }
private void CreateMesh() { Sprite sprite = spriteRenderer.sprite; Rect bounds = GetBounds(polygon); TriangleNet.Mesh tnMesh = new TriangleNet.Mesh(); TriangleNet.Geometry.InputGeometry input = new TriangleNet.Geometry.InputGeometry(); input.AddPolygon(polygon); tnMesh.Triangulate(input); Mesh mesh = new Mesh(); mesh.vertices = tnMesh.Vertices.Select(p => new Vector3((float)p.X, (float)p.Y, 0)).ToArray(); // Not sure about winding // If there is an interesting error, It is probably because of cw/ccw windings int[] tris = tnMesh.Triangles.ToUnityMeshTriangleIndices(); mesh.triangles = tris; List<Vector2> uv = new List<Vector2>(); Vector3 lower = new Vector3(bounds.x, bounds.y); Vector3 size = new Vector3(bounds.xMax, bounds.yMax) - lower; Rect uv_bounds = new Rect(sprite.rect.x / sprite.texture.width, sprite.rect.y / sprite.texture.height, sprite.rect.width / sprite.texture.width, sprite.rect.height / sprite.texture.height); float scalex = sprite.bounds.size.x / bounds.width; float scaley = sprite.bounds.size.y / bounds.height; Vector3[] scaled = mesh.vertices; for (int i = 0; i < mesh.vertices.Length; i++) { Vector3 v = scaled[i]; Vector3 rel = v - lower; uv.Add(new Vector2(rel.x / size.x * uv_bounds.width, rel.y / size.y * uv_bounds.height) + new Vector2(uv_bounds.x, uv_bounds.y)); scaled[i] = new Vector3(v.x * scalex, v.y * scaley, v.z) - ((Vector3)bounds.center * scalex) + sprite.bounds.center; } mesh.MarkDynamic(); mesh.vertices = scaled; mesh.uv = uv.ToArray(); mesh.RecalculateNormals(); mesh.RecalculateBounds(); //GameObject go = new GameObject(); //MeshFilter mf = go.AddComponent<MeshFilter>(); //mf.sharedMesh = mesh; //MeshRenderer mr = go.AddComponent<MeshRenderer>(); //mr.sharedMaterial = spriteRenderer.sharedMaterial; // Check if the Meshes directory exists, if not, create it. DirectoryInfo meshDir = new DirectoryInfo("Assets/Meshes"); if (Directory.Exists(meshDir.FullName) == false) { Directory.CreateDirectory(meshDir.FullName); } ScriptableObjectUtility.CreateAsset(mesh, "Meshes/" + spriteRenderer.gameObject.name + ".Mesh"); }
public Mesh CreateMeshFromVerts(Vector3[] vertsToCopy, Mesh mesh, List <int> pathSplitIds, Transform SpriteGO = null) { Sprite spr = new Sprite(); Rect rec = new Rect(); Vector3 bound = Vector3.zero; TextureImporter textureImporter = new TextureImporter(); if (SpriteGO != null && SpriteGO.GetComponent <SpriteRenderer>() && SpriteGO.GetComponent <SpriteRenderer>().sprite) { spr = SpriteGO.GetComponent <SpriteRenderer>().sprite; rec = spr.rect; bound = SpriteGO.GetComponent <Renderer>().bounds.max - SpriteGO.GetComponent <Renderer>().bounds.min; textureImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(spr)) as TextureImporter; } //Create triangle.NET geometry TriangleNet.Geometry.InputGeometry geometry = new TriangleNet.Geometry.InputGeometry(vertsToCopy.Length); //Add vertices foreach (Vector3 p in vertsToCopy) { geometry.AddPoint(p.x, p.y); } //Add segments int prevEnd = 0; for (int i = 0; i < vertsToCopy.Length - 1; i++) { if (!pathSplitIds.Contains(i + 1)) { geometry.AddSegment(i, i + 1); //Debug.Log ("joining " + i + " to " + (i + 1)); } else { geometry.AddSegment(i, prevEnd); prevEnd = i + 1; } } if (pathSplitIds.Count <= 1) { //Debug.Log ("joining " + (vertsToCopy.Length - 1) + " to 0"); geometry.AddSegment(vertsToCopy.Length - 1, 0); } //Triangulate, refine and smooth TriangleNet.Mesh triangleNetMesh = new TriangleNet.Mesh(); triangleNetMesh.Triangulate(geometry); //transform vertices Vector3[] vertices = new Vector3[triangleNetMesh.Vertices.Count]; Vector2[] uvs = new Vector2[triangleNetMesh.Vertices.Count]; Vector3[] normals = new Vector3[triangleNetMesh.Vertices.Count]; int idx = 0; foreach (TriangleNet.Data.Vertex v in triangleNetMesh.Vertices) { vertices[idx] = new Vector3((float)v.X, (float)v.Y, 0); normals[idx] = new Vector3(0, 0, -1); if (SpriteGO != null && SpriteGO.GetComponent <SpriteRenderer>()) { Vector2 newUv = new Vector2(((float)v.X / bound.x) + 0.5f, ((float)v.Y / bound.y) + 0.5f); newUv.x *= rec.width / spr.texture.width; newUv.y *= rec.height / spr.texture.height; //Debug.Log(spr.textureRectOffset); newUv.x += (rec.x) / spr.texture.width; newUv.y += (rec.y) / spr.texture.height; SpriteMetaData[] smdArray = textureImporter.spritesheet; Vector2 pivot = new Vector2(.0f, .0f); ; for (int i = 0; i < smdArray.Length; i++) { if (smdArray [i].name == spr.name) { switch (smdArray [i].alignment) { case (0): smdArray [i].pivot = Vector2.zero; break; case (1): smdArray [i].pivot = new Vector2(0f, 1f) - new Vector2(.5f, .5f); break; case (2): smdArray [i].pivot = new Vector2(0.5f, 1f) - new Vector2(.5f, .5f); break; case (3): smdArray [i].pivot = new Vector2(1f, 1f) - new Vector2(.5f, .5f); break; case (4): smdArray [i].pivot = new Vector2(0f, .5f) - new Vector2(.5f, .5f); break; case (5): smdArray [i].pivot = new Vector2(1f, .5f) - new Vector2(.5f, .5f); break; case (6): smdArray [i].pivot = new Vector2(0f, 0f) - new Vector2(.5f, .5f); break; case (7): smdArray [i].pivot = new Vector2(0.5f, 0f) - new Vector2(.5f, .5f); break; case (8): smdArray [i].pivot = new Vector2(1f, 0f) - new Vector2(.5f, .5f); break; case (9): smdArray [i].pivot -= new Vector2(.5f, .5f); break; } pivot = smdArray [i].pivot; } } if (textureImporter.spriteImportMode == SpriteImportMode.Single) { pivot = textureImporter.spritePivot - new Vector2(.5f, .5f); } newUv.x += ((pivot.x) * rec.width) / spr.texture.width; newUv.y += ((pivot.y) * rec.height) / spr.texture.height; uvs [idx] = newUv; } idx++; } //transform triangles int[] triangles = new int[triangleNetMesh.Triangles.Count * 3]; idx = 0; foreach (TriangleNet.Data.Triangle t in triangleNetMesh.Triangles) { triangles[idx++] = t.P1; triangles[idx++] = t.P0; triangles[idx++] = t.P2; } mesh.vertices = vertices; mesh.triangles = triangles; mesh.uv = uvs; mesh.normals = normals; return(mesh); }
private void CreateMesh() { Sprite sprite = spriteRenderer.sprite; Rect bounds = GetBounds(polygon); TriangleNet.Mesh tnMesh = new TriangleNet.Mesh(); TriangleNet.Geometry.InputGeometry input = new TriangleNet.Geometry.InputGeometry(); input.AddPolygon(polygon); tnMesh.Triangulate(input); Mesh mesh = new Mesh(); mesh.vertices = tnMesh.Vertices.Select(p => new Vector3((float)p.X, (float)p.Y, 0)).ToArray(); // Not sure about winding // If there is an interesting error, It is probably because of cw/ccw windings int[] tris = tnMesh.Triangles.ToUnityMeshTriangleIndices(); mesh.triangles = tris; List <Vector2> uv = new List <Vector2>(); Vector3 lower = new Vector3(bounds.x, bounds.y); Vector3 size = new Vector3(bounds.xMax, bounds.yMax) - lower; Rect uv_bounds = new Rect(sprite.rect.x / sprite.texture.width, sprite.rect.y / sprite.texture.height, sprite.rect.width / sprite.texture.width, sprite.rect.height / sprite.texture.height); float scalex = sprite.bounds.size.x / bounds.width; float scaley = sprite.bounds.size.y / bounds.height; Vector3[] scaled = mesh.vertices; for (int i = 0; i < mesh.vertices.Length; i++) { Vector3 v = scaled[i]; Vector3 rel = v - lower; uv.Add(new Vector2(rel.x / size.x * uv_bounds.width, rel.y / size.y * uv_bounds.height) + new Vector2(uv_bounds.x, uv_bounds.y)); scaled[i] = new Vector3(v.x * scalex, v.y * scaley, v.z) - ((Vector3)bounds.center * scalex) + sprite.bounds.center; } mesh.MarkDynamic(); mesh.vertices = scaled; mesh.uv = uv.ToArray(); mesh.RecalculateNormals(); mesh.RecalculateBounds(); mesh.Optimize(); //GameObject go = new GameObject(); //MeshFilter mf = go.AddComponent<MeshFilter>(); //mf.sharedMesh = mesh; //MeshRenderer mr = go.AddComponent<MeshRenderer>(); //mr.sharedMaterial = spriteRenderer.sharedMaterial; // Check if the Meshes directory exists, if not, create it. DirectoryInfo meshDir = new DirectoryInfo("Assets/Meshes"); if (Directory.Exists(meshDir.FullName) == false) { Directory.CreateDirectory(meshDir.FullName); } ScriptableObjectUtility.CreateAsset(mesh, "Meshes/" + spriteRenderer.gameObject.name + ".Mesh"); }
private bool Open(string filename) { if (FileProcessor.ContainsMeshData(filename)) { if (DarkMessageBox.Show("Import mesh", Settings.ImportString, "Do you want to import the mesh?", MessageBoxButtons.YesNo) == DialogResult.OK) { input = null; mesh = FileProcessor.Import(filename); if (mesh != null) { statisticView.UpdateStatistic(mesh); // Update settings settings.CurrentFile = Path.GetFileName(filename); HandleMeshImport(); btnSmooth.Enabled = true; // TODO: Remove } // else Message return true; } } input = FileProcessor.Read(filename); if (input != null) { // Update settings settings.CurrentFile = Path.GetFileName(filename); HandleNewInput(); } // else Message return true; }
public static void Triangulate(List<Vector2> vertices, List<IndexedEdge> edges, List<Hole> holes,ref List<int> indices) { indices.Clear(); if(vertices.Count >= 3) { InputGeometry inputGeometry = new InputGeometry(vertices.Count); for(int i = 0; i < vertices.Count; ++i) { Vector2 position = vertices[i]; inputGeometry.AddPoint(position.x,position.y); } for(int i = 0; i < edges.Count; ++i) { IndexedEdge edge = edges[i]; inputGeometry.AddSegment(edge.index1,edge.index2); } for(int i = 0; i < holes.Count; ++i) { Vector2 hole = holes[i].vertex; inputGeometry.AddHole(hole.x,hole.y); } TriangleNet.Mesh trangleMesh = new TriangleNet.Mesh(); trangleMesh.Triangulate(inputGeometry); foreach (TriangleNet.Data.Triangle triangle in trangleMesh.Triangles) { if(triangle.P0 >= 0 && triangle.P0 < vertices.Count && triangle.P0 >= 0 && triangle.P1 < vertices.Count && triangle.P0 >= 0 && triangle.P2 < vertices.Count) { indices.Add(triangle.P0); indices.Add(triangle.P2); indices.Add(triangle.P1); } } } }