0

I have a lighting problem in which some triangles seem to exhibit poor shading artifacts in which the shading isn't smooth across the overall surface of the entire polygon (a wall, for instance). That is, each triangle that makes up the polygon seems to be shading slightly darker or lighter than it's neighbor.

I am trying to achieve a simple directional lighting. Here is what it looks like:

enter image description here

Here is what the vertex shader code:

gl_Position  = uPMatrix * uMVMatrix * vec4(aVertexPosition.xyz, 1.0);    
vNormal = vec3(uNMatrix * vec4(aVertexNormal.xyz, 1.0));
vColor  = aVertexMaterialColor;

And here is the fragment shader code:

vec3  light   = normalize(vec3( 0.5,  0.2,  1.0));
float amount  = max(dot(vNormal, light),  0.0);
vec4 finalColor = vColor; 
finalColor.rgb *= amount;

The problem is that the wall with the windows exhibits various banding where individual triangles appear darker than others. I can't control the geometry I'm getting, but I do believe the triangles are defined ok, as are the normals.

uPMatrix is the projection matrix, uMVMatrix is the model view matrix, and uNMatrix is the normal matrix. Here is how the normal matrix is created (gl-matrix):

var mvMatrix = this.getModelViewMatrix();
var nMatrix  = this.nMatrix;

mat4.copy(nMatrix, mvMatrix);
mat4.invert(nMatrix, nMatrix);
mat4.transpose(nMatrix, nMatrix);

Any ideas what I might be doing wrong, or how I can make the entire wall smoothly shaded?

superqd
  • 333
  • 4
  • 12
  • Looks like classic vertex lighting artifacts, if you "*can't control the geometry*" you should certainly use [per-fragment lighting](http://learningwebgl.com/blog/?p=1523) – LJᛃ Mar 18 '15 at 01:30
  • Thanks for the response. I'll take a look at the link... – superqd Mar 18 '15 at 02:10

1 Answers1

0
gl_Position  = uPMatrix * uMVMatrix * vec4(aVertexPosition.xyz, 1.0);    
vNormal = vec3(uNMatrix * vec4(aVertexNormal.xyz, 1.0));
vColor  = aVertexMaterialColor;
vec3  light   = normalize(vec3( 0.5,  0.2,  1.0));
float amount  = max(dot(vNormal, light),  0.0);
vec4 finalColor = vColor; 
finalColor.rgb *= amount;

In order for a triangle to have some variation in color over its surface, there must be some varying input (well, or gl_FragCoord, but that's a while other thing) that is actually varying. Since your two varyings vNormal and vColor depend on two attributes, one of the following must be true:

  • aVertexMaterialColor is not the same for all three vertices.
  • aVertexNormal is not the same for all three vertices.

Most likely, it is the normals; assuming your geometry comes from a file, either you have not loaded the normals correctly (consistently), or you did not properly instruct the modeling tool to generate flat-shading normals.

Here's a debugging trick:

finalColor.rgb = vNormal * 0.5 + vec3(0.5);

This will colorize all your vertices just according to their normals, disregarding material colors and lighting. You'll get wacky colors, but if you see any surfaces with shaded colors, those triangles have normals which are not all the same.

(Any flat surface should be made of triangles with identical normals; furthermore, those normals should be perpendicular to the plane of the triangle.)

Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
  • I greatly appreciate your response. I tried the debugging technique and got this: http://imgur.com/ftV9MMg I assume by "non-flat normals", you mean that the normals for the wall don't all point in the same direction? Which means the normals for the 3 verts aren't the same...you know, just in thinking about this out loud (the way you phrased it), I think I know where I should now go look for a potential problem (the code that calculates the normals, which I *can* control). – superqd Mar 18 '15 at 02:07
  • @superqd Edited a bit to clarify. – Kevin Reid Mar 18 '15 at 02:18
  • I went back to the code that calculates the normals, and found the error. Sadly, I use unique vertices. The code that was calculating the normals was iterating over indices and grabbing triangle verts from that. But, since vertices are not duplicated, it meant the same vertex could be used in more than one triangle. Which meant the normal for that vertex was getting changed each time. I store the vertices uniquely to save space, but I'm curious what the "usual" solution for this is. Do folks normally just live with duplicated vertices and thus don't normally have this issue? – superqd Mar 18 '15 at 14:33
  • Yes, vertices with the same position but different normals are typical at any sharp edge. Shared vertices occur when a smooth surface has multiple triangles (a corner or a curved surface) – Kevin Reid Mar 18 '15 at 15:14