Calculating Vertex-Normals [Solved]

Started by
40 comments, last by fredrik90 18 years, 5 months ago
I tried your code out, but all I get is a checkerboard-style-terrain. I suppose either the i&1 vertex or the other one is not working. Those that are not working seem to be stretched quite randomly or something.
Advertisement
Ah, the modulus isn't that a good idea, I see. It does not wrap accordingly. Altough you're right that in all cases _both_ tris must be renderd. What's about this way:
for(int j=0;j<SIZE-1;++j) {   for(int i=0;i<SIZE-1;++i) {      int base = j*SIZE+i;      glNormal3f ( normals[base].x, normals[base].y, normals[base].z );      glTexCoord2f ( 0.0f, 0.0f );      glVertex3f ( trn[base].x, trn[base].y, trn[base].z );      glVertex3f ( trn[base+1].x, trn[base+1].y, trn[base+1].z );      glVertex3f ( trn[base+SIZE].x, trn[base+SIZE].y, trn[base+SIZE].z );      glVertex3f ( trn[base+1].x, trn[base+1].y, trn[base+1].z );      glVertex3f ( trn[base+SIZE+1].x, trn[base+SIZE+1].y, trn[base+SIZE+1].z );      glVertex3f ( trn[base+SIZE].x, trn[base+SIZE].y, trn[base+SIZE].z );   }}


Sorry, but my "pen & paper" based computer has made an error ;-) Some more iterations, and we'll get it...

EDIT: Notice please that this still renders the tris as a checkerboard. Does you compute the normals another way? If so, the index computation must be adapted... Hmm, I have to look into your snippets above again...
I could not found how you use the indices to compute the normals. However, your very first post shows a terrain rendered using pairs of two opposite tris, and so _should_ my suggested routine do. As long as you mention nothing other, I assume furthurmore that your terrain (and normals) are still defined this way...
Wow, it works fine! Finally!

The only thing left to do now is change it so that it won't create a new polygon pair for every loop iteration, but to consider STEP_SIZE.

Right now, it creates a ton of polygons (every unit 1), that make my fps drop to 1 every 10 seconds. :)
Not yet. There is more to do! the normals must be pushed for _all_ vertices:
for(int j=0;j<SIZE-1;++j) {   for(int i=0;i<SIZE-1;++i) {      int base = j*SIZE+i;      glNormal3f ( normals[base].x, normals[base].y, normals[base].z );      glVertex3f ( trn[base].x, trn[base].y, trn[base].z );      glNormal3f ( normals[base+1].x, normals[base+1].y, normals[base+1].z );      glVertex3f ( trn[base+1].x, trn[base+1].y, trn[base+1].z );      glNormal3f ( normals[base+SIZE].x, normals[base+SIZE].y, normals[base+SIZE].z );      glVertex3f ( trn[base+SIZE].x, trn[base+SIZE].y, trn[base+SIZE].z );      glNormal3f ( normals[base+1].x, normals[base+1].y, normals[base+1].z );      glVertex3f ( trn[base+1].x, trn[base+1].y, trn[base+1].z );      glNormal3f ( normals[base+SIZE+1].x, normals[base+SIZE+1].y, normals[base+SIZE+1].z );      glVertex3f ( trn[base+SIZE+1].x, trn[base+SIZE+1].y, trn[base+SIZE+1].z );      glNormal3f ( normals[base+SIZE].x, normals[base+SIZE].y, normals[base+SIZE].z );      glVertex3f ( trn[base+SIZE].x, trn[base+SIZE].y, trn[base+SIZE].z );   }}


The first optimization I recommend (if you're interested) is to use tri-strips. If I remember right, it has to work this way:
for(int j=0;j<SIZE-1;++j) {   glBegin(GL_TRIANGLE_STRIP);   for(int i=0;i<SIZE-1;++i) {      int base = j*SIZE+i;      glNormal3f ( normals[base].x, normals[base].y, normals[base].z );      glVertex3f ( trn[base].x, trn[base].y, trn[base].z );      glNormal3f ( normals[base+SIZE].x, normals[base+SIZE].y, normals[base+SIZE].z );      glVertex3f ( trn[base+SIZE].x, trn[base+SIZE].y, trn[base+SIZE].z );   }   glEnd();}

(The glBegin(GL_TRIANGLES) and glEnd() around this must be removed, of course!)

EDIT: Moved the initialize 2 vertices into the loop.

[Edited by - haegarr on November 3, 2005 12:07:19 PM]
Another relative simple optimization is to use glVertex3fv and glNormal3fv, so that something like this is possible:
for(int j=0;j<SIZE-1;++j) {   glBegin(GL_TRIANGLE_STRIP);   for(int i=0;i<SIZE-1;++i) {      int base = j*SIZE+i;      glNormal3fv ( &normals[base] );      glVertex3fv ( &trn[base] );      glNormal3fv ( &normals[base+SIZE] );      glVertex3fv ( &trn[base+SIZE] );   }   glEnd();}

This way requires a suitable definition of the normals and trn, of course. If normals and trn does have more than the 3 members x,y,z then you may use &normals[base].x instead of &normals[base] (and so on).

EDIT: Moved the initializing two vertices into the loop!

[Edited by - haegarr on November 3, 2005 12:15:05 PM]
Allright, I am using your triangle strip code from before and it appears to be fine.

Look at this screenshot, the terrain looks good (except this "terrace" effect and a strange dark line), and when moving the camera/lights in real-time, everything looks nicely shaded!

I've two comments on this:

(1) The rendering code I suggested assumes that the normals of the two opposite tri of a quad are stored subsequently: normal of upper left tri of quad 1, followed by normal of lower right tri of quad 1, followed by normal of upper left tri of quad 2, ... If it isn't, then wrong normals are used. You may take into account to post your current normals computation routine if you are not sure.

(2) What happens to the "terraces" if you zoom in, or else if you move the camera closer to the terrain? It may be an alias artifact due to a too great count of tris for the given view. If so, then the terraces will change and later disappear if the camera comes closer to the terrain.

Well, a dark line ... interesting. At the moment I have no idea what the reason for that line may be.
Thanks for the reply!

(1) Hm. I'll have to change the normal order than. I'll look into that!

(2) The "terrace" effect stays there. See this close-up screenshot of the terrain edge:

That is definitely no alias but a geometrical problem. If the original height map is smooth (say it doesn't already show this terraces, and I assume so) then again it looks like an indexing thing.

First, I've edited the routines using tri-strips in the past. In detail, I've moved the pushing of the first two vertices into the inner loop. Along this action the index of the inner loop is edited to start from 0 (formerly it started from 1). Please check this. From the screen shot I mean to notice that the steps are in one of the both x z directions only, while the other direction is smooth?

If the issue above is verified and the artifact still occurs, then it would be interesting to know if the artifact also occurs in the previous solution that uses the particular tris instead of the tri-strips.

This topic is closed to new replies.

Advertisement