切线空间法线贴图的奇怪结果

这是我的问题,我尝试在原始着色器中添加一个处理切线空间法线贴图的过程,该着色器使用BlinnPhone Lighting模型,BlinnPhone Light模型工作正常

BlinnPhone Light

但是,当我尝试转换切线空间法线(从法线贴图采样)时,如果我组合矩阵,则可以一次将法线从切线空间转换为世界空间(因为TBN已经乘以世界转换矩阵) ,那么我总是得到错误的点亮结果:

Wrong result

但是,如果我组合了TBN矩阵,该矩阵仅将切线空间转换为顶点着色器中的对象空间(模型空间),并将世界转换矩阵传递给片段着色器,那么我将法线转换两次,一次使用TBN转换法线到对象(模型)空间,然后将其转换为世界空间,最后我可以获得正确的结果。

right result

我怀疑第一种方法的normalize函数出了点问题(一次转换正常),但是我找不到问题所在。 帮帮我,谢谢。

PS:附加的代码段是默认使用方法2的,但是您可以将整个方法转换为方法2,方法是在顶点着色器中用注释“ for method 1”取消注释该行,然后在注释器中用注释注释该行“不适用于方法1”。

顶点着色器:

#version 450 core
#pragma debug(on)

layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec2 in_uv;
layout (location = 2) in vec3 vTangent;
layout (location = 3) in vec3 vBitangent;
layout (location = 4) in vec3 vNormal;

uniform mat4x4 mat_mvp;
uniform mat4x4 mat_world;

//----out vars
out vec2 uv;
out vec3 worldNormal;
out vec3 worldPos;
out mat3x3 tangentToModelMat;
out mat4x4 worldMat;
precise out vec3 testV;
out float f1;
out float f2;
out float f3;

void main()
{
    gl_Position = mat_mvp * vec4(vPosition, 1);

    worldPos = (mat_world * vec4(vPosition, 1)).xyz;

    vec3 T = normalize(mat3(mat_world) * vTangent);
    //T = mat3(mat_world) * vTangent;
    vec3 B = normalize(mat3(mat_world) * vBitangent);
    //B = mat3(mat_world) * vBitangent;
    vec3 N = normalize(vNormal * inverse(mat3(mat_world)));
    //N = vNormal * inverse(mat3(mat_world));

    // re-orthogonalize T with respect to N
    //T = (T - dot(T, N) * N);

    B = cross(N, T);

    tangentToModelMat[0] = vTangent;
    tangentToModelMat[1] = vBitangent;
    tangentToModelMat[2] = vNormal;
    //tangentToModelMat = mat3(T, B, N);//for method 1

    worldNormal = normalize(vNormal * inverse(mat3(mat_world)));

    uv = in_uv;
    worldMat = mat_world;
}

片段着色器:

#version 450 core

layout (location = 0) out vec4 fColor;

uniform vec3 worldCamPos;

uniform sampler2D tex;
uniform sampler2D normalMap;

//----in vars
in vec2 uv;
in vec3 worldNormal;
in vec3 worldPos;
in mat3x3 tangentToModelMat;
in mat4x4 worldMat;
precise in vec3 testV;
in float f1;
in float f2;
in float f3;

void main()
{
    // assumption directional light color and dir
    vec3 worldLightColor = vec3(1, 1, 1);
    vec3 worldLightDir = vec3(1, -1, -1);
    worldLightDir = normalize(worldLightDir);

    // assumption ambient light color
    vec3 ambient = vec3(1, 1, 1);
    // assumption diffuse color
    vec3 diffuseColor = vec3(1, 1, 1);
    // assumption specular color
    vec3 specularColor = vec3(1, 1, 1);

    // Get "normal" from the normalmap
    vec3 normal = texture(normalMap, uv).rgb;
    normal = normal * 2 - 1;
    normal = normalize(tangentToModelMat * normal);
    normal = normalize(mat3(worldMat) * normal);//not for method 1

    vec3 viewDir = normalize(worldCamPos - worldPos);
    vec3 halfDir = normalize(viewDir + worldLightDir);

    vec4 albedo = texture(tex, uv);
    ambient = ambient * 0.7 * albedo.rgb;
    vec3 diffuse = worldLightColor * ambient.rgb * clamp(dot(worldLightDir, normal), 0.0, 1.0);

    float spec = pow(max(dot(halfDir, normal), 0.0), 512);
    vec3 specular = worldLightColor * specularColor.rgb * spec;

    fColor = vec4(ambient + diffuse + specular, 1);
    //fColor = vec4(albedo.rgb, 1);
    //fColor = albedo;
    //fColor = vec4(f1, f2, f3, 1);
}
评论