| using System; |
| using System.Collections.Generic; |
| using System.Text; |
| using Microsoft.Xna.Framework; |
| using Microsoft.Xna.Framework.Content; |
| using Microsoft.Xna.Framework.Graphics; |
| |
| namespace UnderWorld |
| { |
| public class DynamicTerrain : DrawableGameComponent |
| { |
| protected struct VertexMultitextured |
| { |
| public Vector3 Position; |
| public Vector3 Normal; |
| public Vector4 TextureCoordinate; |
| public Vector4 TexWeights; |
| public Vector3 Tangent; |
| |
| public static int SizeInBytes = (3 + 3 + 3 + 4 + 4) * 4; |
| public static VertexElement[] VertexElements = new VertexElement[] |
| { |
| new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0 ), |
| new VertexElement( 0, sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0 ), |
| new VertexElement( 0, sizeof(float) * 6, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0 ), |
| new VertexElement( 0, sizeof(float) * 10, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 1 ), |
| new VertexElement( 0, sizeof(float) * 14, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Tangent, 0 ), |
| }; |
| } |
| |
| private VertexBuffer vb; |
| private IndexBuffer ib; |
| VertexMultitextured[] myVertices; |
| private int myHeight; |
| private int myWidth; |
| private float[,] myHeightData; |
| private string myHeightAsset; |
| |
| private Vector3 basePosition; |
| private Vector3 myPosition; |
| private Vector3 myScale; |
| private Quaternion myRotation; |
| |
| Effect shader; |
| |
| private string[] myColorAssets; |
| private string[] myBumpMapAssets; |
| private Texture2D myHeightMap; |
| private Texture2D[] myTextures; |
| private Texture2D[] bumpMaps; |
| |
| private Vector3 myLightPosition; |
| |
| public Vector3 LightPosition |
| { |
| get { return myLightPosition; } |
| set { myLightPosition = value; } |
| } |
| public Vector3 Position |
| { |
| get { return basePosition; } |
| set { basePosition = value; } |
| } |
| |
| ContentManager content; |
| |
| string myShader; |
| |
| public DynamicTerrain(Game game,string[] textureAssets, string[] bumpAssets, string heightAsset,string shaderAsset) : base(game) |
| { |
| content = new ContentManager(game.Services); |
| |
| myShader = shaderAsset; |
| myHeightAsset = heightAsset; |
| |
| myColorAssets = new string[textureAssets.Length]; |
| for (int ass = 0; ass < textureAssets.Length; ass++) |
| myColorAssets[ass] = textureAssets[ass]; |
| |
| myBumpMapAssets = new string[bumpAssets.Length]; |
| for (int ass = 0; ass < bumpAssets.Length; ass++) |
| myBumpMapAssets[ass] = bumpAssets[ass]; |
| |
| myPosition = new Vector3(0, 0, 0); |
| myScale = Vector3.One; |
| myRotation = new Quaternion(0, 0, 0, 1); |
| } |
| |
| public void PickTerrain(Point mousecoords, bool Up) |
| { |
| /** |
| Vector3 nearSource = Camera.myViewport.Unproject(new Vector3(mousecoords.X, mousecoords.Y, Camera.myViewport.MinDepth), Camera.myProjection, Camera.myView, Matrix.Identity); |
| Vector3 farSource = Camera.myViewport.Unproject(new Vector3(mousecoords.X, mousecoords.Y, Camera.myViewport.MaxDepth), Camera.myProjection, Camera.myView, Matrix.Identity); |
| Vector3 direction = farSource - nearSource; |
|
| Ray ray = new Ray(nearSource, direction); |
|
| for (int x = 0; x < myWidth; x++) |
| for (int y = 0; y < myHeight; y++) |
| { |
| BoundingBox tmp = new BoundingBox(myVertices[x + y * myWidth].Position + myPosition, (myVertices[x + y * myWidth].Position + myPosition) + new Vector3(1f, 1f, 1f)); |
|
| if (ray.Intersects(tmp) != null) |
| { |
| float val = 0; |
| if (Up) |
| val += .5f; |
| else |
| val -= .5f; |
|
| for (int xx = 0; xx < 5; xx++) |
| { |
| for (int yy = 0; yy < 5; yy++) |
| { |
| try |
| { |
| if (Up && myHeightData[x + xx, y + yy] < 30) |
| myHeightData[x + xx, y + yy] += .1f; |
| if (!Up && myHeightData[x + xx, y + yy] > 0) |
| myHeightData[x + xx, y + yy] -= .1f; |
| } |
| catch |
| { |
| // user clicked at edge of map... |
| } |
| } |
| } |
|
| break; |
| } |
| } |
| */ |
| BuildTerrain(); |
| } |
| |
| public bool Collision(Vector3 objPosition, float heightBuffer) |
| { |
| bool retVal = false; |
| int x, y, objHeight; |
| |
| y = (int)objPosition.X + (myWidth / 2); |
| x = (int)objPosition.Z + (myHeight / 2); |
| |
| objHeight = (int)(objPosition.Y - heightBuffer); |
| |
| if ((x >= 0 && y >= 0) && (x < myWidth && y < myHeight)) |
| { |
| if (objHeight < myPosition.Y + myHeightData[x, y]) |
| retVal = true; |
| } |
| return retVal; |
| } |
| |
| public Vector3 GetHeightAt(Vector3 objPosition) |
| { |
| Vector3 retVal = new Vector3(); |
| int x, y; |
| |
| y = (int)objPosition.X + (myWidth / 2); |
| x = (int)objPosition.Z + (myHeight / 2); |
| |
| if ((x >= 0 && y >= 0) && (x < myWidth && y < myHeight)) |
| retVal = new Vector3(x, y, myPosition.Y + myHeightData[x, y]); |
| |
| return retVal; |
| } |
| |
| protected override void LoadContent() |
| { |
| shader = content.Load<Effect>(myShader); |
| // Textures |
| myTextures = new Texture2D[myColorAssets.Length]; |
| for (int ass = 0; ass < myColorAssets.Length; ass++) |
| myTextures[ass] = content.Load<Texture2D>(myColorAssets[ass]); |
| |
| bumpMaps = new Texture2D[myBumpMapAssets.Length]; |
| for (int ass = 0; ass < myBumpMapAssets.Length; ass++) |
| bumpMaps[ass] = content.Load<Texture2D>(myBumpMapAssets[ass]); |
| |
| |
| // Height Data |
| myHeightMap = content.Load<Texture2D>(myHeightAsset); |
| LoadHeightData(); |
| |
| // Update position |
| myPosition = new Vector3(basePosition.X - (myWidth / 2), basePosition.Y, basePosition.Z - (myHeight / 2)); |
| |
| BuildTerrain(); |
| base.LoadContent(); |
| } |
| private void BuildTerrain() |
| { |
| // Vertices |
| myVertices = new VertexMultitextured[myWidth * myHeight]; |
| |
| for (int x = 0; x < myWidth; x++) |
| for (int y = 0; y < myHeight; y++) |
| { |
| myVertices[x + y * myWidth].Position = new Vector3(y, myHeightData[x, y], x); |
| myVertices[x + y * myWidth].Normal = new Vector3(0, 1, 0); |
| myVertices[x + y * myWidth].TextureCoordinate.X = (float)x / 30.0f; |
| myVertices[x + y * myWidth].TextureCoordinate.Y = (float)y / 30.0f; |
| |
| myVertices[x + y * myWidth].TexWeights.X = MathHelper.Clamp(1.0f - Math.Abs(myHeightData[x, y] - 0) / 8.0f, 0, 1); |
| myVertices[x + y * myWidth].TexWeights.Y = MathHelper.Clamp(1.0f - Math.Abs(myHeightData[x, y] - 12) / 6.0f, 0, 1); |
| myVertices[x + y * myWidth].TexWeights.Z = MathHelper.Clamp(1.0f - Math.Abs(myHeightData[x, y] - 20) / 6.0f, 0, 1); |
| myVertices[x + y * myWidth].TexWeights.W = MathHelper.Clamp(1.0f - Math.Abs(myHeightData[x, y] - 30) / 6.0f, 0, 1); |
| |
| float totalWeight = myVertices[x + y * myWidth].TexWeights.X; |
| totalWeight += myVertices[x + y * myWidth].TexWeights.Y; |
| totalWeight += myVertices[x + y * myWidth].TexWeights.Z; |
| totalWeight += myVertices[x + y * myWidth].TexWeights.W; |
| myVertices[x + y * myWidth].TexWeights.X /= totalWeight; |
| myVertices[x + y * myWidth].TexWeights.Y /= totalWeight; |
| myVertices[x + y * myWidth].TexWeights.Z /= totalWeight; |
| myVertices[x + y * myWidth].TexWeights.W /= totalWeight; |
| |
| } |
| |
| for (int x = 0; x < myWidth; x++) |
| { |
| for (int y = 0; y < myHeight; y++) |
| { |
| Vector3 normX = Vector3.One; |
| Vector3 normY = Vector3.One; |
| if (x != 0 && x < myWidth - 1) |
| normX = new Vector3((myVertices[x - 1 + y * myWidth].Position.Y - myVertices[x + 1 + y * myWidth].Position.Y) / 2, 0, 1); |
| else |
| if(x == 0) |
| normX = new Vector3((myVertices[x + y * myWidth].Position.Y - myVertices[x + 1 + y * myWidth].Position.Y) / 2, 0, 1); |
| else |
| normX = new Vector3((myVertices[x - 1 + y * myWidth].Position.Y - myVertices[x + y * myWidth].Position.Y) / 2, 0, 1); |
| |
| if(y != 0 && y < myHeight-1) |
| normY = new Vector3(0, 1, (myVertices[x + (y - 1) * myWidth].Position.Y - myVertices[x + (y + 1) * myWidth].Position.Y) / 2); |
| else |
| if(y == 0) |
| normY = new Vector3(0, 1, (myVertices[x + y * myWidth].Position.Y - myVertices[x + (y + 1) * myWidth].Position.Y) / 2); |
| else |
| normY = new Vector3(0, 1, (myVertices[x + (y - 1) * myWidth].Position.Y - myVertices[x + (y) * myWidth].Position.Y) / 2); |
| |
| myVertices[x + y * myWidth].Normal = normX + normY; |
| myVertices[x + y * myWidth].Normal.Normalize(); |
| |
| if (x != 0 && x < myWidth - 1) |
| myVertices[x + y * myWidth].Tangent = myVertices[x - 1 + y * myWidth].Position - myVertices[x + 1 + y * myWidth].Position; |
| else |
| if(x == 0) |
| myVertices[x + y * myWidth].Tangent = myVertices[x + y * myWidth].Position - myVertices[x + 1 + y * myWidth].Position; |
| else |
| myVertices[x + y * myWidth].Tangent = myVertices[x - 1 + y * myWidth].Position - myVertices[x + y * myWidth].Position; |
| } |
| } |
| |
| vb = new VertexBuffer(base.GraphicsDevice, VertexMultitextured.SizeInBytes * myWidth * myHeight, BufferUsage.WriteOnly); |
| vb.SetData(myVertices); |
| |
| //Index |
| short[] terrainIndices = new short[(myWidth - 1) * (myHeight - 1) * 6]; |
| for (short x = 0; x < myWidth - 1; x++) |
| { |
| for (short y = 0; y < myHeight - 1; y++) |
| { |
| terrainIndices[(x + y * (myWidth - 1)) * 6] = (short)((x + 1) + (y + 1) * myWidth); |
| terrainIndices[(x + y * (myWidth - 1)) * 6 + 1] = (short)((x + 1) + y * myWidth); |
| terrainIndices[(x + y * (myWidth - 1)) * 6 + 2] = (short)(x + y * myWidth); |
| |
| terrainIndices[(x + y * (myWidth - 1)) * 6 + 3] = (short)((x + 1) + (y + 1) * myWidth); |
| terrainIndices[(x + y * (myWidth - 1)) * 6 + 4] = (short)(x + y * myWidth); |
| terrainIndices[(x + y * (myWidth - 1)) * 6 + 5] = (short)(x + (y + 1) * myWidth); |
| } |
| } |
| |
| |
| ib = new IndexBuffer(base.GraphicsDevice, typeof(short), (myWidth - 1) * (myHeight - 1) * 6, BufferUsage.WriteOnly); |
| ib.SetData(terrainIndices); |
| } |
| private void LoadHeightData() |
| { |
| float minimumHeight = 255; |
| float maximumHeight = 0; |
| |
| myWidth = myHeightMap.Width; |
| myHeight = myHeightMap.Height; |
| |
| Color[] heightMapColors = new Color[myWidth * myHeight]; |
| myHeightMap.GetData(heightMapColors); |
| |
| myHeightData = new float[myWidth, myHeight]; |
| for (int x = 0; x < myWidth; x++) |
| for (int y = 0; y < myHeight; y++) |
| { |
| myHeightData[x, y] = heightMapColors[x + y * myWidth].R; |
| if (myHeightData[x, y] < minimumHeight) |
| minimumHeight = myHeightData[x, y]; |
| if (myHeightData[x, y] > maximumHeight) |
| maximumHeight = myHeightData[x, y]; |
| } |
| |
| float HeigntBar = 30; |
| for (int x = 0; x < myWidth; x++) |
| for (int y = 0; y < myHeight; y++) |
| { |
| myHeightData[x, y] = (myHeightData[x, y]) / (maximumHeight - minimumHeight) * HeigntBar; |
| //myHeightData[x, y] = 15; |
| } |
| |
| } |
| |
| |
| public override void Draw(GameTime gameTime) |
| { |
| Matrix World = Matrix.CreateScale(myScale) * |
| Matrix.CreateFromQuaternion(myRotation) * |
| Matrix.CreateTranslation(myPosition); |
| |
| //shader.Parameters["wvp"].SetValue(World * Camera.myView * Camera.myProjection); |
| shader.Parameters["wvp"].SetValue(World * ChaseCamera.ActiveCamera.View * ChaseCamera.ActiveCamera.Projection); |
| shader.Parameters["world"].SetValue(World); |
| //shader.Parameters["EyePosition"].SetValue(Camera.myPosition); |
| shader.Parameters["EyePosition"].SetValue(ChaseCamera.ActiveCamera.Position); |
| |
| shader.Parameters["LightPosition"].SetValue(myLightPosition); |
| |
| shader.Parameters["LayerMap0"].SetValue(myTextures[0]); |
| shader.Parameters["LayerMap1"].SetValue(myTextures[1]); |
| shader.Parameters["LayerMap2"].SetValue(myTextures[2]); |
| shader.Parameters["LayerMap3"].SetValue(myTextures[3]); |
| |
| shader.Parameters["tileSizeMod"].SetValue(1.75f); |
| |
| shader.Parameters["BumpMap0"].SetValue(bumpMaps[0]); |
| shader.Parameters["BumpMap1"].SetValue(bumpMaps[1]); |
| shader.Parameters["BumpMap2"].SetValue(bumpMaps[2]); |
| shader.Parameters["BumpMap3"].SetValue(bumpMaps[3]); |
| |
| // Fog settings. |
| shader.Parameters["fog"].SetValue(GlobalShaderFog.FogOn); |
| shader.Parameters["fogNear"].SetValue(GlobalShaderFog.FogNear); |
| shader.Parameters["fogFar"].SetValue(GlobalShaderFog.FogFar); |
| shader.Parameters["fogAltitudeScale"].SetValue(GlobalShaderFog.FogAltitudeScale); |
| shader.Parameters["fogThinning"].SetValue(GlobalShaderFog.FogThining); |
| shader.Parameters["fogColor"].SetValue(GlobalShaderFog.FogColor.ToVector4()); |
| |
| shader.Begin(SaveStateMode.SaveState); |
| for (int pass = 0; pass < shader.CurrentTechnique.Passes.Count; pass++) |
| { |
| shader.CurrentTechnique.Passes[pass].Begin(); |
| base.GraphicsDevice.Vertices[0].SetSource(vb, 0, VertexMultitextured.SizeInBytes); |
| base.GraphicsDevice.Indices = ib; |
| base.GraphicsDevice.VertexDeclaration = new VertexDeclaration(base.GraphicsDevice, VertexMultitextured.VertexElements); |
| base.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, myWidth * myHeight, 0, (myWidth - 1) * (myHeight - 1) * 2); |
| shader.CurrentTechnique.Passes[pass].End(); |
| } |
| shader.End(); |
| |
| } |
| } |
| } |
| |