Sign in to follow this  

Calculating Vertex Normals With No idexes

This topic is 4837 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey All, I am creating a simple heightmap renderer for a sort of 3D overworld. Everything in my renderer works fine, but I can't seem to figure out a way to calculate vertex normals correctly. Basicaly my heightmap is a 2D array of points which the program itterates thrugh and pushes off to the renderer using glVertex3f. I don't need any fancy vertex-lists, or indexes, etc. as this method works fine and dandy for my needs. My only issue is when it comes to calculating the vertex normals, Is there an easy way to figure it out in this situation?

Share this post


Link to post
Share on other sites
You could always use the normal (0,1,0) until you find a better solution...

Or, if you're using triangle primitives, and you have all three vertices for the triangle, you can just calculate it using this snippet from a DirectX app (should be easily converted to OGL - it's just simple maths):

Private Function GetNormal(v0 As D3DVECTOR, v1 As D3DVECTOR, v2 As D3DVECTOR) As D3DVECTOR
'//0. Any Variables
Dim L As Double
Dim v01 As D3DVECTOR, v02 As D3DVECTOR, vNorm As D3DVECTOR

'//1. Get the vectors 0->1 and 0->2
v01.X = v1.X - v0.X
v01.Y = v1.Y - v0.Y
v01.Z = v1.Z - v0.Z

v02.X = v2.X - v0.X
v02.Y = v2.Y - v0.Y
v02.Z = v2.Z - v0.Z

'//2. Get the cross product
vNorm.X = (v01.Y * v02.Z) - (v01.Z * v02.Y)
vNorm.X = (v01.Z * v02.X) - (v01.X * v02.Z)
vNorm.X = (v01.X * v02.Y) - (v01.Y * v02.X)

'//3. Normalize this vector
L = Sqr((vNorm.X * vNorm.X) + (vNorm.Y * vNorm.Y) + (vNorm.Z * vNorm.Z))
vNorm.X = vNorm.X / L
vNorm.Y = vNorm.Y / L
vNorm.Z = vNorm.Z / L

'//4. Return the value:
GetNormal = vNorm
End Function

Though you'll have to translate it into whatever language you're using, as it's in VB6 right now. But that's generally how its done.

EDIT: this will create vectors correctly when the vertices are listed in clock-wise order. If they are listed ccw, then the resultant normal will be inversed. You can un-inverse it by multiplying each of the values by -1.


Mushu - trying to help those he doesn't know, with things he doesn't know.
Why won't he just go away? An question the universe may never have an answer to...

Share this post


Link to post
Share on other sites
Hey Mushu,

The code example you gave, while good, illustrates how to find a Face normal of a given triangle. That is, you give the function your triangles 3 points and out pops the face normal. I need to obtain the vertex normal in order to achive a smooth lighting effect.

Does anyoen have any ideas on this?

Share this post


Link to post
Share on other sites
Well, is it possible to use the position of the neighboring 4 vertices to find a plane, then use the tangent to that plane?

I have no idea how to implement that, but you'll probably end up doing something along those lines, more or less.

Or you can just calculate all the face normals, then average the 4/8 per vertex to find the vertex normal. That's all the ideas I have left. Good luck!


Mushu - trying to help those he doesn't know, with things he doesn't know.
Why won't he just go away? An question the universe may never have an answer to...

Share this post


Link to post
Share on other sites
So the way I learned how to do this is through implementing subdivision surfaces. They're a bit complicated, but pretty neat. Anywho, you can find a doc that has the normal generation (among other things) http://www.mrl.nyu.edu/~dzorin/sig00course/ in the coursenotes00.pdf, specifically on page 71-72. Essentially, the idea is that you loop around a vertex, and preform this weighted sum of each of the vertices to calculate two tangent vectors. The smoothed normal is then the cross product of the two. More specifically:

assume connected_vertices is a std::vector of all the vertices around the vertex you're calculating the normal for. These must be in order. It should be something like this (i dont think the winding direction matters though):


3__2__1
|\ | /|
| \|/ |
4--a--0
| /|\ |
|/_|_\|
5 6 7


t1, t2 are the tangent vectors, and are initially set to zero.


for (int i = 0; i < connected_vertices.size () - 1; ++i) {
t1 += connected_vertices.at (i) * cos (2 * PI * i / connected_vertices.size ());
t2 += connected_vertices.at (i) * sin (2 * PI * i / connected_vertices.size ());
}

normal = cross (t1, t2);




To calculate at a boundary, its a little complicated. Here you once again generate the two tangent vectors, and take the cross product. This time we'll call them t_along (along the boundary), and t_across. Say we've got a 10x10 heightmap, and we're trying to calculate the normal at (0,5), where the boundary is along x=0:

1--a--0


t_along = connected_vertices(1) - connected_vertices(0);




For the t_across, there are three separate cases: if the current vertex only has two connections (eg: in a line):

1--a--0


t_across = vertex(0) + vertex(1) - 2*vertex(a);




for three, we are trying to calculate at vertex 1 in this case:


1
/|\
/ | \
2--a--0




t_across = vertex(1) - vertex(a);




for all the other cases:


3__2__1
|\ | /|
| \|/ |
4--a--0




theta = PI / (connected_vertices.size () - 1);

for (int i = 1; i < connected_vertices.size () - 1; ++i) {
t_across += connected_vertices.at (i) * sin (i * theta);
}

t_across *= 2 cos (theta) - 2;
t_across += sin (theta) * (connected_vertices.front () + connected_vertices.back ());



Then the normal is just cross (t_along, t_across). Its a bit complicated, you just have to make sure that you're using the right vertices.

Share this post


Link to post
Share on other sites
Since you are using heightmap, "Finite Difference" is the best method to calculate by far. It's faster and simpler than anything else. Use google to finde some implementations. And I belive nVidia's normalmapper has source for this.

Share this post


Link to post
Share on other sites
yeah, but my way's funner

:p

but in all actuality, mine might just be a complicated way to do finite difference on complicated meshes, and heightmaps are much simpler. I'm not sure however which one generates better normals. One thing mine will do is generate along the edge, where finite difference I don't think will work there. You could combine the two for that case though.

Share this post


Link to post
Share on other sites
Quote:
Original post by idadesub
yeah, but my way's funner

Nice one :)

Quote:
Original post by idadesub
One thing mine will do is generate along the edge, where finite difference I don't think will work there.

Finite difference will work on edges if you take that in account while writing it. You can select to clamp, clamp to border or to repeat the heightmap, depending on what you need.

But the downside is that it only works on hightmaps, not on general meshes.

Share this post


Link to post
Share on other sites

This topic is 4837 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this