6

我只是想确保我正确理解 TBN 矩阵计算

在顶点着色器中我们通常使用:

vec3 n = normalize(gl_NormalMatrix * gl_Normal);
vec3 t = normalize(gl_NormalMatrix * Tangent.xyz);
vec3 b = normalize(gl_NormalMatrix * Bitangent.xyz);
mat3 tbn = mat3(t, b, n);

据我了解,该tbn矩阵将向量从切线空间转换为眼睛空间。实际上我们想要反向 - 将向量从眼睛空间转换到切线空间。因此我们需要反转tbn矩阵:

tbn = transpose(tbn); // transpose should be OK here for doing matrix inversion

注意: tbn - 应该只包含旋转,对于这种情况,我们可以使用转置来反转矩阵。

我们可以转换我们的向量:

vec3 lightT  = tbn * light_vector;
...          = tbn * ...

在几个教程中,我发现作者使用了这样的源代码:

light.x = dot(light, t);
light.y = dot(light, b);
light.z = dot(light, n);

上面的代码与乘以transposed(tbn)矩阵相同。

问题:

tbn我们应该像我上面解释的那样使用转置矩阵吗?或者,也许我错过了什么?

请注意,通过该解决方案,我们在顶点着色器中将向量(light_vector)转换为 TBN,然后在片段着色器中我们只需要从法线贴图获取法线。其他选项是创建从 TBN 空间转换到眼睛空间的 TBN 矩阵,然后在片段着色器中转换从法线贴图读取的每个法线。

4

1 回答 1

0

转置不是矩阵的反转!

我在顶点着色器中的 TBN 矩阵如下所示:

uniform mat4x4 tm_l2g_dir;
layout(location=3) in vec3 tan;
layout(location=4) in vec3 bin;
layout(location=5) in vec3 nor;
out smooth mat3 pixel_TBN;

void main()
{
    vec4 p;
    //...
    p.xyz=tan.xyz; p.w=1.0; pixel_TBN[0]=normalize((tm_l2g_dir*p).xyz);
    p.xyz=bin.xyz; p.w=1.0; pixel_TBN[1]=normalize((tm_l2g_dir*p).xyz);
    p.xyz=nor.xyz; p.w=1.0; pixel_TBN[2]=normalize((tm_l2g_dir*p).xyz);
    //...
}

在哪里:

  • tm_l2g_dir 是从局部模型空间到全局场景空间的转换矩阵,对您的代码没有任何移动(仅更改方向)它是您的法线矩阵
  • tan,bin,nor 不是 TBN 矩阵的向量(作为我模型的一部分)

也不是 - 从实际顶点位置到表面的法线向量(可以计算为来自该顶点的两个顶点的向量乘法)

tan,bin 是垂直向量,通常平行于纹理映射轴或模型的细分。如果您选择错误的 tan/bin 向量,有时可能会出现一些照明伪影。例如,如果您有圆柱体,则 bin 是它的旋转轴,而 tan 沿圆垂直于它(切线)

tan,bin,nor 不应相互垂直

您也可以自动计算 TBN,但这会导致一些伪影。要做到这一点,您只需选择一个用于正常计算的顶点作为 tan 向量,并且 bin=nor x bin

在片段着色器中,我使用带有法线贴图的 pixel_TBN 来计算片段的真实法线

//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
in smooth vec2 pixel_txr;
in smooth mat3 pixel_TBN;
uniform sampler2D   txr_normal;
out layout(location=0) vec4 frag_col;
const vec4 v05=vec4(0.5,0.5,0.5,0.5);
//------------------------------------------------------------------
void main(void)
    {
    vec4 col;
    vec3 normal;
    col=(texture2D(txr_normal,pixel_txr.st)-v05)*2.0;       // normal/bump maping
    normal=pixel_TBN*col.xyz;
    // col=... other stuff to compute col

    frag_col=col;
    }
//------------------------------------------------------------------
于 2013-08-05T14:44:15.803 回答