/// <summary> /// Initializes a new instance of the <see cref="SimpleSmoother" /> class. /// </summary> /// <param name="factory">Voronoi object factory.</param> /// <param name="config">Configuration.</param> public SimpleSmoother(IVoronoiFactory factory, Configuration config) { this.factory = factory; this.config = config; this.options = new ConstraintOptions() { ConformingDelaunay = true }; }
/// <summary> /// Initializes a new instance of the <see cref="SimpleSmoother" /> class. /// </summary> /// <param name="factory">Voronoi object factory.</param> /// <param name="predicates">Geometric predicates implementation.</param> public SimpleSmoother(IVoronoiFactory factory, IPredicates predicates) { this.factory = factory; this.predicates = predicates; this.options = new ConstraintOptions() { ConformingDelaunay = true }; }
/// <summary> /// Initializes a new instance of the <see cref="SimpleSmoother" /> class. /// </summary> public SimpleSmoother(IVoronoiFactory factory) { this.factory = factory; this.pool = new TrianglePool(); this.config = new Configuration( () => RobustPredicates.Default, () => pool.Restart()); this.options = new ConstraintOptions() { ConformingDelaunay = true }; }
/// <summary> /// Insert segments into the mesh. /// </summary> /// <param name="input">The polygon.</param> /// <param name="options">Constraint options.</param> public void Apply(IPolygon input, ConstraintOptions options) { behavior.Poly = input.Segments.Count > 0; // Copy constraint options if (options != null) { behavior.ConformingDelaunay = options.ConformingDelaunay; behavior.Convex = options.Convex; behavior.NoBisect = options.SegmentSplitting; if (behavior.ConformingDelaunay) { behavior.Quality = true; } } //if (input.EdgeMarkers != null) //{ // behavior.UseBoundaryMarkers = true; //} behavior.useRegions = input.Regions.Count > 0; // Ensure that no vertex can be mistaken for a triangular bounding // box vertex in insertvertex(). mesh.infvertex1 = null; mesh.infvertex2 = null; mesh.infvertex3 = null; if (behavior.useSegments) { // Segments will be introduced next. mesh.checksegments = true; // Insert PSLG segments and/or convex hull segments. FormSkeleton(input); } if (behavior.Poly && (mesh.triangles.Count > 0)) { // Copy holes and regions mesh.holes.AddRange(input.Holes); mesh.regions.AddRange(input.Regions); // Carve out holes and concavities. CarveHoles(); } }
/// <inheritdoc /> public IMesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality) { var mesh = (Mesh)triangulator.Triangulate(polygon.Points, config); var cmesher = new ConstraintMesher(mesh, config); var qmesher = new QualityMesher(mesh, config); mesh.SetQualityMesher(qmesher); // Insert segments. cmesher.Apply(polygon, options); // Refine mesh. qmesher.Apply(quality); return(mesh); }
/// <inheritdoc /> public IMesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality) { var mesh = (Mesh)triangulator.Triangulate(polygon.Points, config); var cmesher = new ConstraintMesher(mesh, config); var qmesher = new QualityMesher(mesh, config); mesh.SetQualityMesher(qmesher); // Insert segments. cmesher.Apply(polygon, options); // Refine mesh. qmesher.Apply(quality); return mesh; }
public static void ExtrudeText(this MeshBuilder builder, string text, string font, FontStyle fontStyle, FontWeight fontWeight, double fontSize, Vector3D textDirection, Point3D p0, Point3D p1) { var outlineList = GetTextOutlines(text, font, fontStyle, fontWeight, fontSize); // Build the polygon to mesh (using Triangle.NET to triangulate) var polygon = new TriangleNet.Geometry.Polygon(); int marker = 0; foreach (var outlines in outlineList) { var outerOutline = outlines.OrderBy(x => x.AreaOfSegment()).Last(); for (int i = 0; i < outlines.Count; i++) { var outline = outlines[i]; var isHole = i != outlines.Count - 1 && IsPointInPolygon(outerOutline, outline[0]); polygon.AddContour(outline.Select(p => new Vertex(p.X, p.Y)), marker++, isHole); builder.AddExtrudedSegments(outline.ToSegments().ToList(), textDirection, p0, p1); } } var mesher = new GenericMesher(); var options = new ConstraintOptions(); var mesh = mesher.Triangulate(polygon, options); var u = textDirection; u.Normalize(); var z = p1 - p0; z.Normalize(); var v = Vector3D.CrossProduct(z, u); // Convert the triangles foreach (var t in mesh.Triangles) { var v0 = t.GetVertex(0); var v1 = t.GetVertex(1); var v2 = t.GetVertex(2); // Add the top triangle. // Project the X/Y vertices onto a plane defined by textdirection, p0 and p1. builder.AddTriangle(v0.Project(p0, u, v, z, 1), v1.Project(p0, u, v, z, 1), v2.Project(p0, u, v, z, 1)); // Add the bottom triangle. builder.AddTriangle(v2.Project(p0, u, v, z, 0), v1.Project(p0, u, v, z, 0), v0.Project(p0, u, v, z, 0)); } }
public void MakeMesh(Vector3[] _vertices) { Polygon polygon = new Polygon(); elevations.Clear(); for (int i = 0; i < _vertices.Length; i++) { polygon.Add(new Vertex(_vertices[i].x, _vertices[i].z)); elevations.Add(_vertices[i].y); } Debug.Log("Length of polygon vertex-count: " + polygon.Count + "\n Length of elevations:" + elevations.Count); int trianglesInChunk = 400; TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true, Convex = false, SegmentSplitting = 1 }; mesh = (TriangleNet.Mesh)polygon.Triangulate(options); /* * foreach (Vertex vert in mesh.Vertices) * { * elevations.Add(7); * } */ Debug.Log("Mesh.vertices at breakpoint: " + mesh.Vertices.Count); // Instantiate an enumerator to go over the Triangle.Net triangles - they don't // provide any array-like interface for indexing IEnumerator <Triangle> triangleEnumerator = mesh.Triangles.GetEnumerator(); // Create more than one chunk, if necessary for (int chunkStart = 0; chunkStart < mesh.Triangles.Count; chunkStart += trianglesInChunk) { // Vertices in the unity mesh List <Vector3> vertices = new List <Vector3>(); // Per-vertex normals List <Vector3> normals = new List <Vector3>(); // Per-vertex UVs - unused here, but Unity still wants them List <Vector2> uvs = new List <Vector2>(); // Triangles - each triangle is made of three indices in the vertices array List <int> triangles = new List <int>(); // Iterate over all the triangles until we hit the maximum chunk size int chunkEnd = chunkStart + trianglesInChunk; for (int i = chunkStart; i < chunkEnd; i++) { if (!triangleEnumerator.MoveNext()) { // If we hit the last triangle before we hit the end of the chunk, stop break; } // Get the current triangle Triangle triangle = triangleEnumerator.Current; // For the triangles to be right-side up, they need // to be wound in the opposite direction Vector3 v0 = GetPoint3D(triangle.vertices[2].id); Vector3 v1 = GetPoint3D(triangle.vertices[1].id); Vector3 v2 = GetPoint3D(triangle.vertices[0].id); // This triangle is made of the next three vertices to be added triangles.Add(vertices.Count); triangles.Add(vertices.Count + 1); triangles.Add(vertices.Count + 2); triangles.Add(vertices.Count); triangles.Add(vertices.Count + 2); triangles.Add(vertices.Count + 1); // Add the vertices vertices.Add(v0); vertices.Add(v1); vertices.Add(v2); // Compute the normal - flat shaded, so the vertices all have the same normal Vector3 normal = Vector3.Cross(v1 - v0, v2 - v0); normals.Add(normal); normals.Add(normal); normals.Add(normal); // If you want to texture your terrain, UVs are important, // but I just use a flat color so put in dummy coords uvs.Add(new Vector2(0.0f, 0.0f)); uvs.Add(new Vector2(0.0f, 0.0f)); uvs.Add(new Vector2(0.0f, 0.0f)); } // Create the actual Unity mesh object UnityEngine.Mesh chunkMesh = new UnityEngine.Mesh(); chunkMesh.vertices = vertices.ToArray(); chunkMesh.uv = uvs.ToArray(); chunkMesh.triangles = triangles.ToArray(); chunkMesh.normals = normals.ToArray(); // Instantiate the GameObject which will display this chunk Transform chunk = Instantiate <Transform>(chunkPrefab, transform.position, transform.rotation); chunk.GetComponent <MeshFilter>().mesh = chunkMesh; //chunk.GetComponent<MeshCollider>().sharedMesh = chunkMesh; chunk.transform.parent = transform; } }
/// <inheritdoc /> public IMesh Triangulate(IPolygon polygon, ConstraintOptions options) { return(Triangulate(polygon, options, null)); }
/// <summary> /// Triangulates a polygon, applying quality and constraint options. /// </summary> /// <param name="options">Constraint options.</param> /// <param name="quality">Quality options.</param> /// <param name="triangulator">The triangulation algorithm.</param> public static IMesh Triangulate(this IPolygon polygon, ConstraintOptions options, QualityOptions quality, ITriangulator triangulator) { return (new GenericMesher(triangulator)).Triangulate(polygon, options, quality); }
/// <summary> /// Triangulates a polygon, applying constraint options. /// </summary> /// <param name="options">Constraint options.</param> public static IMesh Triangulate(this IPolygon polygon, ConstraintOptions options) { return (new GenericMesher()).Triangulate(polygon, options, null); }
/// <inheritdoc /> public IMesh Triangulate(IPolygon polygon, ConstraintOptions options) { return Triangulate(polygon, options, null); }
private void Triangulate() { if (input == null) return; var options = new ConstraintOptions(); var quality = new QualityOptions(); if (meshControlView.ParamConformDelChecked) { options.ConformingDelaunay = true; } if (meshControlView.ParamQualityChecked) { quality.MinimumAngle = meshControlView.ParamMinAngleValue; double maxAngle = meshControlView.ParamMaxAngleValue; if (maxAngle < 180) { quality.MaximumAngle = maxAngle; } // Ignore area constraints on initial triangulation. //double area = slMaxArea.Value * 0.01; //if (area > 0 && area < 1) //{ // var size = input.Bounds; // double min = Math.Min(size.Width, size.Height); // mesh.SetOption(Options.MaxArea, area * min); //} } if (meshControlView.ParamConvexChecked) { options.Convex = true; } try { if (meshControlView.ParamSweeplineChecked) { mesh = (Mesh)input.Triangulate(options, quality, new SweepLine()); } else { mesh = (Mesh)input.Triangulate(options, quality); } statisticView.UpdateStatistic(mesh); HandleMeshUpdate(); if (meshControlView.ParamQualityChecked) { settings.RefineMode = true; } } catch (Exception ex) { LockOnException(); DarkMessageBox.Show("Exception - Triangulate", ex.Message, MessageBoxButtons.OK); } UpdateLog(); }
private static Mesh GetTriangleDotNetMesh(List <Vector2[]> poly_vertices) { var num_vxs = 0; foreach (var ring_vxs in poly_vertices) { num_vxs += ring_vxs.Length + 1; } var poly = new TriangleNet.Geometry.Polygon(num_vxs); // set vertices var ri = 0; foreach (var ring_vxs in poly_vertices) { var vxs_input = new List <TriangleNet.Geometry.Vertex>(ring_vxs.Length + 1); foreach (var vx in ring_vxs) { vxs_input.Add(new TriangleNet.Geometry.Vertex(vx.x, vx.y)); } // add to poly bool is_hole = ri != 0; var contour = new TriangleNet.Geometry.Contour(vxs_input); poly.Add(contour, is_hole); ++ri; } // triangulate var opts = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; var tn_mesh = (TriangleNet.Mesh)poly.Triangulate(opts); // write var tri_vxs = new Vector3[tn_mesh.Triangles.Count * 3]; var tri_ids = new int[tn_mesh.Triangles.Count * 3]; int i = 0; foreach (var tri in tn_mesh.Triangles) { tri_vxs[i + 0] = new Vector3((float)tri.GetVertex(0).x, (float)tri.GetVertex(0).y, 0); tri_vxs[i + 1] = new Vector3((float)tri.GetVertex(2).x, (float)tri.GetVertex(2).y, 0); tri_vxs[i + 2] = new Vector3((float)tri.GetVertex(1).x, (float)tri.GetVertex(1).y, 0); tri_ids[i + 0] = i + 0; tri_ids[i + 1] = i + 1; tri_ids[i + 2] = i + 2; i += 3; } // create mesh var m = new Mesh(); // assign to mesh m.vertices = tri_vxs; m.triangles = tri_ids; // recompute geometry // QUESTION why do we need bounds? m.RecalculateNormals(); m.RecalculateBounds(); return(m); }
private void Triangulate_Click(object sender, RoutedEventArgs e) { var qualityOptions = new TriangleNet.Meshing.QualityOptions(); qualityOptions.MaximumArea = double.Parse(hTextBox.Text); qualityOptions.MinimumAngle = double.Parse(LTextBox.Text); var objct = new TriangleNet.Geometry.Polygon(); foreach (var item in mycoordinates) { objct.Add(item); } for (int i = 0; i < mycoordinates.Count - 1; i++) { objct.Add(new Segment(mycoordinates[i], mycoordinates[i + 1])); } objct.Add(new Segment(mycoordinates.LastOrDefault(), mycoordinates.FirstOrDefault())); //var test = new TriangleNet.Meshing.Algorithm.SweepLine(); var constraintOption = new TriangleNet.Meshing.ConstraintOptions(); meshResult = objct.Triangulate(constraintOption, qualityOptions, new TriangleNet.Meshing.Algorithm.Incremental()); //Triangulation //meshResult = objct.Triangulate(qualityOptions); meshResult.Renumber(); //triangleResult = new List<TriangleNet.Topology.Triangle>(meshResult.Triangles); //Triangles trianglesResult = GetTrianglesFromMeshTriangles(meshResult.Triangles); resultsTriangles.ItemsSource = trianglesResult; //Vertices verticesResult = new List <Vertex>(meshResult.Vertices); myvertixesResult = meshResult.Vertices.Select(v => new MyVertex { Id = v.ID, X = v.X, Y = v.Y }).ToList(); results.ItemsSource = myvertixesResult; //Заповнення граничних сегментів for (int i = 0; i < boundaries.Count; i++) { boundaries[i].SetSegments(meshResult.Segments, boundaries.Count); } //Перетворення орієнтації всіх сегментів проти годинникової стрілки for (int i = 0; i < boundaries.Count; i++) { if (i != boundaries.Count - 1) { boundaries[i].SetSegmentsOrientationToCounterclockwise(i, i + 1); } else { boundaries[i].SetSegmentsOrientationToCounterclockwise(i, 0); } } // FillGridWithBoundaries(resultsBoundaries, boundaries); DrawData(meshResult); //Етап 2: Створення матриць Me, Ke, Qe, Re, Pe //Підготовка //Зчитування параметрів double a11 = double.Parse(a11TextBox.Text); double a22 = double.Parse(a22TextBox.Text); double d = double.Parse(dTextBox.Text); double f = double.Parse(fTextBox.Text); //Створення масиву точок var CT = GetPointsArray(myvertixesResult); //Створення масиву трикутників var NT = GetTrianglesArray(trianglesResult); //Створення масиву граничних сегментів var NTGR = GetBoundarySegments(boundaries); //Створення масиву значень ф-кції f у точках var fe = GetFe(CT, f); //Етап 3 (ініціалізація A,B) //Кількість вузлів int nodeNumber = CT.Length; var A = new double[nodeNumber][]; for (int i = 0; i < nodeNumber; i++) { A[i] = new double[nodeNumber]; } var b = new double[nodeNumber]; //Створення Me, Ke, Qe (та їх розсилання) double[] function_value = new double[3]; for (int k = 0; k < trianglesResult.Count; k++) { //трикутник містить координати вузлів скінченного елемента var triangle = NT[k]; //Підготовка double[] i = CT[triangle[0]], j = CT[triangle[1]], m = CT[triangle[2]]; double Se = GetArea(i, j, m); double ai = GetA(j, m), bi = GetB(j, m), ci = GetC(j, m), aj = GetA(m, i), bj = GetB(m, i), cj = GetC(m, i), am = GetA(i, j), bm = GetB(i, j), cm = GetC(i, j); double[] a = new double[] { ai, aj, am }, B = new double[] { bi, bj, bm }, c = new double[] { ci, cj, cm }; function_value[0] = fe[triangle[0]]; function_value[1] = fe[triangle[1]]; function_value[2] = fe[triangle[2]]; //Ke var ke = new KE(k, Se, a11, a22, B, c); ke.print(); //Me var me = new ME(k, Se, d); me.print(); //Qe var qe = new QE(k, Se, fe); qe.print(); //Етап 3 for (int q = 0; q < 3; q++) { //triangle[q] це номер вузла елемента for (int w = 0; w < 3; w++) { A[triangle[q]][triangle[w]] += ke.Ke[q][w] + me.Me[q][w]; } b[triangle[q]] += qe.Qe[q][0]; } } //Створення Re, Pe (та їх розсилання) for (int k = 0; k < boundaries.Count; k++) { for (int l = 0; l < NTGR[k].Length; l++) { //сегмент містить координати вузлів граничного сегмента var segment = NTGR[k][l]; //Підготовка double[] i = CT[NTGR[k][l][0]], j = CT[NTGR[k][l][1]]; double Length = GetLength(i, j); //Re var re = new RE(k + l, boundaries[k].G, boundaries[k].B, Length, k + "|" + l + "|" + NTGR[k][l][0] + "-" + NTGR[k][l][1]); re.print(); //Pe var pe = new PE(k + l, boundaries[k].G, boundaries[k].B, boundaries[k].Uc, Length, k + "|" + l + "|" + NTGR[k][l][0] + "-" + NTGR[k][l][1]); pe.print(); //Етап 3 for (int q = 0; q < 2; q++) { //segment[q] це номер вузла сегмента for (int w = 0; w < 2; w++) { A[segment[q]][segment[w]] += re.Re[q][w]; } b[segment[q]] += pe.Pe[q][0]; } } } //Запис у файл A,b print(A, b); //Етап 3-2 var u = GausseMethod(nodeNumber, A, b); printNonFormatted(CT, u, "results.txt"); }
void Start() { //UnityEngine.Random.InitState(0); elevations = new List <float>(); //float[] seed = new float[octaves]; //for (int i = 0; i < octaves; i++) //{ // seed[i] = Random.Range(0.0f, 100.0f); //} Polygon polygon = new Polygon(); ShapeFile shapeFile = new ShapeFile(); shapeFile.Read(path); List <double> MinMax = shapeFile.FileHeader.GetMinMax(); double xMin = MinMax[0]; double xMax = MinMax[1]; double yMin = MinMax[2]; double yMax = MinMax[3]; int intxMin = (int)Math.Floor(xMin); int intxMax = (int)Math.Ceiling(xMax); int intyMin = (int)Math.Floor(yMin); int intyMax = (int)Math.Ceiling(yMax); Debug.Log(xMin); Debug.Log(intxMin); Debug.Log(yMin); Debug.Log(intyMin); xsize = 0; ysize = 0; Debug.Log(shapeFile.ToString()); //PoissonDiscSampler sampler = new PoissonDiscSampler(xsize, ysize, minPointRadius); //// Add uniformly-spaced points //foreach (Vector2 sample in sampler.Samples()) { // polygon.Add(new Vertex((double)sample.x, (double)sample.y)); //} //Add some randomly sampled points //for (int i = 0; i < randomPoints; i++) //{ // polygon.Add(new Vertex(Random.Range(0.0f, xsize), Random.Range(0.0f, ysize))); // xpoint = Random.Range(0.0f, xsize); // ypoint = Random.Range(0.0f, ysize); // Debug.Log(xpoint); // Debug.Log(ypoint); //} foreach (ShapeFileRecord record in shapeFile.Records) { foreach (Vector3 point in record.Points) { polygon.Add(new Vertex((double)point.x, (double)point.y)); xpoint = point.x; ypoint = point.y; xsize += 1; ysize += 1; elevations.Add(point.z); } } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; mesh = (TriangleNet.Mesh)polygon.Triangulate(options); // //bin = new TriangleBin(mesh, xsize, ysize, minPointRadius); // Sample perlin noise to get elevations //foreach (Vertex vert in mesh.Vertices) //{ // float elevation = 0.0f; // float amplitude = Mathf.Pow(persistence, octaves); // float frequency = 1.0f; // float maxVal = 0.0f; // for (int o = 0; o < octaves; o++) // { // float sample = (Mathf.PerlinNoise(seed[o] + (float)vert.x * sampleSize / (float)xsize * frequency, // seed[o] + (float)vert.y * sampleSize / (float)ysize * frequency) - 0.5f) * amplitude; // elevation += sample; // maxVal += amplitude; // amplitude /= persistence; // frequency *= frequencyBase; // } // elevation = elevation / maxVal; // Debug.Log(elevation); // Debug.Log(elevation * elevationScale); // elevations.Add(elevation * elevationScale); //} //foreach (ShapeFileRecord record in shapeFile.Records) //{ // foreach (Vector3 point in record.Points) // { // foreach (Vertex vert in mesh.Vertices) // { // elevations.Add(point.z); // zpoint = point.z; // Debug.Log(zpoint); // } // } // } MakeMesh(); //ScatterDetailMeshes(); }
public virtual void Generate() { UnityEngine.Random.InitState(0); elevations = new List <float>(); float[] seed = new float[octaves]; for (int i = 0; i < octaves; i++) { seed[i] = Random.Range(0.0f, 100.0f); } PoissonDiscSampler sampler = new PoissonDiscSampler(xsize, ysize, minPointRadius); Polygon polygon = new Polygon(); // Add uniformly-spaced points foreach (Vector2 sample in sampler.Samples()) { polygon.Add(new Vertex((double)sample.x, (double)sample.y)); } // Add some randomly sampled points for (int i = 0; i < randomPoints; i++) { polygon.Add(new Vertex(Random.Range(0.0f, xsize), Random.Range(0.0f, ysize))); } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; mesh = (TriangleNet.Mesh)polygon.Triangulate(options); bin = new TriangleBin(mesh, xsize, ysize, minPointRadius * 2.0f); // Sample perlin noise to get elevations foreach (Vertex vert in mesh.Vertices) { float elevation = 0.0f; float amplitude = Mathf.Pow(persistence, octaves); float frequency = 1.0f; float maxVal = 0.0f; for (int o = 0; o < octaves; o++) { float sample = (Mathf.PerlinNoise(seed[o] + (float)vert.x * sampleSize / (float)xsize * frequency, seed[o] + (float)vert.y * sampleSize / (float)ysize * frequency) - 0.5f) * amplitude; elevation += sample; maxVal += amplitude; amplitude /= persistence; frequency *= frequencyBase; } elevation = elevation / maxVal; elevations.Add(elevation * elevationScale); } MakeMesh(); ScatterDetailMeshes(); }
public void MakeMesh() { float elevationScale = Random.Range(elevationScaleLow, elevationScaleHigh); Debug.Log(elevationScale); int octaves = Random.Range(octavesLow, octavesHigh); float persistence = Random.Range(persistenceLow, persistenceHigh); // Vertex is TriangleNet.Geometry.Vertex Polygon polygon = new Polygon(); for (int i = 0; i < vertexNumber; i++) { var newVer = new Vertex(Random.Range(0, xsize / 2f), Random.Range(0, ysize / 2f)); polygon.Add(newVer); } // ConformingDelaunay is false by default; this leads to ugly long polygons at the edges // because the algorithm will try to keep the mesh convex TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; mesh = (TriangleNet.Mesh)polygon.Triangulate(options); float[] seed = new float[octaves]; for (int i = 0; i < octaves; i++) { seed[i] = Random.Range(0.0f, 100.0f); } // Sample perlin noise at each generated point to get elevation and store it in // the elevations array foreach (Vertex vert in mesh.Vertices) { float elevation = 0.0f; float amplitude = Mathf.Pow(persistence, octaves); float frequency = 1.0f; float maxVal = 0.0f; for (int o = 0; o < octaves; o++) { float sample = (Mathf.PerlinNoise(seed[o] + (float)vert.x * sampleSize / (float)xsize * frequency, seed[o] + (float)vert.y * sampleSize / (float)ysize * frequency) - 0.5f) * amplitude; elevation += sample; maxVal += amplitude; amplitude /= persistence; frequency *= frequencyBase; } elevation = elevation / maxVal; elevations.Add(elevation * elevationScale); } // Instantiate an enumerator to go over the Triangle.Net triangles - they don't // provide any array-like interface for indexing IEnumerator <Triangle> triangleEnumerator = mesh.Triangles.GetEnumerator(); // Create more than one chunk, if necessary for (int chunkStart = 0; chunkStart < mesh.Triangles.Count; chunkStart += trianglesInChunk) { // Vertices in the unity mesh List <Vector3> vertices = new List <Vector3>(); // Per-vertex normals List <Vector3> normals = new List <Vector3>(); // Per-vertex UVs - unused here, but Unity still wants them List <Vector2> uvs = new List <Vector2>(); // Triangles - each triangle is made of three indices in the vertices array List <int> triangles = new List <int>(); // Iterate over all the triangles until we hit the maximum chunk size int chunkEnd = chunkStart + trianglesInChunk; for (int i = chunkStart; i < chunkEnd; i++) { if (!triangleEnumerator.MoveNext()) { // If we hit the last triangle before we hit the end of the chunk, stop break; } // Get the current triangle Triangle triangle = triangleEnumerator.Current; // For the triangles to be right-side up, they need // to be wound in the opposite direction Vector3 v0 = GetPoint3D(triangle.vertices[2].id); Vector3 v1 = GetPoint3D(triangle.vertices[1].id); Vector3 v2 = GetPoint3D(triangle.vertices[0].id); // This triangle is made of the next three vertices to be added triangles.Add(vertices.Count); triangles.Add(vertices.Count + 1); triangles.Add(vertices.Count + 2); // Add the vertices vertices.Add(v0); vertices.Add(v1); vertices.Add(v2); // Compute the normal - flat shaded, so the vertices all have the same normal Vector3 normal = Vector3.Cross(v1 - v0, v2 - v0); normals.Add(normal); normals.Add(normal); normals.Add(normal); // If you want to texture your terrain, UVs are important, // but I just use a flat color so put in dummy coords uvs.Add(new Vector2(0.0f, 0.0f)); uvs.Add(new Vector2(0.0f, 0.0f)); uvs.Add(new Vector2(0.0f, 0.0f)); } // Create the actual Unity mesh object Mesh chunkMesh = new Mesh(); chunkMesh.vertices = vertices.ToArray(); chunkMesh.uv = uvs.ToArray(); chunkMesh.triangles = triangles.ToArray(); chunkMesh.normals = normals.ToArray(); chunkMesh.RecalculateNormals(); chunkMesh.RecalculateTangents(); chunkMesh.RecalculateBounds(); // Instantiate the GameObject which will display this chunk Transform chunk = new GameObject("terrain patch").GetComponent <Transform>(); chunk.gameObject.AddComponent <MeshFilter>().mesh = chunkMesh; chunk.gameObject.AddComponent <MeshCollider>().sharedMesh = chunkMesh; var rend = chunk.gameObject.AddComponent <MeshRenderer>(); rend.sharedMaterial = material; // rend.material = ColorManager.instance.GetMaterial(1f, false,false); chunk.gameObject.AddComponent <MeshCollider>(); chunk.transform.parent = transform; chunk.transform.position = new Vector3(-xsize / 4f, transform.position.y, -ysize / 4f); // chunk.transform.Translate(Random.Range(-10f, 10f), 0, Random.Range(-10f, 10f)); } }
void generateMesh(int xOffSet, int yOffSet) { #region Triangle.Net mesh Generation and trianglation elevations.Clear(); polygon = new Polygon(); mesh = null; for (int i = 0; i < randomPoints; i++) { polygon.Add(new Vertex(Random.Range(0.0f, xsize), Random.Range(0.0f, ysize))); } TriangleNet.Meshing.ConstraintOptions options = new TriangleNet.Meshing.ConstraintOptions() { ConformingDelaunay = true }; mesh = (TriangleNet.Mesh)polygon.Triangulate(options); boundedVoronoi = new TriangleNet.Voronoi.BoundedVoronoi(mesh); #endregion //setting up bounds to be used for generatating UVs meshBounds = new Bounds(new Vector3((float)mesh.Bounds.Left - (float)mesh.Bounds.Right, (float)mesh.Bounds.Top - (float)mesh.Bounds.Bottom), new Vector3((float)mesh.Bounds.Width, (float)mesh.Bounds.Height)); #region defining and sampling data from images or noise int randomMap = Random.Range(0, typesOfImages[selectedImagePoolIndex].Count); int min = 0; int maxW; int maxH; int maxX = 0; int maxY = 0; // setting width and height to be used for normalising the values to select the appropriate portion of the image if (useCustomImage) { circleGradient = customImage; maxW = circleGradient.width; maxH = circleGradient.height; } else { if (useImagePool) { circleGradient = typesOfImages[selectedImagePoolIndex][randomMap]; maxW = typesOfImages[selectedImagePoolIndex][randomMap].width; maxH = typesOfImages[selectedImagePoolIndex][randomMap].height; } else { maxW = circleGradient.width; maxH = circleGradient.height; } } //sampling image/noise and defining heights for (int i = 0; i < mesh.vertices.Count; i++) { float sample; if (usePerlinNoise) { sample = Mathf.PerlinNoise((float)mesh.vertices[i].x + xOffSet, (float)mesh.vertices[i].y + yOffSet); } else { int x = Mathf.FloorToInt(HelperFunctions.normalise((float)mesh.vertices[i].x, min, xsize, min, maxW)); int y = Mathf.FloorToInt(HelperFunctions.normalise((float)mesh.vertices[i].y, min, ysize, min, maxH)); maxX = Mathf.Max(x, maxX); maxY = Mathf.Max(y, maxY); sample = circleGradient.GetPixel(x, y).grayscale; } sample = defineIsland(sample, mesh.vertices[i]); elevations.Add(sample); } #endregion MakeMesh(xOffSet, yOffSet); }