0

我正在使用 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 \
4

2 回答 2

4

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

通常,您不会单独将 Tangent、Bitangent 和 Normal 向量相乘。它们定义了你的向量空间基础,应该不理会。用于进出这个向量空间的矩阵就是从这三个向量中推导出来的。


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

mat3 (Tangent, Bitangent, Normal);

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

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

于 2013-10-30T22:49:18.093 回答
3

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

于 2013-10-30T21:19:27.473 回答