private static (Mesh Mesh, double MaxElevation, double MinElevation) GenerateMesh( double[] elevations, Vector3 origin, int rowWidth, double cellWidth, double cellHeight) { var minElevation = double.MaxValue; var maxElevation = double.MinValue; var mesh = new Mesh(); var triangles = (Math.Sqrt(elevations.Length) - 1) * rowWidth * 2; for (var y = 0; y < rowWidth; y++) { for (var x = 0; x < rowWidth; x++) { var ei = x + y * rowWidth; var el = elevations[ei]; minElevation = Math.Min(minElevation, el); maxElevation = Math.Max(maxElevation, el); var u = (double)x / (double)(rowWidth - 1); var v = (double)y / (double)(rowWidth - 1); // Shrink the UV space slightly to avoid // visible edges on applied textures. var uvTol = 0.001; u = u == 0.0 ? uvTol : u; v = v == 0.0 ? uvTol : v; u = u == 1.0 ? 1 - uvTol : u; v = v == 1.0 ? 1 - uvTol : v; var uv = new UV(u, v); mesh.AddVertex(origin + new Vector3(x * cellWidth, y * cellHeight, el), uv: uv); if (y > 0 && x > 0) { var i = x + y * rowWidth; // Top triangle var a = mesh.Vertices[i]; var b = mesh.Vertices[i - 1]; var c = mesh.Vertices[i - rowWidth]; var tt = mesh.AddTriangle(a, b, c); // Bottom triangle var d = mesh.Vertices[i - 1]; var e = mesh.Vertices[i - 1 - rowWidth]; var f = mesh.Vertices[i - rowWidth]; var tb = mesh.AddTriangle(d, e, f); } } } mesh.ComputeNormals(); return(mesh, maxElevation, minElevation); }
/// <summary> /// Create a topography from a custom mesh. It is assumed that the mesh is an open mesh that's roughly parallel to the XY plane. /// </summary> /// <param name="mesh">The mesh geometry of the topography.</param> /// <param name="material">The topography's material.</param> /// <param name="transform">The topography's transform.</param> /// <param name="id">The topography's id.</param> /// <param name="name">The topography's name.</param> /// <returns></returns> public Topography(Mesh mesh, Material material, Transform transform, Guid id, string name) : base(material, transform, false, id, name) { var newMesh = new Mesh(mesh); var bbox = new BBox3(mesh.Vertices.Select(v => v.Position)); this._minElevation = bbox.Min.Z; this._maxElevation = bbox.Max.Z; double absoluteMinimumElevation = this.AbsoluteMinimumElevation ?? this.MinElevation - this.DepthBelowMinimumElevation; var nakedBoundaries = mesh.GetNakedBoundaries(); var basePlane = new Plane((0, 0, absoluteMinimumElevation), (0, 0, 1)); foreach (var polygon in nakedBoundaries) { // construct bottom var bottomPolygon = polygon.Project(basePlane); var tess = new Tess { NoEmptyPolygons = true }; tess.AddContour(bottomPolygon.Reversed().ToContourVertexArray()); tess.Tessellate(WindingRule.Positive, ElementType.Polygons, 3); var faceMesh = tess.ToMesh(normal: (0, 0, -1)); this._baseVerts = new List <Vertex>(faceMesh.Vertices); newMesh.AddMesh(faceMesh); // construct sides var upperSegments = polygon.Segments(); var lowerSegments = bottomPolygon.Segments(); for (int i = 0; i < upperSegments.Count(); i++) { var topEdge = upperSegments[i]; var bottomEdge = lowerSegments[i]; var normal = topEdge.Direction().Cross(Vector3.ZAxis).Unitized(); var a = newMesh.AddVertex(topEdge.Start, normal: normal); var b = newMesh.AddVertex(topEdge.End, normal: normal); var c = newMesh.AddVertex(bottomEdge.End, normal: normal); var d = newMesh.AddVertex(bottomEdge.Start, normal: normal); newMesh.AddTriangle(a, c, b); newMesh.AddTriangle(a, d, c); } } this.Mesh = newMesh; }
private void CreateSidesAndBottomMesh(Mesh mesh, int rowWidth, double depth, double cellHeight, double cellWidth, Vector3 origin) { // Track the last created "low" // point so that we can merge // vertices in the side meshes. Vertex lastL = null; Vertex lastR = null; Vertex lastT = null; Vertex lastB = null; (Vector3 U, Vector3 V)basisLeft = (default(Vector3), default(Vector3)); (Vector3 U, Vector3 V)basisRight = (default(Vector3), default(Vector3)); (Vector3 U, Vector3 V)basisTop = (default(Vector3), default(Vector3)); (Vector3 U, Vector3 V)basisBottom = (default(Vector3), default(Vector3)); this._baseVerts.Clear(); for (var u = 0; u < rowWidth - 1; u++) { if (u == 0) { basisLeft = Vector3.XAxis.Negate().ComputeDefaultBasisVectors(); basisRight = Vector3.XAxis.ComputeDefaultBasisVectors(); basisTop = Vector3.YAxis.ComputeDefaultBasisVectors(); basisBottom = Vector3.YAxis.Negate().ComputeDefaultBasisVectors(); } // Left side Vertex l1 = null; var i1 = u * rowWidth; var v1Existing = mesh.Vertices[i1]; var v1 = mesh.AddVertex(v1Existing.Position, normal: Vector3.XAxis.Negate()); if (lastL != null) { l1 = lastL; } else { var p = new Vector3(v1.Position.X, v1.Position.Y, depth); l1 = mesh.AddVertex(p); _baseVerts.Add(l1); } var i2 = i1 + rowWidth; var v2Existing = mesh.Vertices[i2]; var v2 = mesh.AddVertex(v2Existing.Position); var pl2 = new Vector3(v2.Position.X, v2.Position.Y, depth); var l2 = mesh.AddVertex(pl2); _baseVerts.Add(l2); lastL = l2; mesh.AddTriangle(l1, v1, v2); mesh.AddTriangle(l2, l1, v2); // Right side Vertex l3 = null; var i3 = u * (rowWidth) + (rowWidth - 1); var v3Existing = mesh.Vertices[i3]; var v3 = mesh.AddVertex(v3Existing.Position, normal: Vector3.XAxis); if (lastR != null) { l3 = lastR; } else { var p = new Vector3(v3.Position.X, v3.Position.Y, depth); l3 = mesh.AddVertex(p); _baseVerts.Add(l3); } var i4 = i3 + rowWidth; var v4Existing = mesh.Vertices[i4]; var v4 = mesh.AddVertex(v4Existing.Position); var pl4 = new Vector3(v4.Position.X, v4.Position.Y, depth); var l4 = mesh.AddVertex(pl4); _baseVerts.Add(l4); lastR = l4; mesh.AddTriangle(l3, v4, v3); mesh.AddTriangle(l3, l4, v4); // Top side Vertex l5 = null; var i5 = u; var v5Existing = mesh.Vertices[i5]; var v5 = mesh.AddVertex(v5Existing.Position, normal: Vector3.YAxis); if (lastT != null) { l5 = lastT; } else { var p = new Vector3(v5.Position.X, v5.Position.Y, depth); l5 = mesh.AddVertex(p); _baseVerts.Add(l5); } var i6 = i5 + 1; var v6Existing = mesh.Vertices[i6]; var v6 = mesh.AddVertex(v6Existing.Position); var pl6 = new Vector3(v6.Position.X, v6.Position.Y, depth); var l6 = mesh.AddVertex(pl6); _baseVerts.Add(l6); lastT = l6; mesh.AddTriangle(l5, v6, v5); mesh.AddTriangle(l5, l6, v6); // Bottom side Vertex l7 = null; var i7 = rowWidth * rowWidth - u - 1; var v7Existing = mesh.Vertices[i7]; var v7 = mesh.AddVertex(v7Existing.Position, normal: Vector3.YAxis.Negate()); if (lastB != null) { l7 = lastB; } else { var p = new Vector3(v7.Position.X, v7.Position.Y, depth); l7 = mesh.AddVertex(p); _baseVerts.Add(l7); } var i8 = i7 - 1; var v8Existing = mesh.Vertices[i8]; var v8 = mesh.AddVertex(v8Existing.Position); var pl8 = new Vector3(v8.Position.X, v8.Position.Y, depth); var l8 = mesh.AddVertex(pl8); _baseVerts.Add(l8); lastB = l8; mesh.AddTriangle(l7, v8, v7); mesh.AddTriangle(l7, l8, v8); } // Add the bottom var bb1 = mesh.AddVertex(origin + new Vector3(0, 0, depth)); var bb2 = mesh.AddVertex(origin + new Vector3((rowWidth - 1) * cellWidth, 0, depth)); var bb3 = mesh.AddVertex(origin + new Vector3((rowWidth - 1) * cellWidth, (rowWidth - 1) * cellHeight, depth)); var bb4 = mesh.AddVertex(origin + new Vector3(0, (rowWidth - 1) * cellHeight, depth)); _baseVerts.AddRange(new[] { bb1, bb2, bb3, bb4 }); mesh.AddTriangle(bb1, bb3, bb2); mesh.AddTriangle(bb1, bb4, bb3); mesh.ComputeNormals(); }