#region File Description //----------------------------------------------------------------------------- // TerrainProcessor.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System.IO; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Content.Pipeline.Graphics; using Microsoft.Xna.Framework.Content.Pipeline.Processors; #endregion namespace GeneratedGeometryPipeline { /// /// Custom content processor for creating terrain meshes. Given an /// input heightfield texture, this processor uses the MeshBuilder /// class to programatically generate terrain geometry. /// [ContentProcessor] public class TerrainProcessor : ContentProcessor { const float terrainScale = 4; const float terrainBumpiness = 64; const float texCoordScale = 0.1f; const string terrainTexture = "rocks.bmp"; /// /// Generates a terrain mesh from an input heightfield texture. /// public override ModelContent Process(Texture2DContent input, ContentProcessorContext context) { MeshBuilder builder = MeshBuilder.StartMesh("terrain"); // Convert the input texture to float format, for ease of processing. input.ConvertBitmapType(typeof(PixelBitmapContent)); PixelBitmapContent heightfield; heightfield = (PixelBitmapContent)input.Mipmaps[0]; // Create the terrain vertices. for (int y = 0; y < heightfield.Height; y++) { for (int x = 0; x < heightfield.Width; x++) { Vector3 position; position.X = (x - heightfield.Width / 2) * terrainScale; position.Z = (y - heightfield.Height / 2) * terrainScale; position.Y = (heightfield.GetPixel(x, y) - 1) * terrainBumpiness; builder.CreatePosition(position); } } // Create a material, and point it at our terrain texture. BasicMaterialContent material = new BasicMaterialContent(); string directory = Path.GetDirectoryName(input.Identity.SourceFilename); string texture = Path.Combine(directory, terrainTexture); material.Texture = new ExternalReference(texture); builder.SetMaterial(material); // Create a vertex channel for holding texture coordinates. int texCoordId = builder.CreateVertexChannel( VertexChannelNames.TextureCoordinate(0)); // Create the individual triangles that make up our terrain. for (int y = 0; y < heightfield.Height - 1; y++) { for (int x = 0; x < heightfield.Width - 1; x++) { AddVertex(builder, texCoordId, heightfield.Width, x, y); AddVertex(builder, texCoordId, heightfield.Width, x + 1, y); AddVertex(builder, texCoordId, heightfield.Width, x + 1, y + 1); AddVertex(builder, texCoordId, heightfield.Width, x, y); AddVertex(builder, texCoordId, heightfield.Width, x + 1, y + 1); AddVertex(builder, texCoordId, heightfield.Width, x, y + 1); } } // Chain to the ModelProcessor so it can convert the mesh we just generated. MeshContent terrainMesh = builder.FinishMesh(); return context.Convert(terrainMesh, "ModelProcessor"); } /// /// Helper for adding a new triangle vertex to a MeshBuilder, /// along with an associated texture coordinate value. /// static void AddVertex(MeshBuilder builder, int texCoordId, int w, int x, int y) { builder.SetVertexChannelData(texCoordId, new Vector2(x, y) * texCoordScale); builder.AddTriangleVertex(x + y * w); } } }