
You are to create a terrain in XNA using a heightmap. You will find this site very useful.
The terrain is created by using a regular grid of points laid on the x-z plane. The x & z coordinates of this grid follow a regular pattern like the vertices of a chess board. The y-coord from each point is taken from a heighmap. The heighmap is an image file, each pixel in the image represents one of the points on our grid. The height of the point (y-coord) is represented by the colour of the pixel. Below is a height map of one of the Hawaiian Islands. The bright areas represent high ground.

The height map is loaded as a 2DTexture and the pixel data can be easily read.
The following code may be useful. It copies the data from the texture to an array which can then be used to create the points for the terrain.
size = heightmap.Width; // assume a square heightmap height = new float[size, size];// array of height values // get the colour data from the heightmap Color[] tmpheight = new Color[size*size]; heightmap.GetData(tmpheight); for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { height[i, j] = (float)(tmpheight[i * size + j].R); // only interested in the red channel // convert LIST of datapoints into an ARRAY of datapoints } }
The next bit of code will create an array of vertex list representing the triangles of the surface. The function PlaneVertex return a VertexPositionNormalTexture object representing a point on the grid. (you will need to write this yourself).
// next create a triangle list for the terrain
numTri = (size-1) * (size-1) * 2;
numVert = numTri * 3;
planeVertices =new VertexPositionNormalTexture[numVert];
int vert_num=0;
for(i=0;i<size-1;i++){
for(j=0;j<size-1;j++){
planeVertices[vert_num++] = PlaneVertex(i, j, size);
planeVertices[vert_num++] = PlaneVertex(i+1, j , size);
planeVertices[vert_num++] = PlaneVertex(i , j+1, size);
planeVertices[vert_num++] = PlaneVertex(i+1, j+1, size);
planeVertices[vert_num++] = PlaneVertex(i, j+1, size);
planeVertices[vert_num++] = PlaneVertex(i+1, j, size);
}
}
You should be able to render a terrain before you move onto the next phase.
In order for this terrain to be correctly rendered with lighting, each vertex needs a normal. A normal for a vertex is found by averaging the normals for the neighbouring triangles,. In the following code, the vectors n,s,e & w are vectors to a points neighbouring points (north, south east & west). Vectors sw,nw,se & nw are the normals for the neighbouring triangles. We then just get the average of these to calc the normal for the current point.
sw=Vector3.Cross(s,w);
nw=Vector3.Cross(w,n);
ne=Vector3.Cross(n,e);
se=Vector3.Cross(e,s);
sw.Normalize();
nw.Normalize();
se.Normalize();
ne.Normalize();
normals[i,j]=(sw+se+nw+ne)/4.0f; // average all 4 normals to get normal for this position
normals[i, j].Normalize();
To turn on lighting with a basic effect;
effect.EnableDefaultLighting();
To add realisim we can add a texture to the terrain. We need to load a texture as a 2DTexture object (this will usually be a different texture to the height map). In this case I have created a texture which will show the zero height areas as blue (sea), lowlying areas as yellow (beach), and mountain tops as white (snow). This texture need to be correctly aligned in order to work. (The texture was created from the original heightmap + some simple photoshop manipulation)

This involves giving each point a texture coordinate and setting the texture for the BasicEffect. To apply a texture;
texture = content.Load(@"Content\IslandTexture"); terrainEffect.Texture = texture; terrainEffect.TextureEnabled = true; terrainEffect.EnableDefaultLighting();