Выбрать главу

 float fColor = –0.15f + (Height(pHeightMap, x, y ) / 256.0f);

 // Assign This Blue Shade To The Current Vertex

 glColor3f(0.0f, 0.0f, fColor );

}

This is the code that actually draws our landscape. X and Y will be used to loop through the height map data. x, y and z will be used to render the quads making up the landscape.

As always, we check to see if the height map (pHeightMap) contains data. If not, we return without doing anything.

void RenderHeightMap(BYTE pHeightMap[]) // This Renders The Height Map As Quads

{

 int X = 0, Y = 0; // Create Some Variables To Walk The Array With.

 int x, y, z; // Create Some Variables For Readability

 if (!pHeightMap) return; // Make Sure Our Height Data Is Valid

Since we can switch between lines and quads, we check our render state with the code below. If bRender = True, then we want to render polygons, otherwise we render lines.

 if (bRender) // What We Want To Render

  glBegin(GL_QUADS ); // Render Polygons

 else

  glBegin(GL_LINES); // Render Lines Instead

Next we actually need to draw the terrain from the height map. To do that, we just walk the array of height data and pluck out some heights to plot our points. If we could see this happening, it would draw the columns first (Y), then draw the rows. Notice that we have a STEP_SIZE. This determines how defined our height map is. The higher the STEP_SIZE, the more blocky the terrain looks, while the lower it gets, the more rounded (smooth) it becomes. If we set STEP_SIZE = 1 it would create a vertex for every pixel in the height map. I chose 16 as a decent size. Anything too much less gets to be insane and slow. Of course, you can increase the number when you get lighting in. Then vertex lighting would cover up the blocky shape. Instead of lighting, we just put a color value associated with every poly to simplify the tutorial. The higher the polygon, the brighter the color is.

 for (X = 0; X < MAP_SIZE; X += STEP_SIZE) for (Y = 0; Y < MAP_SIZE; Y += STEP_SIZE) {

  // Get The (X, Y, Z) Value For The Bottom Left Vertex

  x = X;

  y = Height(pHeightMap, X, Y );

  z = Y;

  // Set The Color Value Of The Current Vertex

  SetVertexColor(pHeightMap, x, z);

  glVertex3i(x, y, z); // Send This Vertex To OpenGL To Be Rendered

  // Get The (X, Y, Z) Value For The Top Left Vertex

  x = X;

  y = Height(pHeightMap, X, Y + STEP_SIZE );

  z = Y + STEP_SIZE ;

  // Set The Color Value Of The Current Vertex

  SetVertexColor(pHeightMap, x, z);

  glVertex3i(x, y, z); // Send This Vertex To OpenGL To Be Rendered

  // Get The (X, Y, Z) Value For The Top Right Vertex

  x = X + STEP_SIZE;

  y = Height(pHeightMap, X + STEP_SIZE, Y + STEP_SIZE );

  z = Y + STEP_SIZE ;

  // Set The Color Value Of The Current Vertex

  SetVertexColor(pHeightMap, x, z);

  glVertex3i(x, y, z); // Send This Vertex To OpenGL To Be Rendered

  // Get The (X, Y, Z) Value For The Bottom Right Vertex

  x = X + STEP_SIZE;

  y = Height(pHeightMap, X + STEP_SIZE, Y );

  z = Y;

  // Set The Color Value Of The Current Vertex

  SetVertexColor(pHeightMap, x, z);

  glVertex3i(x, y, z); // Send This Vertex To OpenGL To Be Rendered

 }

 glEnd();

After we are done, we set the color back to bright white with an alpha value of 1.0f. If there were other objects on the screen, we wouldn't want them showing up BLUE :)

 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // Reset The Color

}

For those of you who haven't used gluLookAt(), what it does is position your camera position, your view, and your up vector. Here we set the camera in a obscure position to get a good outside view of the terrain. In order to avoid using such high numbers, we would divide the terrain's vertices by a scale constant, like we do in glScalef() below.

The values of gluLookAt() are as follows: The first three numbers represent where the camera is positioned. So the first three values move the camera 212 units on the x-axis, 60 units on the y-axis and 194 units on the z-axis from our center point. The next 3 values represent where we want the camera to look. In this tutorial, you will notice while running the demo that we are looking a little to the left. We are also look down towards the landscape. 186 is to the left of 212 which gives us the look to the left, and 55 is lower than 60, which gives us the appearance that we are higher than the landscape looking at it with a slight tilt (seeing a bit of the top of it). The value of 171 is how far away from the camera the object is. The last three values tell OpenGL which direction represents up. Our mountains travel upwards on the y-axis, so we set the value on the y-axis to 1. The other two values are set at 0.

gluLookAt can be very intimidating when you first use it. After reading the rough explanation above you may still be confused. My best advise is to play around with the values. Change the camera position. If you were to change the y position of the camera to say 120, you would see more of the top of the landscape, because you would be looking all the way down to 55.

I'm not sure if this will help, but I'm going to break into one of my highly flamed real life "example" explanations :) Lets say you are 6 feet and a bit tall. Lets also assume your eyes are at the 6 foot mark (your eyes represent the camera — 6 foot is 6 units on the y-axis). Now if you were standing in front of a wall that was only 2 feet tall (2 units on the y-axis), you would be looking DOWN at the wall and would be able to see the top of the wall. If the wall was 8 feet tall, you would be looking UP at the wall and you would NOT see the top of the wall. The view would change depending on if you were looking up or down (if you were higher than or lower than the object you are looking at). Hope that makes a bit of sense!

int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing

{

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer

 glLoadIdentity(); // Reset The Matrix

 // Position View Up Vector

 gluLookAt(212, 60, 194, 186, 55, 171, 0, 1, 0); // This Determines The Camera's Position And View

This will scale down our terrain so it's a bit easier to view and not so big. We can change this scaleValue by using the UP and DOWN arrows on the keyboard. You will notice that we mupltiply the Y scaleValue by a HEIGHT_RATIO as well. This is so the terrain appears higher and gives it more definition.

 glScalef(scaleValue, scaleValue * HEIGHT_RATIO, scaleValue);

If we pass the g_HeightMap data into our RenderHeightMap() function it will render the terrain in Quads. If you are going to make any use of this function, it might be a good idea to put in an (X, Y) parameter to draw it at, or just use OpenGL's matrix operations (glTranslatef() glRotate(), etc) to position the land exactly where you want it.

 RenderHeightMap(g_HeightMap); // Render The Height Map

 return TRUE; // Keep Going

}

The KillGLWindow() code is the same as lesson 1.