《Unity着色器圣经》6.0.3 | TBN矩阵

目录索引

译文

我们已经知道,TBN矩阵由模型的切线、副切线和法线组成。在本书的第 6.0.1 小节中,我们已经学习了如何将这三种向量从模型空间变换到世界空间,那么接下来我们就要创建一个用于将法线贴图变换到切线空间的矩阵。我们将在片元着色器阶段按照 TBN 的首字母缩写的相同顺序来创建矩阵。

fixed4 frag (v2f i) : SV_Target
{
    fixed4 normal_map = tex2D(_NormalMap, i.uv_normal);
    fixed4 normal_compressed = DXTCompression(normal_map);
    float3x3 TBN_matrix = float3x3
    (
        i.tangent_world.xyz,
        i.binormal_world,
        i.normal_world
    );
    ...
}

在上面的例子中,我们创建了一个名为 TBN_matrix 的 3 * 3 矩阵,里面包括了世界空间下切线、副切线和法线的值。需要注意的是,矩阵中的切线后面有个“.xyz”是因为它在 v2f 结构体中被声明成了一个四维向量。如果不明确写出我们只使用其中的 XYZ 三个通道,程序会默认我们四个通道(XYZW)都使用,这可能导致着色器在编译的时候报错。

接着,我们只需将法线贴图与 TBN 矩阵相乘,并返回运算结果即可:

fixed4 frag (v2f i) : SV_Target
{
    fixed4 normal_map = tex2D(_NormalMap, i.uv_normal);
    fixed3 normal_compressed = DXTCompression(normal_map);
    float3x3 TBN_matrix = float3x3
    (
        i.tangent_world.xyz,
        i.binormal_world,
        i.normal_world
    );
    fixed4 normal_color = normalize(mul(normal_compressed, TBN_matrix));

    return fixed4 (normal_color, 1);
}

结果得到了一个三维向量 normal_color。最后,我们用一个四维向量返回法线的颜色,并将值“1”分配给 A(alpha)通道。

值得一提的是,当我们将法线贴图导入 Unity 时,纹理类型在默认情况下会被设置为“Texture Type Default”。在我们将法线贴图赋到材质之前,需要打开法线贴图的检查器,将纹理类型设置成“Normal map”,否则会得到错误的结果。

图片[1]-《Unity着色器圣经》6.0.3 | TBN矩阵-软件开发学习笔记
Fig. 6.0.3a

原文对照

As we already know, the TBN matrix is composed of the tangents, binormals and normals of our object. In section 6.0.1 we looked at how to transform these properties from objectspace to world-space. What we will do next is create a new matrix to transform our normal map to tangent-space. To do this, we will go to the fragment shader stage and create the matrix following the same order mentioned in the acronym TBN.

fixed4 frag (v2f i) : SV_Target
{
    fixed4 normal_map = tex2D(_NormalMap, i.uv_normal);
    fixed4 normal_compressed = DXTCompression(normal_map);
    float3x3 TBN_matrix = float3x3
    (
        i.tangent_world.xyz,
        i.binormal_world,
        i.normal_world
    );
    ...
}

In the example above, we created a matrix called TBN_matrix, which has three by three dimensions [3×3]. In it, we included the tangent and binormal outputs and the normals; all in world-space. Please note that in the case of tangents, we included their XYZ coordinates explicitly. This is because they were declared as a four-dimensional vector in the struct v2f, otherwise, if we do not specify the number of dimensions we want to use, the program will assume that it must use all of them (XYZW), and this could, consequently, generate an error with our shader unable to compile them.

To conclude, all we have to do is multiply our normal map by the TBN matrix and return the result of the operation.

fixed4 frag (v2f i) : SV_Target
{
    fixed4 normal_map = tex2D(_NormalMap, i.uv_normal);
    fixed3 normal_compressed = DXTCompression(normal_map);
    float3x3 TBN_matrix = float3x3
    (
        i.tangent_world.xyz,
        i.binormal_world,
        i.normal_world
    );
    fixed4 normal_color = normalize(mul(normal_compressed, TBN_matrix));

    return fixed4 (normal_color, 1);
}

The example has created a three-dimensional vector called normal_color. This vector has the result or factor between the normal map and the TBN matrix. Finally, we have returned the color of the normals in RGB, and assigned the value “one” to the A (alpha) channel.

It is important to mention that when we import a normal map to Unity, by default, it is configured in “Texture Type Default” within our project.

Before assigning the normal map to our material, we must select the texture, go to the inspector, and set it as Texture Type Normal Map, otherwise, it may create a program error.

图片[1]-《Unity着色器圣经》6.0.3 | TBN矩阵-软件开发学习笔记
Fig. 6.0.3a
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容