1
\$\begingroup\$

I've been reading today about normal mapping. Up to now, the only normal mapping I encountered was with maps already in world space so I just extracted the info from the texture and transformed them with the normal matrix.

Now I wanted to try to use a normal map that is in tangent space, but I immediately became really confused.

What I've in my code up-to-now is

Vertex Shader

 ...
passedPosition = modelViewMatrix*vec4(vertexPosition,1.0);
 ...

Fragment Shader

 vec3 V = normalize(-passedPosition .xyz);   // Eye vector
 ...
 vec3 L_dir = passedPosition .xyz - lights[i].lightPosition.xyz;
 vec3 L = normalize(L_dir); 
 ...

And then proceed with my lighting calculations.

All the tutorial I came across change all the light directions and the view vector into tangent space (in the vertex shader) and then extract the normal from the texture and keep going (in fragment). My issue here is that I'd like to avoid to access all my lights informations in the vertex shader, so my questions are:

  • Does make sense to pass to the fragment shader the t,b,n vectors so that I transform the light directions there? Should I consider access all my lighting informations in vertex shader (I have an array of Light struct which has more than just the position) and then passed them on to the fragment shader? Is something I'd like to avoid, but if is much better I can think of it.
  • There is a way to perform normal mapping that is more compatible with what I've now (snippets above posted).
  • Should I consider change my calculations from view space to world space? In that case, how can I perform normal mapping?

Thanks

\$\endgroup\$
2
\$\begingroup\$

Yes, it does make sense to pass the tangent basis (the T,B,N vectors) down to the fragment shader, then transform the normal (from the normal map) to world space or view space and do all the shading calculations in that space. In fact that's probably the more common way to do normal mapping these days, I suspect.

I prefer world space for shading calculations as you then don't need to transform all your light positions/directions to view space each frame, and it also makes it easier to use things like pre-rendered environment cubemaps or spherical harmonics, which are in world space anyway. However, shading can be done perfectly well in view space also.

To do shading in world space, you would do the following:

  • In the vertex shader, transform the TBN vectors by the object's local-to-world matrix (not including translation, since they're vectors, not points). Send the now world-space TBN basis down to the fragment shader. (Actually you don't need to transform B, you can just calculate it as B = N cross T.)
  • Also calculate world-space vectors from the vertex to the camera and the light (just a subtraction) and send those down to the fragment shader as well. (Or this can be done in the fragment shader.)
  • In the fragment shader, sample the normal map and use the TBN vectors to transform it into world space. Then do all the shading calculations (N dot L and so forth).

For view-space shading you would do the same thing; just substitute view space for world space in the previous steps. The only new step is that you need the light position to be in view space, so you have to calculate that somewhere, either on the CPU or in one of the shaders.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.