Using A Height Map

I’m still very new to opengl and had a question on using a height map. This is for a school asignment so I’d like to have some assistance learning rather than just getting an answer. This is an excerpt from the assignment.

                                                                               The height values are

given by height(i, j) = 15.0 ∗ sin(10πi/256.0) ∗ sin(10πj/256.0). The 3D coordinates of points on
the terrain are given by (i, j, height(i, j)).
Render the terrain surface using triangle strips. Set the color of each vertex to (0.1∗height[i][j], 1.0, 0.1∗
height[i][j]). Compute the unit normal vector for each vertex, p, by using the cross product. If
p = (i, j, height(i, j)) then let a = (i + 1, j, height(i + 1, j)) and b = (i, j + 1, height(i, j + 1)).

Construct the vector v = a − p and w = b − p and n = v × w. The unit normal is given by N = n/||n||

This is what I’ve come up with so far:


glBegin(GL_TRIANGLE_STRIP);
int i,j;
for(i=0; i < 256; i++)
{
     for(j=0; j < 256; j++)
     {        			       			
     glNormal3f(0, 0, 1);
     glColor3f(0.1*15 * sin((10*PI*(i+1))/256.0) * sin((10*PI*j)/256.0), 1.0, 0.1*15 * sin((10*PI*(i+1))/256.0) * sin((10*PI*j)/256.0));
     glVertex3f(i+1, j, 15 * sin((10*PI*(i+1))/256.0) * sin((10*PI*j)/256.0));        			
     glColor3f(0.1*15 * sin((10*PI*i)/256.0) * sin((10*PI*(j+1))/256.0), 1.0, 0.1*15 * sin((10*PI*i)/256.0) * sin((10*PI*(j+1))/256.0));
     glVertex3f(i, j+1, 15 * sin((10*PI*i)/256.0) * sin((10*PI*(j+1))/256.0));
        			
     glColor3f(0.1*15 * sin((10*PI*i)/256.0) * sin((10*PI*j)/256.0), 1.0, 0.1*15 * sin((10*PI*i)/256.0) * sin((10*PI*j)/256.0));
     glVertex3f(i, j, 15 * sin((10*PI*i)/256.0) * sin((10*PI*j)/256.0));        				
     glColor3f(0.1*15 * sin((10*PI*(i+1))/256.0) * sin((10*PI*(j+1))/256.0), 1.0, 0.1*15 * sin((10*PI*(i+1))/256.0) * sin((10*PI*(j+1))/256.0));
     glVertex3f(i+1, j+1, 15 * sin((10*PI*(i+1))/256.0) * sin((10*PI*(j+1))/256.0));
        			
    }
}
glEnd();

I get a kind of nice image on the screen, but I don’t think I’m doing it right. And I’m not really sure on normalization. Any pointers in the right direction would be greatly appreciated.

can you provide the image to take a look?

I’ve noticed a few things:

  1. You use one triangle strip for entire heightmap, but you should be using one per row (or column).
  2. you specify 4 vertices in each step, while you shold specify two (left and right edge of strip) - that’s how triangle strip works.

If at some point you will want your program to run faster, then consider running this loop once and instead of calling glVertex etc., store all coordinates in arrays, then use OpenGL’s vertex array to draw it.

it might be a bit confusing that “height” is used in 2 ways:


float height(float i, float j)
{
  return 15.0 &#8727; sin(10&#960;i/256.0) &#8727; sin(10&#960;j/256.0);
}

and 

float[][] height;

In order to solve the assignment, you should do 2 things:

First:
Ignore that you’re supposed to output a triangle strip for now. Get correct results with GL_POINTS and worry about the triangle strip later.

Second:
precalculate all data at program initialization time. There is no need to solve height(i,j) a dozen times for each Vertex every frame. Find the solution once and store it for later use.

You will have to create the array “float[][] height” as a minimum. Better would be something like:


struct C3N3V3_Vertex
{
  Vector3f Color;
  Vector3f Normal;
  Vector3f Position;
}

// create an array from it and initialize it afterwards etc.

C3N3V3_Vertex[][] MyVertices;

You will to have to run 2 passes through the array: first pass to determine Position and Color, and in a second pass the Normal (because you need to know about the neighbouring Vertices to obtain it).

Edit: Not sure if this is obvious, but whenever you were previously using height(i,j) use MyVertices[i,j].Position.Z instead, after the field is filled from the first pass.

I’m still a little confused as to what values I should be filling float[][] height; with.

and also if a = (i + 1, j, height(i + 1, j)) and b = (i, j + 1, height(i, j + 1)) are those the 2 vertices I should using for my triangle strip?

No. These two are on the opposite corners of a square, wchich is wrong.

It depends on your loop. For example:


for (x = 0; x < maxX; x++)
{
 glBegin(GL_TRIANGLE_STRIP);
 for (y = 0; y <= maxY; y++)
 {
  glVertex3f(x, y, height[x][y])
  glVertex3f(x+1, y, height[x+1][y])
 }
 glEnd();
}

So, first we draw a strip between columns x and x+1, then we draw a strip between columns x+1 and x+2, and so on.

|/||/||/||/||/| - 1st strip
|/||/||/||/||/| - 2nd strip
|/||/||/||/||/| - 3rd strip
|/||/||/||/||/| - 4th strip
|/||/||/||/||/| - 5th strip
|/||/||/||/||/| - 6th strip
|/||/||/||/||/| - 7th strip
7 rows - 10 triangles a row - this mamkes up your heightmap.
you read a heightmap (8bit assumed) and take the 0 - 255 value. x and z advance while reading the heightmap but the height is taken from the heightmap channel.

in your code above you use one triangle strip for the whole terrain. instead you need more draw calls. i.e 7 here.
a screenshot would really help because you say you get a nice picture already.