我正在为教程和教学目的进行法线映射实现我想将 TBN 矩阵传递给片段着色器(来自顶点着色器),以便我可以将切线空间中的法线向量转换为世界空间以进行照明计算。法线贴图应用于 2D 平面,其法线指向正 z 方向。
但是,当我在平面的顶点着色器中计算 TBN 矩阵时(因此所有顶点的所有切线/双切线都相同),显示的法线完全关闭。如果我将切线/副切线和法线向量传递给片段着色器并在那里构造 TBN,它就可以正常工作,如下图所示(显示法线):
这就是它变得奇怪的地方。因为平面是平的,所以 T、B 和 N 向量对于它的所有顶点都是相同的,因此每个片段的 TBN 矩阵也应该是相同的(因为片段插值不会改变任何东西)。顶点着色器中的 TBN 矩阵应该与片段着色器中的 TBN 矩阵完全相同,但视觉输出另有说明。
顶点着色器和片段着色器的源代码如下:
顶点:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoords;
layout (location = 3) in vec3 tangent;
layout (location = 4) in vec3 bitangent;
out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
vec3 Tangent;
vec3 Bitangent;
mat3 TBN;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f);
vs_out.FragPos = vec3(model * vec4(position, 1.0));
vs_out.TexCoords = texCoords;
mat3 normalMatrix = transpose(inverse(mat3(model)));
vs_out.Normal = normalize(normalMatrix * normal);
vec3 T = normalize(normalMatrix * tangent);
vec3 B = normalize(normalMatrix * bitangent);
vec3 N = normalize(normalMatrix * normal);
vs_out.TBN = mat3(T, B, N);
vs_out.Tangent = T;
vs_out.Bitangent = B;
}
分段
#version 330 core
out vec4 FragColor;
in VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
vec3 Tangent;
vec3 Bitangent;
mat3 TBN;
} fs_in;
uniform sampler2D diffuseMap;
uniform sampler2D normalMap;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform bool normalMapping;
void main()
{
vec3 normal = fs_in.Normal;
mat3 tbn;
if(normalMapping)
{
// Obtain normal from normal map in range [0,1]
normal = texture(normalMap, fs_in.TexCoords).rgb;
// Transform normal vector to range [-1,1]
normal = normalize(normal * 2.0 - 1.0);
// Then transform normal in tangent space to world-space via TBN matrix
tbn = mat3(fs_in.Tangent, fs_in.Bitangent, fs_in.Normal); // TBN calculated in fragment shader
// normal = normalize(tbn * normal); // This works!
normal = normalize(fs_in.TBN * normal); // This gives incorrect results
}
// Get diffuse color
vec3 color = texture(diffuseMap, fs_in.TexCoords).rgb;
// Ambient
vec3 ambient = 0.1 * color;
// Diffuse
vec3 lightDir = normalize(lightPos - fs_in.FragPos);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * color;
// Specular
vec3 viewDir = normalize(viewPos - fs_in.FragPos);
vec3 reflectDir = reflect(-lightDir, normal);
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);
vec3 specular = vec3(0.2) * spec; // assuming bright white light color
FragColor = vec4(ambient + diffuse + specular, 1.0f);
FragColor = vec4(normal, 1.0); // display normals for debugging
}
两个 TBN 矩阵明显不同。下面我编译了不同片段着色器输出的图像:
您可以看到 T、B 和 N 向量是正确的,片段着色器的tbn
矩阵也是正确的,但是来自顶点着色器的 TBN 矩阵fs_in.TBN
给出了完全虚假的值。
我完全不知道为什么它不起作用。我知道我可以简单地将 Tangent 和 Bitangent 向量传递给片段着色器,在那里计算并完成它,但我很好奇这不起作用的确切原因?