Sign in to follow this  

GLSL NormalMap problems

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

Alright, I've been having a bit of problems with my normal mapping. As far as I can tell, Im doing everything correctly, however, the display is... Less than correct. I've got a fairly simple vertex/fragment shader, the vertex shader simply converts from object space to tangent space in the typical way, I pass in the tangent and the crossfactor to the vertex shader that way I can reassemble the bitangent on the graphics card. I pass the tangent and cross factor in through a multitexture coordinate. My actual application uses vertex/texture/polygon coord arrays as well as multi texturing. Everything there is set up perfectly, to my knowledge anyway. The thing is, everything is displayed correctly until if I use the interpolated per vertex normals. It looks just fine, exactly as it should. But when I attempt to use the normal map, it appears as though the light is moving around the rendered object at a fairly high speed, and it has some other graphical oddities to say the least. Anyway, I think my code will explain a lot more than I can. I really appreciate any help anyone can give. I realize that my methods are a little strange, they're something of a modification of another peice of code. Vertex Program:
const vec4 AMBIENT = vec4( 0.1, 0.1, 0.1, 1.0 );
const vec4 SPECULAR = vec4( 1.0, 1.0, 1.0, 1.0 );

varying vec4 Ca;
varying vec4 Cd;
varying vec4 Cs;

varying vec4 V_eye;
varying vec4 L_eye;
varying vec4 N_eye;

void main(void)
{
  vec3 bitangent = cross(gl_MultiTexCoord1.xyz,gl_Normal)*gl_MultiTexCoord1.w;

  vec4 V = gl_ModelViewMatrix * gl_Vertex;
  vec4 L = (gl_ModelViewMatrix * gl_LightSource[0].position) - V;
  vec4 N = vec4(gl_NormalMatrix * gl_Normal, 0.0);

  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  V = -V;
  
  V = V * gl_ModelViewMatrixInverse;
  L = L * gl_ModelViewMatrixInverse;
  N = N * gl_ModelViewMatrixInverse;

  N_eye.x = dot(N.xyz,gl_MultiTexCoord1.xyz);
  N_eye.y = dot(N.xyz,bitangent);
  N_eye.z = dot(N.xyz,gl_Normal);
  
  V_eye.x = dot(V.xyz,gl_MultiTexCoord1.xyz);
  V_eye.y = dot(V.xyz,bitangent);
  V_eye.z = dot(V.xyz,gl_Normal);
  
  L_eye.x = dot(L.xyz,gl_MultiTexCoord1.xyz);
  L_eye.y = dot(L.xyz,bitangent);
  L_eye.z = dot(L.xyz,gl_Normal);

  Ca = AMBIENT;
  Cd = 0.5;
  Cs = SPECULAR;
  
  gl_TexCoord[0] = gl_MultiTexCoord0;
}


Fragment Program:
uniform sampler2D Base;
uniform sampler2D Gloss;
uniform sampler2D Normal;

varying vec4 Ca;
varying vec4 Cd;
varying vec4 Cs;

varying vec4 V_eye;
varying vec4 L_eye;
varying vec4 N_eye;

void main(void)
{
  vec3 V = normalize(vec3(V_eye));
  vec3 L = normalize(vec3(L_eye));
  vec3 N = normalize(vec3(N_eye));
  
  vec3 base = texture2D(Base,gl_TexCoord[0].st);
  vec3 bump = texture2D(Normal,gl_TexCoord[0].st).xyz * 2.0 - 1.0;
  float gloss = texture2D(Gloss,gl_TexCoord[0].st);

  bump = normalize(bump);

  float diffuse = clamp(dot(L, bump), 0.0, 1.0);

  vec3 H = normalize(L + V);
  float specular = clamp(pow(dot(bump, H), 32.0), 0.0, 1.0);

  gl_FragColor.rgb = Ca + ((base*Cd)*diffuse) + (Cs*specular);
}


And, just incase, a bit of my rendering code:
glVertexPointer(3, GL_FLOAT, 0, &meshVertices[0][0]);
          glNormalPointer(GL_FLOAT, 0, &meshNormals[0][0]);

          if((textureCoordinateCount > 0))
          {
			  glClientActiveTexture(GL_TEXTURE0);
			  glActiveTexture(GL_TEXTURE0);
			  glBindTexture(GL_TEXTURE_2D,e->m_Texture.m_TextureID);
			  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			  glTexCoordPointer(2, GL_FLOAT, 0, &meshTextureCoordinates[0][0]);
			  
			  glClientActiveTexture(GL_TEXTURE1);
			  glActiveTexture(GL_TEXTURE1);
			  glBindTexture(GL_TEXTURE_2D,e->m_Texture.m_GlossID);
			  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			  glTexCoordPointer(4, GL_FLOAT, 0, meshtangent);

			  glClientActiveTexture(GL_TEXTURE2);
			  glActiveTexture(GL_TEXTURE2);
			  glBindTexture(GL_TEXTURE_2D,e->m_Texture.m_NormalID);
          };

		  if(sizeof(CalIndex)==2)
            glDrawElements(GL_TRIANGLES, faceCount * 3, GL_UNSIGNED_SHORT, &meshFaces[0][0]);
          else
            glDrawElements(GL_TRIANGLES, faceCount * 3, GL_UNSIGNED_INT, &meshFaces[0][0]);


Share this post


Link to post
Share on other sites
Here's a hint: Is your normal map in eye space?
Here's a second hint: Why are you passing in the "N" value, when you're not using it?
Here's a third hint (OK, this probably gives it away :-): Normal maps are typically generated in tangent space, and require a transform to take them to object (or eye) space.

Share this post


Link to post
Share on other sites
I've fixed it, actually. I know I didnt need to pass in N, I just was for testing purposes. Second, my normal map was in tangent space, so I was attempting to convert all the lighting calculations into tangent space. My mistake was that, once I had all the coordinates in eye space, I was multiplying them by ModelViewMatrixInverse, which was incorrect. In order to get a coordinate from eye space into object space, I should have been multiplying them by ModelViewMatrix. Once I correctly multiplied them by ModelViewMatrix, I could then use the TBN matrix to convert them into tangent space. Which is much better than the alternative of bringing the normals into eye space for each fragment. Here, I only have to convert the other coordinates into tangent space at each vertex. Anyway, thanks.

Share this post


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