Having recently gotten tangent vectors working, I wanted to try out normal mapping. I'm constructing a TBN matrix in my vertex shader like so (including the whole thing for clarity):
// basic.vert
#version 430 core
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
in vec3 v_position;
in vec3 v_normal;
in vec3 v_tangent;
in vec2 v_texcoord;
out VS_OUT {
vec3 position;
vec2 texcoord;
vec3 tangent;
vec3 bitangent;
vec3 normal;
mat3 TBN;
} vs_out;
void main()
{
gl_Position = projection * view * model * vec4(v_position, 1);
vs_out.position = (model * vec4(v_position, 1)).xyz;
// Compute TBN matrix
// Not using bitangent sign, I was *going* to add that next
vec3 v_bitangent = cross(v_normal, v_tangent);
vec3 T = normalize(vec3(model * vec4(v_tangent, 0.0)));
vec3 B = normalize(vec3(model * vec4(v_bitangent, 0.0)));
vec3 N = normalize(vec3(model * vec4(v_normal, 0.0)));
vs_out.tangent = T;
vs_out.bitangent = B;
vs_out.normal = N;
vs_out.TBN = mat3(T, B, N);
}
You may have noticed that some of my shader outputs are redundent with the TBN matrix, I'll get to that.
So just to test this out, I wrote my fragment shader like so:
// basic.frag
#version 430 core
uniform sampler2D diffuse;
in VS_OUT {
vec3 position;
vec2 texcoord;
vec3 tangent;
vec3 bitangent;
vec3 normal;
mat3 TBN;
} fs_in;
layout (location = 0) out vec3 out_position;
layout (location = 1) out vec3 out_normal;
layout (location = 2) out vec4 out_diffuse;
layout (location = 3) out float out_specular;
void main()
{
out_position = fs_in.position;
out_normal = fs_in.TBN[2];
out_diffuse = texture(diffuse, fs_in.texcoord);
out_specular = 0.3;
}
Finally, the viewport shader just outputs the normal buffer instead of doing any shading. However, I just get a black screen, with no errors.
So I changed the out_normal assignment line in my fragment shader to:
out_normal = fs_in.normal;
And it works. After a lot of head scratching, I ended up with this.
// basic.vert
//...
out VS_OUT {
//...
mat4 TBN;
} vs_out;
//...
vs_out = mat4(vec4(T, 0), vec4(B, 0), vec4(N, 0), vec4(0, 0, 0, 1));
// basic.frag
//...
in VS_OUT {
//...
mat4 TBN;
} fs_in;
//...
out_normal = TBN[2].xyz;
And it works. That obviously isn't really what I'd want, but I have no idea what to believe anymore. Is this a driver bug, or am I doing something stupid (it wouldn't be the first time)?
Edit - Some additional notes
Using (when TBN is a mat3):
out_normal = fs_in.TBN[0];
Outputs the bitangent vector, and:
out_normal = fs_in.TBN[1];
Outputs the normal vector.
fs_in.tangent/bitangent/normal always returns the expected result, so I may end up just constructing the TBN matrix in the fragment shader.