//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkWynter.Stream { #region Using Statements using System; using System.Collections; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; #endregion /// /// Gpu-based Terrain normal processing class /// public class TerrainNormalStuff { private Viewport generateNormalsViewport; // Vertex Buffer private VertexDeclaration vertexDeclaration; // Vertex Declaration private VertexBuffer vertexBuffer; private VertexPositionTexture[] vertices; private RenderTarget2D renderTarget1; private DepthStencilBuffer depthBuff; /// /// Constructor /// /// Texture width /// Texture height public TerrainNormalStuff(int textureWidth, int textureHeight) { // Set up the Indexed viewport generateNormalsViewport.X = 0; generateNormalsViewport.Y = 0; generateNormalsViewport.Width = textureWidth; generateNormalsViewport.Height = textureHeight; generateNormalsViewport.MinDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MinDepth; generateNormalsViewport.MaxDepth = Statics_Stream.RenderSettings.graphics.GraphicsDevice.Viewport.MaxDepth; GraphicsDevice gd = Statics_Stream.RenderSettings.graphics.GraphicsDevice; // Create a 4 point vertex buffer vertices = new VertexPositionTexture[4]; vertexDeclaration = new VertexDeclaration(gd, VertexPositionTexture.VertexElements); vertexBuffer = new VertexBuffer(gd, VertexPositionTexture.SizeInBytes * 4, BufferUsage.None); // Create quad with width and height = 1 vertices[0] = new VertexPositionTexture(new Vector3(0.0f, 0.0f, 0.0f), new Vector2(0.0f, 1.0f)); vertices[1] = new VertexPositionTexture(new Vector3(1.0f, 0.0f, 0.0f), new Vector2(1.0f, 1.0f)); vertices[2] = new VertexPositionTexture(new Vector3(1.0f, 1.0f, 0.0f), new Vector2(1.0f, 0.0f)); vertices[3] = new VertexPositionTexture(new Vector3(0.0f, 1.0f, 0.0f), new Vector2(0.0f, 0.0f)); // Set the data vertexBuffer.SetData(vertices); } /// /// Generate the normal map from the height map /// /// Output normal map /// Input height map public void GenerateTerrainNormals(ref Texture2D normalMap, Texture2D heightMap) { GraphicsDevice gd = Statics_Stream.RenderSettings.graphics.GraphicsDevice; // Create the render target and the depth stencil buffer renderTarget1 = new RenderTarget2D(gd, heightMap.Width, heightMap.Height, 1, SurfaceFormat.Vector4, RenderTargetUsage.DiscardContents); depthBuff = new DepthStencilBuffer(gd, heightMap.Width, heightMap.Height, DepthFormat.Depth16); // Setup view and projection matrixes Matrix matrixProjection = Matrix.CreateOrthographic(generateNormalsViewport.Width, generateNormalsViewport.Height, 1, 5); Matrix matrixPosition = Matrix.CreateScale(generateNormalsViewport.Width, generateNormalsViewport.Height, 1) * Matrix.CreateTranslation(-generateNormalsViewport.Width / 2.0f, -generateNormalsViewport.Height / 2.0f, 0.0f); Matrix matrixView = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, Vector3.Up); // Set graphics related stuff gd.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionTexture.SizeInBytes); gd.SetRenderTarget(0, renderTarget1); DepthStencilBuffer old = gd.DepthStencilBuffer; gd.DepthStencilBuffer = depthBuff; gd.Clear(ClearOptions.Target, Color.White, 1.0f, 0); gd.Viewport = generateNormalsViewport; gd.VertexDeclaration = vertexDeclaration; gd.RenderState.DepthBufferEnable = false; // Set all the different shader parameter for normal generation ShaderParameters.TerrainNormalFX.ViewProj.SetValue(matrixView * matrixProjection); ShaderParameters.TerrainNormalFX.World.SetValue(matrixPosition); ShaderParameters.TerrainNormalFX.heightMapTexture.SetValue(heightMap); ShaderParameters.TerrainNormalFX.effect.CurrentTechnique = ShaderParameters.TerrainNormalFX.effect.Techniques["GenerateTerrainNormals"]; // Render our quad for normal generation ShaderParameters.TerrainNormalFX.effect.Begin(); foreach (EffectPass pass in ShaderParameters.TerrainNormalFX.effect.CurrentTechnique.Passes) { pass.Begin(); gd.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2); pass.End(); } ShaderParameters.TerrainNormalFX.effect.End(); // Reset to the screen render target and depth buffer gd.SetRenderTarget(0, null); gd.DepthStencilBuffer = old; // Retrieve the normal map from our render target normalMap = renderTarget1.GetTexture(); // Dispose of the rendertarget and the depthbuffer to free up memory renderTarget1.Dispose(); depthBuff.Dispose(); } } }