heightmap geometry normals

I can’t get my terrain to be properly lit, and my problem resides of course in the normals.

I generate the terrain with triangle strips, with the code:

for (int z = 0; z < tsize-1; z++)
	{
		glBegin(GL_TRIANGLE_STRIP);

		for (int x=0; x < tsize-1; x++)
		{
			v_height = hmap.GetValue(x,z);	
			scaledHeight = v_height * h_scale;

			glNormal3fv (normals[x*tsize+z]);	
			glVertex3f ((GLfloat) x,  scaledHeight, (GLfloat) z);

			v_height = hmap.GetValue(x,z+1);		
			scaledHeight = v_height * h_scale; 
			
			glNormal3fv (normals[(x*tsize)+z+1]);
			glVertex3f ((GLfloat)x, scaledHeight, (GLfloat)z+1);
		}
		glEnd();
	}
	

As you see, triangles are generated like this:

B\---D\---
| \  | \
|  \ |  \
|   \|   \
A----C---E-

Tris are ABC, CDE…etc.

This triangles of course are generating a terrain geometry… and I need to calculate normals for it.

The method which I think should work is:

  • For every vertex A choose neighbour vertices B and C that share the same triangle as A.
  • Take vectors B-A and C-A, do cross product (B-A)x(C-A)
  • Normalize cross product.
  • We have our normal for the vertex.

But of course this generates very sharp lighting, so for I need to average more vectors in case of vertices that share more than one triangle.

M\---N\---O\---P
| \  | \  | \  |
|  \ |   \|  \ |
I\--\J----k\--\L
| \  | \  | \  |
|  \ |   \|  \ |
E\--\F\---G---\H
| \  | \  | \  |
|  \ |  \ |  \ |
A----B----C----D

Well, let's go for a little pseudocode:

IF VTX=A
   N=NORM((E-A)x(B-A))

// this shares two triangles BEF and BFC
IF VTX=B 
   V1=(E-B)
   V2=(F-B)
   V3=(C-B)
   VP=(V1xV2+V2xV3)/2
   N=NORM(VP)

// a inner vertex like F shares triangles FIJ, FJG, BEF, BFC

and so on...

Should this work or can I use another methods for smooth lighting?

At last, should my normals be 1 at Y (height) or must be multiplied by the height-scale of my terrain vertices?

thank you!

Hi,

At first sight, I don’t see anything wrong with the suggested method. Note that this can be simplified:


(N-J)x(M-J) + 
(M-J)x(I-J) + 
(I-J)x(F-J) + 
(F-J)x(G-J) + 
(G-J)x(K-J) + 
(K-J)x(N-J)

=

NxM-NxJ-JxM+JxJ + 
MxI-MxJ-JxI+JxJ + 
IxF-IxJ-JxF+JxJ + 
FxG-FxJ-JxG+JxJ + 
GxK-GxJ-JxK+JxJ + 
KxN-KxJ-JxN+JxJ 

=

NxM-NxJ+MxJ + 
MxI-MxJ+IxJ + 
IxF-IxJ+FxJ + 
FxG-FxJ+GxJ + 
GxK-GxJ+KxJ + 
KxN-KxJ+NxJ

=

NxM + MxI + IxF + FxG + GxK + KxN

This works if all your triangles have approximately the same area. If they don’t (many peaks) it’s better to use:

normalized(N-J) x normalized(M-J)

instead of:

(N-J)x(M-J)

Your normals should always be normalized, so make sure that automatic normalization is enabled (or done manually in shader) or that your transformation matrices do not scale/skew your object.

Cheers,

N.

Thank you very much!!! Worksss!!! Looks very good and smooth.

Now I need to get some terrain LOD algorithm. What about clipmapping? It’s good and easy to implement?

My terrain is 1024x1024 pixels heightmap based (about 512x512 tris) to represent a 1.5km x 1.5km area.

I recently played with the isometric heightmaps, they may be a bit trickier to implement but provide better-looking results: ftp://ftp.cs.brown.edu/pub/techreports/05/cs05-14.pdf

For LOD I suggest you use geometrical mipmapping as described in this paper: ftp://ftp.cs.brown.edu/pub/techreports/05/cs05-14.pdf

Still, for your terrain you need no LOD. 512x512 tris are only 256k triangles, even older graphics card eat something like this for breakfest. Just load it into a static VBO and you should be fine.

I think for a 1.5km square area 512x512 tris seems to be a little constrained. What triangles per km scale are you using?

Now, just implementing VBOs…

Thanks!