Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Opengl 法线映射,如何变换向量_Opengl_Glsl_Shader_Normals - Fatal编程技术网

Opengl 法线映射,如何变换向量

Opengl 法线映射,如何变换向量,opengl,glsl,shader,normals,Opengl,Glsl,Shader,Normals,在顶点着色器中,我们通常创建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矩阵:

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
    矩阵传递到片段着色器中,然后通过该矩阵变换从法线贴图读取的每个法线。这样我们就可以将这种法线转换为视图空间。
    • 这样我们可以在眼睛/相机空间中进行光线计算
  • 选项1似乎更快:我们在顶点着色器中有大多数变换,只有一个从法线贴图读取

    选项2要求通过TBN矩阵从法线贴图转换每个法线。但这似乎有点简单

    问题:

    哪种选择更好

    是否有任何性能损失?(也许纹理读取将“覆盖”进行矩阵变换的成本)


    哪个选项更常用?

    我现在就告诉你这一点-取决于你的应用程序,选项1甚至可能不可能

    在延迟着色图形引擎中,必须在片段着色器中计算光向量,这排除了选项1。当需要在延迟着色中进行照明时,您也无法保持TBN矩阵不变,因此在构建法线G缓冲区之前,您会将法线转换为世界空间或视图空间(这不再经常受到欢迎)(TBN矩阵的计算可以在顶点着色器中完成,并以
    平面mat3
    的形式传递给片段着色器)。然后使用基础对法线贴图进行采样,并将其写入世界空间

    根据经验,我可以告诉您,大牌图形引擎(如虚幻引擎4、CryEngine 3等)现在实际上在世界空间中进行照明。它们还使用延迟着色,因此对于这些引擎,您上面提出的两个选项都没有使用:)


    顺便说一下,如果您实际存储法线、副法线和切线向量,则会在顶点缓冲区中浪费空间。它们是正交向量空间的基向量,所以它们都是直角的。因此,可以通过取叉积来计算给定任意两个向量的第三个向量。此外,因为它们是直角的,并且应该已经被规格化,所以不需要规格化叉积的结果(回想一下,| a x b |=| a |*| b |*sin(a,b))。因此,这在顶点着色器中就足够了:


    这将使您在通往世界空间法线的道路上前进(这些天来,对于许多流行的后期处理效果来说,世界空间法线往往更有效)。如果要修改矩阵以生成视图空间法线,可能需要重新规范化矩阵。

    这个问题无法回答。答案将取决于许多因素,例如被插值的逐顶点参数的数量,相对于逐片段处理进行的逐顶点处理的数量,等等。好的,特别是性能不容易测量。。。但是视觉差异呢?正如我所看到的,这些解决方案应该是相等的?回答得很好!我只考虑了正向渲染,但延迟渲染现在更流行。-1:“它们是正交向量空间的基向量”不,它们不是。即使从切线计算双切线(这可能“足够好”,但实际上并不正确),切线和法线也不必垂直。记住:切线和双切线向量指向纹理坐标的模型空间方向。很好的一点,我忘记了在网格的法线平滑过程中,我将基向量正交化作为一个额外的处理步骤(我假设这是标准的做法)。在我的例子中,向量总是正交的,但正如你所说的,它们肯定不需要正交。通常,在构建切线时,我们会正交化TBN矩阵,所以这很好。但是,框架的惯用手可能仍然是错误的。解决这个问题的一个方法是将惯用手在切线的w坐标中压缩为∓1,然后将双切线乘以。另一个解决方案是激发美工人员。对于在顶点制作平均法线以近似平滑曲面的典型情况,切线和双切线实际上应该垂直于法线(但不相互垂直)。真实变化率向量位于切线平面(根据切线平面的定义)中,法线垂直于该平面(根据曲面法线的定义)。这些向量基于离散网格的近似值可能不在数值上的切面上,但可以使用Gram Schmidt非常轻松地解决这一问题。 // Normal and tangent should be orthogonal, so the cross-product // is also normalized - no need to re-normalize. vec3 binormal = cross (normal, tangent); TBN = mat3 (tangent, binormal, normal);