Surface normals, really need help! :( Video shows!

Ok, ive ben trying for ages now to get this working but cant! And its driving me crazy!

Ok, i follow this to make my terrain, its simple and so far works well:

http://www.codeproject.com/KB/openGL/OPENGLTG.aspx

SDo ive done away with the height map and amde it so i change each height value using my mouse.

So, i thought i would have a go at calculating either face or vertex normals for the terrain.

And i am YET to get it working, even though its like at most 10 lines of extra code!

Ok, its simple, i have an array of X,Y,Z values and nromal values and i am updating each verts height (y) and normal as i alter them using the mouse.

But ignoring that, this is where i currently stand with it:

Using the code below, when i click on my terrain to alter the height or the Y value in the array, the correct face changes its normal to the newly calculated one, but the caluclate done seems to be always 0,0,0, so it changes the new vertex to just dark color!

Heres the normal calulation, its in lua but obviously easy to understand and see any mistakes.

function CalculateTerrainNormals(i,j)  --i & j is the vert in the array X & Z where the mouse marker is.

			vec1 = {x[i][j],y[i][j],z[i][j]}         --Vector 1  }
			vec2 = {x[i+1][j],y[i][j],z[i][j]} 	 --Vector 2  }--These make the triangle face
			vec3 = {x[i][j],y[i][j],z[i][j+1]}       --Vector 3  }

			--So if the i & j are 3 & 2.
			--vec1 = 3,Y,2
			--vec2 = 4,Y,2
			--vec3 = 3,Y,3

			--    3,2 ------------ 4,2
			--       |         /
			--       |      /
			--       |   /
			--   3,3 |/

			Uvec = {vec2[1] - vec1[1],vec2[2]-vec1[2],vec2[3]-vec1[3] }    -- Could be simpler doing
			Vvec = {vec3[1] - vec1[1],vec3[2]-vec1[2],vec3[3]-vec1[3] }    -- vec2 - vec1, done this way for testing!!!
			
			normalvec[1] = Uvec[2]*Vvec[3] - Uvec[3]*Vvec[2]
			normalvec[2] = Uvec[3]*Vvec[1] - Uvec[1]*Vvec[3]
			normalvec[3] = Uvec[1]*Vvec[2] - Uvec[2]*Vvec[1]

			
			normal[i][j] = {normalvec[1],normalvec[2],normalvec[3]}
			normal[i+1][j] = {normalvec[1],normalvec[2],normalvec[3]}
			normal[i][j+1] = {normalvec[1],normalvec[2],normalvec[3]}

			--in my draw loop is simple call glnormal(normal[i][j])
            
			--Re-Create the terrain from the array, which now has our new normals in.
			GenTerrain(hm,terrain_texture,terrain_size)

end 

Hope you can help.

<object width=“425” height=“350”> <param name=“movie” value=“- YouTube”></param> <param name=“wmode” value=“transparent”></param> <embed src=“- YouTube” type=“application/x-shockwave-flash” wmode=“transparent” width=“425” height=“350”> </embed></object>
Thanks
Andy

Well, those first three lines definitely aren’t helping you. vec1, vec2 and vec3 are all positions on your triangle. Why are you saying in these equations that they all have the same y for a height value?

vec1 looks correct. For vec2, they should all access the *[i+1][j]. For vec3, they should all acess the *[i][j+1].

If they all have the same y values, that’s why your normal calculation goes to zero when you subtract and your final normal is zero when you multiply.

Hi, cheers for that. Definatly now moving in better direction.

I think i had looked at the code for too long. :slight_smile:

Anyways, when i changed that, it didnt make a difference, so i made some test vars to monitor the normals of vert 0,0,0 as a changed it and all the values go negative?

And so if i change theses:


			normal[i][j] = {-normalvec[1],-normalvec[2],-normalvec[3]}
			normal[i+1][j] = {-normalvec[1],-normalvec[2],-normalvec[3]}
			normal[i][j+1] = {-normalvec[1],-normalvec[2],-normalvec[3]} 

To all negative (turning them back to positive) i get better results, but not 100%?

I dont understand why the normals are all coming out negative? There has to be something still being calculated wrong?

Thanks
Andy

Because the UxV = -VxU and the cross product depends on the orientation of U and V (counterclockwise for “positive” normal, well I hope you know the maths to understand what I mean).
What is missing from your code is a normalization of the new normal. cross products are not always unit length vectors!
Also I don’t see why vectors [i+1][j] and [i][j+1] have to have the same normal as the [i][j] vector. Normally, no pun intended, you must call CalculateTerrainNormals for all vectors affected by your brush, plus for vectors immediately surrounding the affected ones. Plus I don’t like this 3-point method. I believe it’s not a good estimation of mean normal value. What I would use is a normalized sum of 8 cross products calculated from the 8 neighbors of the vector.
Just my 2 cents!

I think you need to understand what each iteration of this loop is doing. Like before, each time you go through the loop you are calculating a normal for [i][j] using the [i+1][j] and [i][j+1]. Similarly as Y-tension mentioned, you are trying to set three normals at the end. A particular run through the loop is solving for [i][j]. Don’t worry about the others because the loop will come to those.

Normalize normalvec and that’s your normal[i][j].

Hmm, ill admit im not 100% on the maths your refering to but always willing to learna nd will look into this.

and the [i+1][j] and [i][j+1] have the same normas because its just for face normals at the mo and not vert normals, which is what i want to try next.

and yes your right about having to update any “other” effected vectors. I couldnt really find alot of info on terrain normals so as a beginner just tryed my best at what i knew.

Slowly getting there though and enjoying all the learning in progress! :slight_smile:

What is the none “3 point” method you mention? Is that calulating a normal for each vert?

Thanks
Andy

Ok, bit more playing and its starting to at least work and update correctly, im just actualy unsure if there 100% correct so opionions please. :slight_smile:

It certainly looks not bad, but im not convinced yet.

Some of the normals that are dark spill onto light areas which is probably because im not doing the correct vertex calculations, which ill give a go at next.

Note: Just watched back on my laptop and its really quite dark compared to my computer monitor so didnt realie, apologies for that.

<object width=“425” height=“350”> <param name=“movie” value=“- YouTube”></param> <param name=“wmode” value=“transparent”></param> <embed src=“- YouTube” type=“application/x-shockwave-flash” wmode=“transparent” width=“425” height=“350”> </embed></object>

Another one with a moving light sources to help check the normals.
<object width=“425” height=“350”> <param name=“movie” value=“- YouTube”></param> <param name=“wmode” value=“transparent”></param> <embed src=“- YouTube” type=“application/x-shockwave-flash” wmode=“transparent” width=“425” height=“350”> </embed></object>

Thanks
Andy

That looks pretty good to me. You probably think it looks funny at sharp points and here’s why.


a--b--c
|  |  |
d--e--f
|  |  |
g--h--i

Let’s say in the diagram above e is the tallest vertex. You’re calculating the normal of that vertex say using “efb”. Well, that means the normal for e is pointing towards c, more or less right? Well, if you had calculated it using “edh” it would be pointed more towards g. As Y-Tensor said you can take some type of average around that vertex and use that instead of using picking one side. For example, compute four normals on the adjacent triangles and then average them.

OT, but what did you make the UI in? Looks pretty slick!