/// <summary> /// Adds a grass billboard /// </summary> private void AddGrass(VertexTerrain v, List <VertexBillboard> grassVertices, List <int> grassIndices, Random r, Climate climate) { float rg = r.Next(50, 101) / 100.0f; Vector3 color = Vector3.One; if (climate == Climate.Tropical) { color = new Vector3(rg, rg, r.Next(40, 101) / 100.0f); } else if (climate == Climate.Polar) { color = new Vector3(rg, rg, rg); } else if (climate == Climate.Dry) { color = new Vector3(rg, rg, r.Next(1, 40) / 100.0f); } Vector2 scale = new Vector2(r.Next(5, 8), r.Next(5, 20) / 10.0f); grassVertices.Add(new VertexBillboard(v.Position, v.Normal, color, Vector2.Zero, scale)); grassVertices.Add(new VertexBillboard(v.Position, v.Normal, color, Vector2.UnitX, scale)); grassVertices.Add(new VertexBillboard(v.Position, v.Normal, color, Vector2.One, scale)); grassVertices.Add(new VertexBillboard(v.Position, v.Normal, color, Vector2.UnitY, scale)); int[] baseIndices = new int[] { 0, 1, 2, 0, 2, 3 }; int offset = grassIndices.Count / 6 * 4; for (int i = 0; i < 6; i++) { grassIndices.Add(baseIndices[i] + offset); } }
/// <summary> /// Adds a tree billboard /// </summary> private void AddTree(VertexTerrain v, List <VertexBillboard> treeVertices, List <int> treeIndices, Random r, Climate climate) { Vector3 color; if (climate == Climate.Polar) { color = new Vector3(1, r.Next(90, 101) / 100.0f, r.Next(90, 101) / 100.0f); } else { color = new Vector3(1, r.Next(90, 101) / 100.0f, r.Next(40, 101) / 100.0f); } Vector2 scale = new Vector2(r.Next(4, 11), r.Next(50, 100) / 10.0f); treeVertices.Add(new VertexBillboard(v.Position, Vector3.Up, color, Vector2.Zero, scale)); treeVertices.Add(new VertexBillboard(v.Position, Vector3.Up, color, Vector2.UnitX, scale)); treeVertices.Add(new VertexBillboard(v.Position, Vector3.Up, color, Vector2.One, scale)); treeVertices.Add(new VertexBillboard(v.Position, Vector3.Up, color, Vector2.UnitY, scale)); int[] baseIndices = new int[] { 0, 1, 2, 0, 2, 3 }; int offset = treeIndices.Count / 6 * 4; for (int i = 0; i < 6; i++) { treeIndices.Add(baseIndices[i] + offset); } }
private void Build(Terrain t, Climate climate) { float min = 5; float low = t.LowMark * 2; float max = t.HighMark / 2; float high = (max + low) / 2.0f; List <VertexBillboard> treeVertices = new List <VertexBillboard>(); List <int> treeIndices = new List <int>(); List <VertexBillboard> grassVertices = new List <VertexBillboard>(); List <int> grassIndices = new List <int>(); Random rand = new Random(); for (int i = 0; i < t.Vertices.Length; i++) { VertexTerrain v = t.Vertices[i]; // current vertex in the terrain mesh float height = v.Position.Y; float baseProbability = 0; // initially, there is no chance of adding a plant if (height > min && height < max) // check if the vertex is within allowed height range { if (v.TextureWeights.W >= 0.5f) { baseProbability = 0; } else if (climate == Climate.Dry) { if (height < low) { baseProbability = 0.6f - (height - max / 2) / (max / 2 - min); } else if (height > high) { baseProbability = 0.2f - (height - high) / (max - high); } else { baseProbability = 0.2f; } } else { if (height < low) { baseProbability = (height - min) / (low - min); // fewer plants toward shore } else if (height > high) { baseProbability = v.TextureWeights.Z - (height - high) / (max - high); // fewer plants near mountain peaks } else { baseProbability = v.TextureWeights.Z; // otherwise, the vertex is perfectly good for a plant } } } baseProbability *= density; // scale probability by density float treeProbability = baseProbability * treeDensity; double roll = rand.NextDouble(); // get a random number to check if the plant should be added if (baseProbability > roll) { if (treeProbability > roll) { //trees.Add(new TreeModel(treeModel, v.Position, rand.Next(175,250)/100.0f)); AddTree(v, treeVertices, treeIndices, rand, climate); } else { AddGrass(v, grassVertices, grassIndices, rand, climate); } } } // buffer the vegetation if (grassVertices.Count > 0) { vBufferGrass = new VertexBuffer(sim.GraphicsDevice, grassVertices.Count * VertexBillboard.SizeInBytes, BufferUsage.WriteOnly); vBufferGrass.SetData(grassVertices.ToArray()); iBufferGrass = new IndexBuffer(sim.GraphicsDevice, typeof(int), grassIndices.Count, BufferUsage.WriteOnly); iBufferGrass.SetData(grassIndices.ToArray()); } if (treeVertices.Count > 0) { vBufferTrees = new VertexBuffer(sim.GraphicsDevice, treeVertices.Count * VertexBillboard.SizeInBytes, BufferUsage.WriteOnly); vBufferTrees.SetData(treeVertices.ToArray()); iBufferTrees = new IndexBuffer(sim.GraphicsDevice, typeof(int), treeIndices.Count, BufferUsage.WriteOnly); iBufferTrees.SetData(treeIndices.ToArray()); } }
public TerrainTile(Vector2 position, VertexTerrain[] vertices, VertexBuffer buffer, BoundingBox boundingBox) { this.Vertices = vertices; this.Position = position; this.Buffer = buffer; this.BoundingBox = boundingBox; }
/// <summary> /// Calculate the normals of each vertices by getting the /// two sides of each vertex' triangle and crossing then. /// </summary> /// <param name="vertices">The vertices on which to calculate normals.</param> private void SetupNormals(VertexTerrain[] vertices) { for (int i = 0; i < indices.Length / 3; i++) { int index0 = indices[i * 3]; int index1 = indices[i * 3 + 1]; int index2 = indices[i * 3 + 2]; Vector3 side0 = vertices[index0].Position - vertices[index2].Position; Vector3 side1 = vertices[index0].Position - vertices[index1].Position; Vector3 normal = Vector3.Cross(side1, side0); vertices[index0].Normal += normal; vertices[index1].Normal += normal; vertices[index2].Normal += normal; } for (int i = 0; i < vertices.Length; i++) vertices[i].Normal = vertices[i].Normal.SafeNormalize(); }
/// <summary> /// Construct the vertices and the vertexbuffer. /// </summary> private void LoadVertices() { TileSize = Math.Min(Math.Min(this.Width, this.Height), TileSize); int widthInTiles = (int)Math.Ceiling((this.Width - 1) / (double)(TileSize)); int heightInTiles = (int)Math.Ceiling((this.Height - 1) / (double)(TileSize)); this.tiles = new TerrainTile[widthInTiles * heightInTiles]; Vector3 color = new Vector3(0xed/255.0f, 0xaa/255.0f, 0x09/255.0f); for (int ty = 0; ty < heightInTiles; ty++) { for (int tx = 0; tx < widthInTiles; tx++) { int width = TileSize + 1; int height = TileSize + 1; VertexTerrain[] vertices = new VertexTerrain[width * height]; Vector3 bbmax = Vector3.One * float.MinValue; Vector3 bbmin = Vector3.One * float.MaxValue; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { int rx = (tx * TileSize + x); int ry = (ty * TileSize + y); int ri = rx + ry * this.Width; int i = x + y * width; vertices[i].Position = new Vector3(rx, data[Math.Min(rx, this.Width - 1), Math.Min(ry, this.Height - 1)], ry); bbmax = Vector3.Max(bbmax, vertices[i].Position); bbmin = Vector3.Min(bbmin, vertices[i].Position); float weight = vertices[i].Position.Y; weight -= minheight; weight /= (maxheight - minheight); weight *= weight; vertices[i].Color = Vector3.Lerp(color, Vector3.One, weight); } } this.SetupNormals(vertices); VertexBuffer buffer = new VertexBuffer(GraphicsDevice, typeof(VertexTerrain), vertices.Length, BufferUsage.None); tiles[ty * widthInTiles + tx] = new TerrainTile(new Vector2(tx, ty), vertices, buffer, new BoundingBox(bbmin, bbmax)); } } }