I also created my own shader for the terrain as I found that Riemers, although very good as it had great detail, slowed my engine a little. The shader I came up with, while not being as pretty gives a faster render, I will put that up here to.
So on to the code. What I will do is break it down into chunks again and then offer the whole class at the end. I am not going to go over the basic terrain code as this is all covered in Riemers tutorial, for this please go to his site and read though the tutorial to get a better understanding, saves me repeating his tutorial. Also there are some methods I have commented out as they are unfinished, for example I am working on a random map generator, this is not complete so has been removed, also there is the color map generator for the terrain, this I have left as it is completed, but it was more of a folly rather than for any real purpose, I have left it in as a matter of completeness.
Terrain Position
private Vector3 basePosition;
public new Vector3 Position
{
get { return basePosition; }
set { basePosition = value; }
}
This field and property were added so that I could have my terrain centered on the position rather than the position vector be the bottom left hand corner of the terrain mesh.
GetHeightAt
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;
}
This method basicaly returns the height value of the terrain at a given position. I used this for debugging my collision method using it to display the height of the terrain as I drove my camera over it.
Collision
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;
}
This method returns true if the object is colliding with the terrain and false if it is not, simple enough. The heightBuffer is there as your models position may well be taked from it's center and so you need to specify the distance from the center to the base of the model. I guess you could use the radius of the objects native BoundingSphere, I did not do this as this as just occured to me as I write this.
Here is an example of this in action, this code placed in the Update of your Game will stop your camera from going through the terrain and give it the impression of being solid.
// Terrain collision.
RCTerrain terrain = (RCTerrain)(((RCObjectNode)game.Scene.GetObject("terrain")).Object);
game.WriteText(game.Font, 10, 100, terrain.GetHeightAt(RCCameraManager.ActiveCamera.Position).ToString(), Color.White);
if (terrain.Collision(RCCameraManager.ActiveCamera.Position, 2.5f))
RCCameraManager.ActiveCamera.Position = new Vector3(RCCameraManager.ActiveCamera.Position.X, RCCameraManager.ActiveCamera.Position.Y + .2f, RCCameraManager.ActiveCamera.Position.Z);
PickTerrain
Before Mouse Clicks
After wafting the mouse, clicking left and right buttons
public void PickTerrain(GraphicsDevice device, Point mousecoords,bool Up)
{
RCCameras.RCCamera camera = RCCameras.RCCameraManager.ActiveCamera;
Vector3 nearSource = camera.Viewport.Unproject(new Vector3(mousecoords.X, mousecoords.Y, camera.Viewport.MinDepth), camera.Projection, camera.View, Matrix.Identity);
Vector3 farSource = camera.Viewport.Unproject(new Vector3(mousecoords.X, mousecoords.Y, camera.Viewport.MaxDepth), camera.Projection, camera.View, Matrix.Identity);
Vector3 direction = farSource - nearSource;
float zFactor = nearSource.Y / direction.Y;
Vector3 zeroWorldPoint = nearSource + direction * zFactor;
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;
if (x > 0)
myHeightData[x - 1, y] += val;
myHeightData[x, y] += val;
if (x < myWidth)
myHeightData[x + 1, y] += val;
if (x > 0 && y > 0)
myHeightData[x - 1, y - 1] += val;
if (y > 0)
myHeightData[x, y - 1] += val;
if (x < myWidth && y > 0)
myHeightData[x + 1, y - 1] += val;
if (x > 0 && y < myHeight)
myHeightData[x - 1, y + 1] += val;
if (y < myHeight)
myHeightData[x, y + 1] += val;
if (x < myWidth && y < myHeight)
myHeightData[x + 1, y + 1] += val;
break;
}
}
BuildTerrain(device);
}
This is basicaly my Picking code, but what I am doing here is checking to see if my ray intersects a vertex of the terrain. I do this by moving through each of the terrains verts and using their possition Vector3 build a bounding box around them to check if my ray intersects it, if it does then I do what I want to do, in this case raise or lower the trrain depending on which mouse button was clicked, a bit like POPULOUS, a very old game I used to love. What I need to add to this method is the check to see if the intersecting vertex is the nearest to the camera like in my scene object picking method. Oh well at least this gives you an idea of how it can be done.
Here is the complete class.
RCTerrain:
public class RCTerrain : RCObject, IRCRenderable, IRCLoadable
{
protected struct VertexMultitextured
{
public Vector3 Position;
public Vector3 Normal;
public Vector4 TextureCoordinate;
public Vector4 TexWeights;
public static int SizeInBytes = (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 ),
};
}
private VertexBuffer vb;
private IndexBuffer ib;
VertexMultitextured[] myVertices;
private int myHeight;
private int myWidth;
private float[,] myHeightData;
private string myHeightAsset;
private bool randomMap;
public bool GenerateMap
{
get { return randomMap; }
set { randomMap = value; }
}
Texture2D ColorMap;
private Vector3 basePosition;
public new Vector3 Position
{
get { return basePosition; }
set { basePosition = value; }
}
public int Height
{
get { return myHeight; }
set { myHeight = value; }
}
public int Width
{
get { return myWidth; }
set { myWidth = value; }
}
private string[] myAssets;
private Texture2D myHeightMap;
private Texture2D[] myTextures;
private Vector3 myLightPosition = new Vector3(0.5f, 0.5f, -1);
public Vector3 LightPosition
{
get { return myLightPosition; }
set { myLightPosition = value; }
}
public RCTerrain(string[] textureAssets,string heightAsset,string name):base(name)
{
myHeightAsset = heightAsset;
myAssets = new string[textureAssets.Length];
for(int ass=0;ass<textureAssets.Length;ass++)
myAssets[ass] = textureAssets[ass];
}
public void PickTerrain(GraphicsDevice device, Point mousecoords,bool Up)
{
RCCameras.RCCamera camera = RCCameras.RCCameraManager.ActiveCamera;
Vector3 nearSource = camera.Viewport.Unproject(new Vector3(mousecoords.X, mousecoords.Y, camera.Viewport.MinDepth), camera.Projection, camera.View, Matrix.Identity);
Vector3 farSource = camera.Viewport.Unproject(new Vector3(mousecoords.X, mousecoords.Y, camera.Viewport.MaxDepth), camera.Projection, camera.View, Matrix.Identity);
Vector3 direction = farSource - nearSource;
float zFactor = nearSource.Y / direction.Y;
Vector3 zeroWorldPoint = nearSource + direction * zFactor;
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;
if (x > 0)
myHeightData[x - 1, y] += val;
myHeightData[x, y] += val;
if (x < myWidth)
myHeightData[x + 1, y] += val;
if (x > 0 && y > 0)
myHeightData[x - 1, y - 1] += val;
if (y > 0)
myHeightData[x, y - 1] += val;
if (x < myWidth && y > 0)
myHeightData[x + 1, y - 1] += val;
if (x > 0 && y < myHeight)
myHeightData[x - 1, y + 1] += val;
if (y < myHeight)
myHeightData[x, y + 1] += val;
if (x < myWidth && y < myHeight)
myHeightData[x + 1, y + 1] += val;
break;
}
}
BuildTerrain(device);
}
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;
}
public void LoadGraphicsContent(GraphicsDevice myDevice, ContentManager myLoader)
{
// Textures
myTextures = new Texture2D[myAssets.Length];
for (int ass = 0; ass < myAssets.Length; ass++)
myTextures[ass] = myLoader.Load<Texture2D>(myAssets[ass]);
// Height Data
if (!randomMap)
{
if (myHeightAsset.IndexOf(".raw") == -1)
{
myHeightMap = myLoader.Load<Texture2D>(myHeightAsset);
LoadHeightData();
ColorMap = new Texture2D(myDevice, myWidth, myHeight, 1, ResourceUsage.None, SurfaceFormat.Color);
BuildColorMap();
}
else
LoadRawHeightData();
}
else
GenerateHeightMap();
// Update position
myPosition = new Vector3(basePosition.X - (myWidth / 2), basePosition.Y, basePosition.Z - (myHeight / 2));
//Build Terrain
BuildTerrain(myDevice);
}
private void BuildTerrain(GraphicsDevice myDevice)
{
// 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 = 1; x < myWidth - 1; x++)
{
for (int y = 1; y < myHeight - 1; y++)
{
Vector3 normX = new Vector3((myVertices[x - 1 + y * myWidth].Position.Y - myVertices[x + 1 + y * myWidth].Position.Y) / 2, 0, 1);
Vector3 normY = new Vector3(0, 1, (myVertices[x + (y - 1) * myWidth].Position.Y - myVertices[x + (y + 1) * myWidth].Position.Y) / 2);
myVertices[x + y * myWidth].Normal = normX + normY;
myVertices[x + y * myWidth].Normal.Normalize();
}
}
vb = new VertexBuffer(myDevice, VertexMultitextured.SizeInBytes * myWidth * myHeight, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
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(myDevice, typeof(short), (myWidth - 1) * (myHeight - 1) * 6, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic);
ib.SetData(terrainIndices);
}
private void GenerateHeightMap()
{
// Under Construction
}
private void LoadRawHeightData()
{
myHeightData = new float[myHeight, myWidth];
FileStream fs = new FileStream(myHeightAsset, FileMode.Open, FileAccess.Read);
BinaryReader r = new BinaryReader(fs);
for (int i = 0; i < myHeight; i++)
{
for (int y = 0; y < myWidth; y++)
{
int height = (int)(r.ReadByte() / 10);
myHeightData[y, myHeight - 1 - i] = height;
}
}
r.Close();
}
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];
}
for (int x = 0; x < myWidth; x++)
for (int y = 0; y < myHeight; y++)
myHeightData[x, y] = (myHeightData[x, y] - minimumHeight) / (maximumHeight - minimumHeight) * 30;
}
private void BuildColorMap()
{
Color[] colorMap = new Color[myWidth * myHeight];
Color[] sand = new Color[myTextures[0].Width * myTextures[0].Height];
Color[] grass = new Color[myTextures[1].Width * myTextures[1].Height];
Color[] stone = new Color[myTextures[2].Width * myTextures[2].Height];
Color[] snow = new Color[myTextures[3].Width * myTextures[3].Height];
myTextures[0].GetData(sand);
myTextures[1].GetData(grass);
myTextures[2].GetData(stone);
myTextures[3].GetData(snow);
int cnt = 0;
for (int x = 0; x < myWidth; x++)
{
for (int y = 0; y < myHeight; y++)
{
cnt++;
Color col = Color.Black;
float height = myHeightData[x, y];
if (height <= 5)
{
col = sand[sand.Length-1];
}
else
if (height > 5 && height <= 15)
{
col = grass[grass.Length-1];
}
else
if (height > 15 && height < 25)
{
col = stone[stone.Length-1];
}
else
{
col = snow[snow.Length-1];
}
colorMap[x + y] = col;
ColorMap.SetData(0, new Rectangle(x, y, 1, 1), colorMap, x+y, 1, SetDataOptions.Discard);
}
}
//ColorMap.Save("TerrainMap.jpg", ImageFileFormat.Jpg);
}
public void Render(GraphicsDevice myDevice)
{
Effect effect = RCShaderManager.GetShader(myShader).Effect;
if (effect.Parameters["LightPosition"] != null)
effect.Parameters["LightPosition"].SetValue(myLightPosition);
if (effect.Parameters["SandTexture"] != null)
effect.Parameters["SandTexture"].SetValue(myTextures[0]);
if (effect.Parameters["GrassTexture"] != null)
effect.Parameters["GrassTexture"].SetValue(myTextures[1]);
if (effect.Parameters["RockTexture"] != null)
effect.Parameters["RockTexture"].SetValue(myTextures[2]);
if (effect.Parameters["SnowTexture"] != null)
effect.Parameters["SnowTexture"].SetValue(myTextures[3]);
if (effect.Parameters["LayerMap0"] != null)
effect.Parameters["LayerMap0"].SetValue(myTextures[0]);
if (effect.Parameters["LayerMap1"] != null)
effect.Parameters["LayerMap1"].SetValue(myTextures[1]);
if (effect.Parameters["LayerMap2"] != null)
effect.Parameters["LayerMap2"].SetValue(myTextures[2]);
if (effect.Parameters["LayerMap3"] != null)
effect.Parameters["LayerMap3"].SetValue(myTextures[3]);
if (effect.Parameters["full"] != null)
effect.Parameters["full"].SetValue(ColorMap);
if (effect.Parameters["UseFullMap"] != null)
effect.Parameters["UseFullMap"].SetValue(false);
myDevice.Vertices[0].SetSource(vb, 0, VertexMultitextured.SizeInBytes);
myDevice.Indices = ib;
myDevice.VertexDeclaration = new VertexDeclaration(myDevice, VertexMultitextured.VertexElements);
myDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, myWidth * myHeight, 0, (myWidth - 1) * (myHeight - 1) * 2);
}
}
Almost forgot to post my shader:
//////////////////////////////////////////////////////////////////////////////
// //
// NemoKradTerrain.fx Terrain shader by C.Humphrey 02/05/2007 //
// //
// This shader is based on terrain shaders by Riemer and Frank Luna. //
// Riemer: http://www.riemers.net //
// Frank Luna: http://www.moon-labs.com //
// //
// http://randomchaos.co.uk //
// http://randomchaosuk.blogspot.com //
// //
//////////////////////////////////////////////////////////////////////////////
float4x4 wvp : WorldViewProjection;
float3 LightPosition : LightDirection;
texture LayerMap0;
texture LayerMap1;
texture LayerMap2;
texture LayerMap3;
texture full;
bool UseFullMap;
sampler Full = sampler_state
{
Texture = <full>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
sampler LayerMap0Sampler = sampler_state
{
Texture = <LayerMap0>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
sampler LayerMap1Sampler = sampler_state
{
Texture = <LayerMap1>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
sampler LayerMap2Sampler = sampler_state
{
Texture = <LayerMap2>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
sampler LayerMap3Sampler = sampler_state
{
Texture = <LayerMap3>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
struct OutputVS
{
float4 posH : POSITION0;
float shade : TEXCOORD0;
float4 tiledTexC : TEXCOORD1;
float4 TextureWeights : TEXCOORD2;
};
OutputVS Terrain_MultiTexVS(float4 posL : POSITION0,
float3 normalL : NORMAL0,
float4 tiledTexC : TEXCOORD0,
float4 TextureWeights : TEXCOORD1)
{
OutputVS outVS = (OutputVS)0;
outVS.posH = mul(posL, wvp);
outVS.shade = saturate(saturate(dot(normalL, normalize(LightPosition))));
if(UseFullMap)
outVS.tiledTexC = tiledTexC;
else
outVS.tiledTexC = tiledTexC * .6;
outVS.TextureWeights = TextureWeights;
return outVS;
}
float4 Terrain_MultiTexPS(float shade : TEXCOORD0,
float4 tiledTexC : TEXCOORD1,
float4 TextureWeights : TEXCOORD2) : COLOR
{
float3 c0 = tex2D(LayerMap0Sampler, tiledTexC);
float3 c1 = tex2D(LayerMap1Sampler, tiledTexC);
float3 c2 = tex2D(LayerMap2Sampler, tiledTexC);
float3 c3 = tex2D(LayerMap3Sampler, tiledTexC);
c0 *= TextureWeights.x;
c1 *= TextureWeights.y;
c2 *= TextureWeights.z;
c3 *= TextureWeights.w;
float3 final;
if(UseFullMap)
{
float3 ful = tex2D(Full, tiledTexC * .117);
final = ful;
}
else
final = (c0 + c1 + c2 + c3);
final *= shade;
return float4(final, 1.0f);
}
technique Terrain_MultiTex
{
pass P0
{
vertexShader = compile vs_2_0 Terrain_MultiTexVS();
pixelShader = compile ps_2_0 Terrain_MultiTexPS();
}
}
Well I guess my Water class is next, here is an image of it in action:
First some nice calm water, waves at an amplitude of .1
Now at amplitude 1
"lets go surfing now, everybody's learning how..."
Doesn't work for me :( Nothing is displayed, but FPS gets down to 6... :(
ReplyDeleteOK, this could be a few things. Bare in mind that my shader(s) use semantics so make sure you are loading the shader parameters correctly.
ReplyDeleteHow are you constructing the terrain object?
You will get a big FPS drop if you have a large map.
I'm passing all of the parameters correctly. I'm constructing it like this:
ReplyDeletestring[] textures = new string{and other params};
NTerrain terrain = new NTerrain(textures, "heightMap");
I'm sure I'm doing everything ok...
Are you using my shader or Riemers shader?
ReplyDeleteCan you show me the code snippet that is populating the shader parameters.
Your object construction looks OK.
You say you are getting nothing, so you can see no terrain at all, or is it all black?
I can see no terrain at all, and I'm using your shader.
ReplyDeleteI'm setting the wvp manually like this
if (effect.Parameters["wvp"] != null)
effect.Parameters["wvp"].SetValue(
Matrix.Multiply(Matrix.Multiply(
Matrix.CreateScale(1.0f) *
Matrix.CreateTranslation(Position),
NCameraManager.ActiveCamera.EyeMatrix),
NCameraManager.ActiveCamera.ProjectionMatrix));
OK, just tried it with you wvp settings and it runs fine.
ReplyDeleteCan you send me your code and I can step through it and see what the problem is. You could be drawing the terrain at position 0,0,0 in which case if your terrains height in the height map is above your camera you may not see the terrain as it is above your camera.
give me your e-mail, or add me to MSN
ReplyDeletenemtheem at hotmail dot com (for spam protection :P)
EclipsE,
ReplyDeleteThanks for the code. Turns out you didn't reference your shader correctly. Hope it is all working fine now :)