# Smooth shading: Problems with normals / lighting

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

## 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 on other sites
I can't see the pictures.

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

##### 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 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 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 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 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 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 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   IBE = 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 on other sites
Thanks a lot! I will give that a try and post the results.

##### Share on other sites
I understand your solution but how would you calculate the normals for the top en bottomrow of vertices and assign the vertices?

[Edited by - RvH on November 20, 2009 7:43:21 AM]

##### Share on other sites
Quite simply you disregard any non present vertices, so if you're using the 8 vertex method:
A   B   C                         D---E---F|  /|\  || / | \ ||/  |  \|G---H---I

And you're on the top row you disregard triangles involving verts A,B,C
i.e. you only sum the face normals from EFI, EIH, EHG and EGD