// From https://github.com/speps/LibTessDotNet/issues/1 public void Tesselate_WithNoEmptyPolygonsTrue_RemovesEmptyPolygons() { string data = "2,0,4\n2,0,2\n4,0,2\n4,0,0\n0,0,0\n0,0,4"; var indices = new List <int>(); var expectedIndices = new int[] { 0, 1, 2, 2, 3, 4, 3, 1, 5 }; using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data))) { var pset = DataLoader.LoadDat(stream); var tess = new Tess(); PolyConvert.ToTess(pset, tess); tess.NoEmptyPolygons = true; tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); indices.Clear(); for (int i = 0; i < tess.ElementCount; i++) { for (int j = 0; j < 3; j++) { int index = tess.Elements[i * 3 + j]; indices.Add(index); } } Assert.AreEqual(expectedIndices, indices.ToArray()); } }
private static void AddToMesh(this Csg.Polygon p, ref Mesh mesh) { // Polygons coming back from Csg can have an arbitrary number // of vertices. We need to retessellate the returned polygon. var tess = new Tess(); tess.NoEmptyPolygons = true; tess.AddContour(p.Vertices.ToContourVertices()); tess.Tessellate(WindingRule.Positive, LibTessDotNet.Double.ElementType.Polygons, 3); for (var i = 0; i < tess.ElementCount; i++) { var a = tess.Vertices[tess.Elements[i * 3]].Position.ToVector3(); var b = tess.Vertices[tess.Elements[i * 3 + 1]].Position.ToVector3(); var c = tess.Vertices[tess.Elements[i * 3 + 2]].Position.ToVector3(); var uva = (Csg.Vector2D)tess.Vertices[tess.Elements[i * 3]].Data; var uvb = (Csg.Vector2D)tess.Vertices[tess.Elements[i * 3 + 1]].Data; var uvc = (Csg.Vector2D)tess.Vertices[tess.Elements[i * 3 + 2]].Data; var v1 = mesh.AddVertex(a, uva.ToUV()); var v2 = mesh.AddVertex(b, uvb.ToUV()); var v3 = mesh.AddVertex(c, uvc.ToUV()); mesh.AddTriangle(v1, v2, v3); } }
public void Tesselate_WithSingleTriangle_ProducesSameTriangle() { string data = "0,0,0\n0,1,0\n1,1,0"; var indices = new List <int>(); var expectedIndices = new int[] { 0, 1, 2 }; using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data))) { var pset = DataLoader.LoadDat(stream); var tess = new Tess(); PolyConvert.ToTess(pset, tess); tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); indices.Clear(); for (int i = 0; i < tess.ElementCount; i++) { for (int j = 0; j < 3; j++) { int index = tess.Elements[i * 3 + j]; indices.Add(index); } } Assert.AreEqual(expectedIndices, indices.ToArray()); } }
public static void GenerateTestData() { foreach (var name in _loader.AssetNames) { var pset = _loader.GetAsset(name).Polygons; var lines = new List <string>(); var indices = new List <int>(); foreach (WindingRule winding in Enum.GetValues(typeof(WindingRule))) { var tess = new Tess(); PolyConvert.ToTess(pset, tess); tess.Tessellate(winding, ElementType.Polygons, 3); lines.Add(string.Format("{0} {1}", winding, 3)); for (int i = 0; i < tess.ElementCount; i++) { indices.Clear(); for (int j = 0; j < 3; j++) { int index = tess.Elements[i * 3 + j]; indices.Add(index); } lines.Add(string.Join(" ", indices)); } lines.Add(""); } File.WriteAllLines(Path.Combine(TestDataPath, name + ".testdat"), lines); } }
/// <summary> /// Tessellates a polygon with libtess. /// </summary> /// <param name="contour"></param> /// <returns></returns> public static (List <Vector3> Vertices, List <Vector3> Triangles) TessellatePolygon(List <Vector3> contour) { var tess = new Tess(); var tessContour = contour.Select(v => new ContourVertex() { Position = new Vec3() { X = v.X, Y = v.Z } }).ToArray(); tess.AddContour(tessContour, ContourOrientation.CounterClockwise); tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); // convert verts to Vector3 var verts = new List <Vector3>(); foreach (var vert in tess.Vertices) { verts.Add(new Vector3( vert.Position.X, 0, vert.Position.Y)); } // convert triangles to Vector3 var tris = new List <Vector3>(); var tessTris = tess.Elements; for (int i = 0; i < tess.ElementCount * 3; i += 3) { tris.Add(new Vector3( tessTris[i], tessTris[i + 1], tessTris[i + 2])); } return(verts, tris); }
public static void Triangulate(Vector2[][] paths, float edgeSmoothing, bool nonzero, out Vector2[] vertices, out ushort[] triangles) { Tess tess = new Tess(); foreach (Vector2[] path in paths) { List <ContourVertex> contour = new List <ContourVertex>(); for (var i = 0; i < path.Length; i++) { Vector2 oldPos = path[(path.Length + i - 1) % path.Length]; Vector2 currentPos = path[i]; Vector2 nextPos = path[(i + 1) % path.Length]; //edge smoothing if (Vector2.Dot((currentPos - oldPos).normalized, (nextPos - oldPos).normalized) >= 0.99f + Mathf.Pow(edgeSmoothing, 3) * 0.01) { continue; } contour.Add(new ContourVertex(new Vec3(currentPos.x, currentPos.y, 0))); } tess.AddContour(contour, ContourOrientation.CounterClockwise); } WindingRule windingRule = nonzero ? WindingRule.NonZero : WindingRule.EvenOdd; tess.Tessellate(windingRule); vertices = (tess.Vertices ?? Array.Empty <ContourVertex>()).Select(v => new Vector2(v.Position.X, v.Position.Y)).ToArray(); triangles = (tess.Elements ?? Array.Empty <int>()).Select(t => (ushort)t).ToArray(); }
private void Reset() { tesselationAlgorithm = new Tess(); triangleMapping.Clear(); AllTriangle.Clear(); searchCache.Clear(); }
protected virtual int[] GetTriangleIndices() { if (tess == null) { tess = new Tess(); } var contour = new ContourVertex[Vertices.Count]; for (var i = 0; i < contour.Length; i++) { var vertex = Vertices[i]; contour[i].Position = new Vec3 { X = vertex.X, Y = vertex.Y }; } tess.AddContour(contour, ContourOrientation.Clockwise); tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); var indices = new int[tess.Elements.Length]; for (var i = 0; i < indices.Length; i++) { var position = tess.Vertices[tess.Elements[i]].Position; indices[i] = Vertices.IndexOf(new Vector2(position.X, position.Y)); } return(indices); }
/// <summary> /// Triangulate this solid. /// </summary> /// <param name="mesh">The mesh to which the solid's tessellated data will be added.</param> public virtual void Tessellate(ref Mesh mesh) { foreach (var f in this.Faces.Values) { var tess = new Tess(); tess.NoEmptyPolygons = true; tess.AddContour(f.Outer.ToContourVertexArray(f)); if (f.Inner != null) { foreach (var loop in f.Inner) { tess.AddContour(loop.ToContourVertexArray(f)); } } tess.Tessellate(WindingRule.Positive, LibTessDotNet.Double.ElementType.Polygons, 3); for (var i = 0; i < tess.ElementCount; i++) { var a = tess.Vertices[tess.Elements[i * 3]].Position.ToVector3(); var b = tess.Vertices[tess.Elements[i * 3 + 1]].Position.ToVector3(); var c = tess.Vertices[tess.Elements[i * 3 + 2]].Position.ToVector3(); mesh.AddTriangle(a, b, c); } } }
/// <summary> /// Gets a triangulation, where the Indices are related to the Points /// </summary> /// <param name="Indices">Indices</param> /// <param name="Points">List ofPoints</param> public void TriAngulation(List <IndexType> Indices, List <xyf> Points) { Tess Tess = new Tess(); Tess.UsePooling = true; for (int i = 0; i < Count; i++) { ContourVertex[] CV = new ContourVertex[this[i].Count]; for (int j = 0; j < this[i].Count; j++) { CV[j] = new ContourVertex(); CV[j].Position.X = (float)this[i][j].X; CV[j].Position.Y = (float)this[i][j].Y; } Tess.AddContour(CV); } Tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); Indices.Clear(); for (int i = 0; i < Tess.Elements.Length; i++) { Indices.Add((IndexType)(Tess.Elements[i])); } for (int i = 0; i < Tess.Vertices.Length; i++) { Points.Add(new xyf(Tess.Vertices[i].Position.X, Tess.Vertices[i].Position.Y)); } }
void tessPoly(PointF[] source, Color polyColor, float alpha) { // Now we need to check for polyfill, and triangulate the polygon if needed. //if (enableFilledPolys) { var tess = new Tess(); ContourVertex[] contour = new ContourVertex[source.Length]; for (int pt = 0; pt < contour.Length; pt++) { contour[pt].Position = new Vec3 { X = source[pt].X, Y = source[pt].Y, Z = 0 }; } tess.AddContour(contour, ContourOrientation.Clockwise); // keep our orientation to allow holes to be handled. // Triangulate. tess.Tessellate(WindingRule.NonZero, ElementType.Polygons, 3); // We don't have any hole polygons here. // Iterate triangles and create output geometry for (int i = 0; i < tess.ElementCount; i++) { PointF[] tempPoly = new PointF[3]; // 3 points. tempPoly[0] = new PointF((float)tess.Vertices[tess.Elements[i * 3]].Position.X, (float)tess.Vertices[tess.Elements[i * 3]].Position.Y); tempPoly[1] = new PointF((float)tess.Vertices[tess.Elements[(i * 3) + 1]].Position.X, (float)tess.Vertices[tess.Elements[(i * 3) + 1]].Position.Y); tempPoly[2] = new PointF((float)tess.Vertices[tess.Elements[(i * 3) + 2]].Position.X, (float)tess.Vertices[tess.Elements[(i * 3) + 2]].Position.Y); tessPolyList.Add(new ovp_Poly(clockwiseOrder(tempPoly).ToArray(), polyColor, alpha)); } } }
public List <Vector2[]> TriangulateClipperSolution(ClipperLib.PolyTree solution) { var tess = new Tess(); tess.NoEmptyPolygons = true; // Add a contour for each part of the solution tree ClipperLib.PolyNode node = solution.GetFirst(); while (node != null) { // Only interested in closed paths if (!node.IsOpen) { // Add a new countor. Holes are automatically generated. var vertices = node.Contour.Select(pt => new ContourVertex { Position = new Vec3 { X = pt.X, Y = pt.Y, Z = 0 } }).ToArray(); tess.AddContour(vertices); } node = node.GetNext(); } return(TrianglesFromTessellator(tess)); }
private List <Vector2[]> TrianglesFromTessellator(Tess tess) { var triangles = new List <Vector2[]>(); // Do the tessellation tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); // Extract the triangles int numTriangles = tess.ElementCount; for (int i = 0; i < numTriangles; i++) { var v0 = tess.Vertices[tess.Elements[i * 3 + 0]].Position; var v1 = tess.Vertices[tess.Elements[i * 3 + 1]].Position; var v2 = tess.Vertices[tess.Elements[i * 3 + 2]].Position; var triangle = new List <Vector2>() { new Vector2(v0.X, v0.Y), new Vector2(v1.X, v1.Y), new Vector2(v2.X, v2.Y), }; // Assume each triangle needs to be CCW float cross = GeoMath.Cross(triangle[0], triangle[1], triangle[2]); if (cross > 0) { triangle.Reverse(); } triangles.Add(triangle.ToArray()); } return(triangles); }
public static PolygonSet FromTess(Tess tess) { var output = new PolygonSet(); for (int i = 0; i < tess.ElementCount; i++) { var poly = new Polygon(); for (int j = 0; j < 3; j++) { int index = tess.Elements[i * 3 + j]; if (index == -1) { continue; } var v = new PolygonPoint { X = tess.Vertices[index].Position.X, Y = tess.Vertices[index].Position.Y }; poly.Add(v); } output.Add(poly); } return(output); }
public void Tessellate_WithAsset_ReturnsExpectedTriangulation(TestCaseData data) { var pset = _loader.GetAsset(data.AssetName).Polygons; var tess = new Tess(); PolyConvert.ToTess(pset, tess); tess.Tessellate(data.Winding, ElementType.Polygons, data.ElementSize); var resourceName = Assembly.GetExecutingAssembly().GetName().Name + ".TestData." + data.AssetName + ".testdat"; var testData = ParseTestData(data.Winding, data.ElementSize, Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)); Assert.IsNotNull(testData); Assert.AreEqual(testData.ElementSize, data.ElementSize); var indices = new List <int>(); for (int i = 0; i < tess.ElementCount; i++) { for (int j = 0; j < data.ElementSize; j++) { int index = tess.Elements[i * data.ElementSize + j]; indices.Add(index); } } Assert.AreEqual(testData.Indices, indices.ToArray()); }
/// <summary> /// Triangulate this solid and pack the triangulated data into buffers /// appropriate for use with gltf. /// </summary> public GraphicsBuffers Tessellate() { var tessellations = new Tess[this.Faces.Count]; var fi = 0; foreach (var f in this.Faces.Values) { var tess = new Tess(); tess.NoEmptyPolygons = true; tess.AddContour(f.Outer.ToContourVertexArray(f)); if (f.Inner != null) { foreach (var loop in f.Inner) { tess.AddContour(loop.ToContourVertexArray(f)); } } tess.Tessellate(WindingRule.Positive, LibTessDotNet.Double.ElementType.Polygons, 3); tessellations[fi] = tess; fi++; } var buffers = new GraphicsBuffers(); var iCursor = 0; var imax = int.MinValue; for (var i = 0; i < tessellations.Length; i++) { var tess = tessellations[i]; var a = tess.Vertices[tess.Elements[0]].Position.ToVector3(); var b = tess.Vertices[tess.Elements[1]].Position.ToVector3(); var c = tess.Vertices[tess.Elements[2]].Position.ToVector3(); var n = (b - a).Cross(c - a).Unitized(); for (var j = 0; j < tess.Vertices.Length; j++) { var v = tess.Vertices[j]; buffers.AddVertex(v.Position.ToVector3(), n, new UV()); } for (var k = 0; k < tess.Elements.Length; k++) { var t = tess.Elements[k]; var index = (ushort)(t + iCursor); buffers.AddIndex(index); imax = Math.Max(imax, index); } iCursor = imax + 1; } return(buffers); }
public static void GenerateFillMesh(ShapeData shape, MeshBuilder meshBuilder) { Profiler.BeginSample("GenerateFillMesh"); if (shape.GetVertexInfoList().Count < 3) { return; } Matrix4x4 m = Matrix4x4.TRS(Vector3.zero, Quaternion.LookRotation(shape.FillNormal), Vector3.one).inverse; // tesselation ContourVertex[] contour = new ContourVertex[shape.GetVertexInfoList().Count - 2 - (shape.IsStrokeClosed ? 1 : 0)]; // ignore first and last point for (int i = 0; i < contour.Length; i++) { Vector3 p = m.MultiplyPoint(shape.GetVertexInfoList()[i + 1].position); var pos = new Vec3(); pos.X = p.x; pos.Y = p.y; pos.Z = 0; var v = new ContourVertex(); v.Position = pos; v.Data = shape.GetVertexInfoList()[i + 1].position; contour[i] = v; } if (tesselator == null) { tesselator = new Tess(); //tesselator.UsePooling = true; } tesselator.AddContour(contour, ContourOrientation.CounterClockwise); tesselator.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3, delegate(Vec3 position, object[] data, float[] weights) { return((Vector3)data[0] * weights[0] + (Vector3)data[1] * weights[1] + (Vector3)data[2] * weights[2] + (Vector3)data[3] * weights[3]); }); meshBuilder.currentSubmesh = 0; for (int i = 0; i < tesselator.ElementCount; i++) { meshBuilder.AddTriangle( meshBuilder.currentVertCount + tesselator.Elements[i * 3 + 0], meshBuilder.currentVertCount + tesselator.Elements[i * 3 + 1], meshBuilder.currentVertCount + tesselator.Elements[i * 3 + 2]); } for (int i = 0; i < tesselator.Vertices.Length; i++) { meshBuilder.AddVert(); meshBuilder.SetCurrentPosition((Vector3)tesselator.Vertices[i].Data); meshBuilder.SetCurrentColor(shape.FillColor); meshBuilder.SetCurrentUV0((Vector2)(Vector3)tesselator.Vertices[i].Data); } Profiler.EndSample(); }
public ActiveRegionDict(Tess tess) { _tess = tess; _head = Node.Create(); _head._key = null; _head._prev = _head; _head._next = _head; }
private static void TessellateShapeLibTess(Shape vectorShape, Color color, List <Geometry> geoms, TessellationOptions tessellationOptions) { UnityEngine.Profiling.Profiler.BeginSample("LibTess"); var tess = new Tess(); var angle = 45.0f * Mathf.Deg2Rad; var mat = Matrix2D.RotateLH(angle); var invMat = Matrix2D.RotateLH(-angle); var pats = new List <Vector2[]>(); foreach (var c in vectorShape.Contours) { var contour = new List <Vector2>(100); var tracedshape = ShapeUtils.TraceShape(c, vectorShape.PathProps.Stroke, tessellationOptions); foreach (var v in tracedshape) { contour.Add(mat.MultiplyPoint(v)); } pats.Add(tracedshape); tess.AddContour(contour.Select(v => new ContourVertex() { Position = new Vec3() { X = v.x, Y = v.y } }).ToArray(), ContourOrientation.Original); } var windingRule = (vectorShape.Fill.Mode == FillMode.OddEven) ? WindingRule.EvenOdd : WindingRule.NonZero; try { tess.Tessellate(windingRule, ElementType.Polygons, 3); } catch (System.Exception) { Debug.LogWarning("Shape tessellation failed, skipping..."); UnityEngine.Profiling.Profiler.EndSample(); return; } var indices = tess.Elements.Select(i => (UInt16)i); var vertices = tess.Vertices.Select(v => invMat.MultiplyPoint(new Vector2(v.Position.X, v.Position.Y))); var paths = pats.ToArray(); if (indices.Count() > 0) { geoms.Add(new Geometry() { Vertices = vertices.ToArray(), Indices = indices.ToArray(), Paths = paths, Color = color, Fill = vectorShape.Fill, FillTransform = vectorShape.FillTransform }); } UnityEngine.Profiling.Profiler.EndSample(); }
/// <summary> /// Triangulate this solid. /// </summary> /// <param name="mesh">The mesh to which the solid's tessellated data will be added.</param> /// <param name="transform">An optional transform used to transform the generated vertex coordinates.</param> /// <param name="color">An optional color to apply to the vertex.</param> public void Tessellate(ref Mesh mesh, Transform transform = null, Color color = default(Color)) { foreach (var f in this.Faces.Values) { var tess = new Tess(); tess.NoEmptyPolygons = true; tess.AddContour(f.Outer.ToContourVertexArray(f)); if (f.Inner != null) { foreach (var loop in f.Inner) { tess.AddContour(loop.ToContourVertexArray(f)); } } tess.Tessellate(WindingRule.Positive, LibTessDotNet.Double.ElementType.Polygons, 3); var faceMesh = new Mesh(); (Vector3 U, Vector3 V)basis = (default(Vector3), default(Vector3)); for (var i = 0; i < tess.ElementCount; i++) { var a = tess.Vertices[tess.Elements[i * 3]].Position.ToVector3(); var b = tess.Vertices[tess.Elements[i * 3 + 1]].Position.ToVector3(); var c = tess.Vertices[tess.Elements[i * 3 + 2]].Position.ToVector3(); if (transform != null) { a = transform.OfPoint(a); b = transform.OfPoint(b); c = transform.OfPoint(c); } if (i == 0) { // Calculate the texture space basis vectors // from the first triangle. This is acceptable // for planar faces. // TODO: Update this when we support non-planar faces. // https://gamedev.stackexchange.com/questions/172352/finding-texture-coordinates-for-plane var n = f.Plane().Normal; basis = n.ComputeDefaultBasisVectors(); } var v1 = faceMesh.AddVertex(a, new UV(basis.U.Dot(a), basis.V.Dot(a)), color: color); var v2 = faceMesh.AddVertex(b, new UV(basis.U.Dot(b), basis.V.Dot(b)), color: color); var v3 = faceMesh.AddVertex(c, new UV(basis.U.Dot(c), basis.V.Dot(c)), color: color); faceMesh.AddTriangle(v1, v2, v3); } mesh.AddMesh(faceMesh); } }
/// <summary> /// Get the tessellation. /// </summary> public Tess GetTess() { var tess = new Tess { NoEmptyPolygons = true }; tess.AddContour(polygon.Vertices.ToContourVertices()); tess.Tessellate(WindingRule.Positive, ElementType.Polygons, 3); return(tess); }
// From https://github.com/memononen/libtess2/issues/14 public void Tesselate_WithThinQuad_DoesNotCrash() { string data = "9.5,7.5,-0.5\n9.5,2,-0.5\n9.5,2,-0.4999999701976776123\n9.5,7.5,-0.4999999701976776123"; using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data))) { var pset = DataLoader.LoadDat(stream); var tess = new Tess(); PolyConvert.ToTess(pset, tess); tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); } }
List <PointF[]> checkPoly(PointF[] poly) { List <PointF[]> output = new List <PointF[]>(); PointF[] source = poly.ToArray(); if ((poly[0].X != poly[poly.Length - 1].X) && (poly[0].Y != poly[poly.Length - 1].Y)) { PointF[] tempPoly = new PointF[poly.Length + 1]; for (int pt = 0; pt < poly.Length; pt++) { tempPoly[pt] = new PointF(poly[pt].X, poly[pt].Y); } tempPoly[tempPoly.Length - 1] = new PointF(tempPoly[0].X, tempPoly[0].Y); source = tempPoly.ToArray(); } // Now we need to check for polyfill, and triangulate the polygon if needed. if (enableFilledPolys) { var tess = new Tess(); ContourVertex[] contour = new ContourVertex[source.Length]; for (int pt = 0; pt < contour.Length; pt++) { contour[pt].Position = new Vec3 { X = source[pt].X, Y = source[pt].Y, Z = 0 }; } tess.AddContour(contour, ContourOrientation.Clockwise); // keep our orientation to allow holes to be handled. // Triangulate. tess.Tessellate(WindingRule.Positive, ElementType.Polygons, 3); // We don't have any hole polygons here. // Iterate triangles and create output geometry for (int i = 0; i < tess.ElementCount; i++) { PointF[] tempPoly = new PointF[3]; // 3 points. tempPoly[0] = new PointF((float)tess.Vertices[tess.Elements[i * 3]].Position.X, (float)tess.Vertices[tess.Elements[i * 3]].Position.Y); tempPoly[1] = new PointF((float)tess.Vertices[tess.Elements[(i * 3) + 1]].Position.X, (float)tess.Vertices[tess.Elements[(i * 3) + 1]].Position.Y); tempPoly[2] = new PointF((float)tess.Vertices[tess.Elements[(i * 3) + 2]].Position.X, (float)tess.Vertices[tess.Elements[(i * 3) + 2]].Position.Y); output.Add(clockwiseOrder(tempPoly).ToArray()); } } else { output.Add(source.ToArray()); } return(output); }
public static void GenerateShadowMesh(Mesh mesh, Vector3[] shapePath) { Color meshInteriorColor = new Color(0, 0, 0, 1); List <Vector3> vertices = new List <Vector3>(); List <int> triangles = new List <int>(); List <Vector4> tangents = new List <Vector4>(); // Create interior geometry int pointCount = shapePath.Length; var inputs = new ContourVertex[pointCount]; for (int i = 0; i < pointCount; ++i) { inputs[i] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y }, Data = meshInteriorColor } } ; Tess tessI = new Tess(); tessI.AddContour(inputs, ContourOrientation.Original); tessI.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3, InterpCustomVertexData); var indicesI = tessI.Elements.Select(i => i).ToArray(); var verticesI = tessI.Vertices.Select(v => new Vector3(v.Position.X, v.Position.Y, 0)).ToArray(); vertices.AddRange(verticesI); triangles.AddRange(indicesI); InitializeTangents(vertices.Count, tangents); List <Edge> edges = new List <Edge>(); PopulateEdgeArray(vertices, triangles, edges); SortEdges(edges); CreateShadowTriangles(vertices, triangles, tangents, edges); Vector3[] finalVertices = vertices.ToArray(); int[] finalTriangles = triangles.ToArray(); Vector4[] finalTangents = tangents.ToArray(); mesh.Clear(); mesh.vertices = finalVertices; mesh.triangles = finalTriangles; mesh.tangents = finalTangents; } }
public static void ToTess(PolygonSet pset, Tess tess) { foreach (var poly in pset) { var v = new ContourVertex[poly.Count]; for (int i = 0; i < poly.Count; i++) { v[i].Position = new Vec3(poly[i].X, poly[i].Y, poly[i].Z); v[i].Data = poly[i].Color; } tess.AddContour(v, poly.Orientation); } }
internal static Tess TessFromPolygons(Polygon[] polygons) { var tess = new Tess(); tess.NoEmptyPolygons = true; foreach (var p in polygons) { AddContour(tess, p); } return(tess); }
private static void BuildGeometryFromClipPaths(VectorUtils.Geometry geom, List <List <IntPoint> > paths, List <Vector2> outVerts, List <UInt16> outInds, ref UInt16 maxIndex) { var vertices = new List <Vector2>(100); var indices = new List <UInt16>(vertices.Capacity * 3); var vertexIndex = new Dictionary <IntPoint, UInt16>(); foreach (var path in paths) { if (path.Count == 3) { // Triangle case, no need to tessellate foreach (var pt in path) { StoreClipVertex(vertexIndex, vertices, indices, pt, ref maxIndex); } } else if (path.Count > 3) { // Generic polygon case, we need to tessellate first var tess = new Tess(); var contour = new ContourVertex[path.Count]; for (int i = 0; i < path.Count; ++i) { contour[i] = new ContourVertex() { Position = new Vec3() { X = path[i].X, Y = path[i].Y, Z = 0.0f } } } ; tess.AddContour(contour, ContourOrientation.Original); var windingRule = WindingRule.NonZero; tess.Tessellate(windingRule, ElementType.Polygons, 3); foreach (var e in tess.Elements) { var v = tess.Vertices[e]; var pt = new IntPoint(v.Position.X, v.Position.Y); StoreClipVertex(vertexIndex, vertices, indices, pt, ref maxIndex); } } } var invMatrix = geom.WorldTransform.Inverse(); outVerts.AddRange(vertices.Select(v => invMatrix * v)); outInds.AddRange(indices); }
private void AddContour(Tess tess, Polygon p, bool reversed = false) { var numPoints = p.Vertices.Count; var contour = new ContourVertex[numPoints]; for (var i = 0; i < numPoints; i++) { var v = p.Vertices[i]; contour[i].Position = new Vec3 { X = v.X, Y = v.Y, Z = v.Z }; } tess.AddContour(contour, reversed ? ContourOrientation.Clockwise : ContourOrientation.CounterClockwise); }
public static UnityEngine.Mesh BuildMesh(List <Vector2[]> contours) { Tess tesselation = new Tess(); foreach (Vector2[] contour in contours) { if (contour == null) { continue; } int pathLength = contour.Length; ContourVertex[] path = new ContourVertex[pathLength]; for (int j = 0; j < pathLength; j++) { Vector2 position = contour[j]; path[j].Position = new Vec3 { X = position.x, Y = position.y, Z = 0f }; } tesselation.AddContour(path); } tesselation.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); UnityEngine.Mesh mesh = new UnityEngine.Mesh(); int meshVertexCount = tesselation.Vertices.Length; Vector3[] vertices = new Vector3[meshVertexCount]; for (int i = 0; i < meshVertexCount; i++) { vertices[i] = new Vector3(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y, 0f); } int numTriangles = tesselation.ElementCount; int[] triangles = new int[numTriangles * 3]; for (int i = 0; i < numTriangles; i++) { triangles[i * 3] = tesselation.Elements[i * 3]; triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1]; triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2]; } mesh.vertices = vertices; mesh.triangles = triangles; return(mesh); }
/// <summary> /// Gets the tessellator available. /// </summary> /// <returns></returns> public Tess GetTessellatorAvailable() { if (!AvailableTessellators.TryDequeue(out var tess)) { tess = new Tess { NoEmptyPolygons = true }; if (Interlocked.Increment(ref TessellatorCount) > Environment.ProcessorCount) { Console.WriteLine($"WARNING: Greater number of Tessellators than Processors' count has been Created! Number has reached {TessellatorCount}!"); } } return(tess); }