Jump to content
  • Advertisement
Sign in to follow this  
Elig

GLSL NormalMap problems

This topic is 4557 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
Advertisement
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  

  • Advertisement
×

Important Information

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

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!