OpenGL 顶点着色器的 NormalMatrix

NormalMatrix for OpenGL vertex shader?

本文关键字:NormalMatrix 顶点 OpenGL      更新时间:2023-10-16

我正在使用 Assimp 导入 3D 模型,它为我提供了其法线贴图的切线和双切线,但是我无法弄清楚用于将顶点着色器中的切线和双切线矢量相乘的矩阵是什么样子的 - 是 WorldViewProjection 矩阵还是其他一些特殊用途的"法线矩阵"?

更新:我的顶点着色器

const std::string gVertexShader =   "#version 330                                                                                       n 
                                                                                                                n 
                                        layout(std140) uniform;                                                 n 
                                                                                                                n 
                                        uniform UnifTransform                                                   n 
                                        {                                                                       n 
                                            mat4 mWVPMatrix;                                                    n 
                                            mat4 mWorldMatrix;                                                  n 
                                            float mTextureTilingFactor;                                         n 
                                        } Transform;                                                            n 
                                                                                                                n 
                                        layout(location = 0) in vec3 vert_position;                                             n 
                                        layout(location = 1) in vec3 vert_normal;                                                   n 
                                        layout(location = 2) in vec2 vert_texcoord;                                                 n 
                                        layout(location = 3) in vec3 vert_tangent;                                                 n 
                                        layout(location = 4) in vec3 vert_bitangent;                                                 n 
                                                                                                                n 
                                        out vec3 frag_position;                                                 n 
                                        out vec3 frag_normal;                                                   n 
                                        out vec2 frag_texcoord;                                                 n 
                                        out vec3 frag_tangent;                                                 n 
                                        out vec3 frag_bitangent;                                                 n 
                                                                                                                n 
                                        void main()                                                                                                 n 
                                        {                                                                                                                   n 
                                            gl_Position   = Transform.mWVPMatrix * vec4(vert_position, 1.0);    n 
                                                                                                                n 
                                            vec4 position = Transform.mWorldMatrix * vec4(vert_position, 1.0);  n 
                                            vec4 normal   = Transform.mWorldMatrix * vec4(vert_normal, 0.0);    n 
                                            vec4 tangent = Transform.mWorldMatrix * vec4(vert_tangent, 0.0);   // correct matrix?   n 
                                            vec4 bitangent = Transform.mWorldMatrix * vec4(vert_bitangent, 0.0);    n 
                                                                                                                n 
                                            frag_position = position.xyz;                                       n 
                                            frag_normal   = normal.xyz;                                         n 
                                            frag_tangent   = tangent.xyz;                                         n 
                                            frag_bitangent = bitangent.xyz;                                         n 
                                            frag_texcoord = Transform.mTextureTilingFactor * vert_texcoord;     n 

TBN(切线、双切线、法线)矩阵 (3x3) 通常用于从切线空间到对象空间。您可以将法线乘以此来变换它们。请注意,法线本质上是定向的,因此与您通常处理的大多数变换矩阵不同,您只需要一个 vec3 和 3x3 矩阵即可执行此操作;在我看来,这就是这个特定矩阵"特别"的原因。根据使用此矩阵的方式,您可以将光矢量转换为切线空间,或将法线贴图转换为对象空间。

一般来说,您不会单独乘以切线、双切线和法线向量。它们定义了你的向量空间基础,应该单独保留。用于变换进和变换出此向量空间的矩阵是从这三个向量派生的。


您可以通过执行以下操作(伪代码)创建矩阵以从切线空间转换为对象空间:

mat3 (Tangent, Bitangent, Normal);

当然,您可以使用逆向从对象空间转到切线空间。Assimp 可能会生成(大致)正交基向量,因此逆向是保证存在的,并且在这种情况下可以表示为转置。

然而,切线

和双切线不能保证是正交的,因为可能存在纹理,并且两者都不一定垂直于法线。一些模型导入软件在输出 TBN 向量时执行正交化作为后处理步骤,并且大多数教程似乎假设这种关系始终存在。

切线

和双切线(也称为双法线)遵循与法线相同的规则。事实上,切线、双法线和法线形成了表面局部空间的底,可以用 3×3 矩阵表示。此空间通过模型视图矩阵(也称为法线矩阵)的逆转置进行转换。