法线贴图,TBN矩阵计算

时间:2013-03-10 16:07:24

标签: opengl glsl

我只是想确保我正确理解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矩阵将矢量从Tangent 空间转换为Eye 空间。实际上我们想要反向 - 将一个矢量从眼睛空间变换到切线空间。因此,我们需要反转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空间转换为眼睛空间,然后在片段着色器中转换每个从法线贴图读取的法线。

1 个答案:

答案 0 :(得分: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,也不是TBN矩阵的向量(作为我的模型的一部分)

nor - 是从实际Vertex位置到法线的法线向量(可以计算为来自此顶点的两个顶点的向量乘法)

tan,bin是垂直向量,通常与纹理映射轴或模型的teselation平行。如果选择错误的tan / bin向量,有时会出现一些光照伪影。例如,如果你有圆柱体而不是圆柱体是它的旋转轴,并且棕褐色是沿圆形垂直(切线)

tan,bin,也不应该彼此垂直

你可以自动计算TBN,但这会导致一些伪影。要做到这一点,你只需选择棕褐色矢量一个用于正常计算的顶点和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;
    }
//------------------------------------------------------------------