Jump to content
  • Advertisement
Sign in to follow this  
RvH

Smooth shading: Problems with normals / lighting

This topic is 3299 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

I'm rendering a model with the glDrawElements function. Only using the normal and the vertex arrays for the moment. The vertex normals are drawn in white and seem to be correct. However the model is very weird looking. Has anyone got suggestions or idea's what could be wrong? Any help is appreciated. [Edited by - RvH on November 20, 2009 7:48:23 AM]

Share this post


Link to post
Share on other sites
Advertisement
I can see the pictures. It is better to show some code. Also make sure your normals are of unit length.

Share this post


Link to post
Share on other sites
I'm not 100% convinced that your normals do look right, hard to tell without a close up!

The 2nd picture is the most telling, if you look at the edge nearest the camera, the normals seems to be pointing inwards and some points, outwards at others and near lying in the plane of the triangle at other points. These errors would produce exactly the lighting effect you are seeing.

Additionally I'm not convinced all the normals are unit length, perhaps some are < 1 units long resulting in dark patches?

Share this post


Link to post
Share on other sites
The normals at the toprow are indeed incorrect and some point inwards. But this is only in the toprow.


[Edited by - RvH on November 20, 2009 7:14:54 AM]

Share this post


Link to post
Share on other sites
Your normalisation code in CalculateVertexNormals is wrong, you need to do a proper vector normalise, dividing by the number of contributing vertex normals is unfortunately not the same thing.

For example consider just 2 vertex normals {1,0,0} and {0,1,0}, if you add them together and divide by 2 you get {0.5,0.5,0} which is not normalised

sqrt(0.5^2 + 0.5^2 + 0^2) = 0.707107 != 1

As it happens the vertex normal should have been {0.707107, 0.707107, 0}

Its not entirely clear which vertices CalculateVertexNormals is referencing, I must admit I am having problems reading it. Perhaps the indexing could be clearer? I would expect the number of vertices referenced in building the normal to be different to the code you have. For example, an interior vertex might reference 9 vertices (this + 8 surrounding) or perhaps if you're interested in speed 5 vertices (this + diagonals or this + vertically + horizontally adjacent)

I would be tempted to build a function which generates a vertex for any X,Y coordinate on your grid, get that working then optimise later. This would be much clearer / easier to debug / easier to ask for help on.

Share this post


Link to post
Share on other sites
I don't know OpenGL either (I'm a DirectX guy) but perhaps theres some issue with tristrips? Tristrips have to invert the winding order of each triangle for the purposes of backface culling. It almost looks like the vertex normal is being flipped per triangle but this really shouldn't happen....

Share this post


Link to post
Share on other sites
So if I understand it correctly I need to normalize the vector after dividing it?

Sorry about the indexing, it is indeed very confusing. In pseudo code this is what Im trying to do:


// Get the three triangles below the vertex
vec[0] = SurfaceNormals[ triIndex ];
vec[1] = SurfaceNormals[ indexPlusOne ];
vec[2] = SurfaceNormals[ indexPlusTwo ];

// Get the three triangles above the vertex
vec[3] = SurfaceNormals[ rowOffset + triIndex ];
vec[4] = SurfaceNormals[ rowOffset + indexPlusOne ];
vec[5] = SurfaceNormals[ rowOffset + indexPlusTwo ];

// Sum the vectors and then divide by 6 to average them
vertexNormal = vec[0] + vec[1] + vec[2] + vec[3] + vec[4] + vec[5];
vertexNormal /= 6.0f;



So instead of taking the surrounding vertices Im taking the normals of the surrounding faces.

Share this post


Link to post
Share on other sites
For each vertex, sum the face normals that share that vertex and average the result. Then normalise. E.g. for a vertex in a mesh, it's going to share typically 6 triagles. Edge vertices will share less etc.

Another way to do it is to calculate the face normals as usual and add the result to each vertex in that triangle face (assuming the vertex normals have been initialized to (0,0,0)). At the end, loop through and normalize each vertex normal.

Share this post


Link to post
Share on other sites
You don't need to divide the normal at all, just normalise it as is

So you're attempting to do this:

A B---C
/| /|
/ | / |
/ |/ |
D---E---F
| /| /
| / | /
|/ |/
G---H I

Computing the normal for vertex E by considering summing the 6 triangles surface normals around E (and then normalising) should work fine. I'm not entirely sure this is what your pseudo code is doing however

I've previously found faster / more accurate / simpler ways of solving this problem without prestoring triangle normals. This method is independant of your actual triangulation used during rendering. (which is a good thing)

A B C
/|\
/ | \
/ | \
D---E---F
\ | /
\ | /
\|/
G H I

BE = B-E;
FE = F-E;
HE = H-E;
DE = D-E;
VertexNormalE = BE.Cross(FE);
VertexNormalE += FE.Cross(HE);
VertexNormalE += HE.Cross(DE);
VertexNormalE += DE.Cross(BE);
VertexNormalE.Normalise();

For more accuracy but at the cost of more processing you could even introduce A,C,G and I into the mix and use 8 cross products

A---B---C
|\ | /|
| \ | / |
| \|/ |
D---E---F
| /|\ |
| / | \ |
|/ | \|
G---H---I

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!