【问题标题】:Normal mapping, how to transform vectors法线映射,如何变换向量
【发布时间】:2013-08-09 08:27:48
【问题描述】:

在顶点着色器中我们通常会创建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);

这个矩阵将顶点从切线空间转换到眼睛/相机空间。

现在对于法线贴图(在正向渲染中完成),我们有两个选择:

  1. 逆tbn矩阵并变换light_vectorview_direction并将这些向量发送到片段着色器。之后,这些向量位于切线空间中。
    • 这样在片段着色器中我们只需要从法线贴图中读取法线。由于此类法线位于切线空间中(通过“定义”),因此它们与未转换的 light_vectorview_direction 匹配。
    • 这样我们在切线空间中进行光照计算。
  2. tbn 矩阵传递给片段着色器,然后通过该方法转换从法线贴图中读取的每个法线。这样我们就可以将这样的法线转换为视图空间。
    • 这样我们在眼睛/相机空间中进行光照计算

选项 1 似乎更快:我们在顶点着色器中进行了大部分转换,只有一个从法线贴图读取。

选项2需要将法线贴图中的每个法线通过TBN矩阵进行变换。不过好像简单了一点。

问题:

哪个选项更好?

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

哪个选项更常用?

【问题讨论】:

  • 无法按要求回答此问题。答案将取决于许多因素,例如被插值的每个顶点参数的数量、相对于每个片段处理的每个顶点处理量等等。
  • 好吧,尤其是性能不能轻易衡量...但是视觉差异呢?我认为这些解决方案应该是平等的?

标签: opengl glsl shader normals


【解决方案1】:

我现在就告诉你这么多 - 根据你的应用程序,选项 1 甚至可能都不可行。

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

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


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


   // 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);

这将使您走上通往世界空间法线的道路(对于当今许多流行的后期处理效果来说,这往往更有效)。如果您打算更改矩阵以生成视图空间法线,您可能必须重新规范化矩阵。

【讨论】:

  • 很好的答案!我只考虑前向渲染,但现在更流行的是延迟渲染。
  • -1: "它们是正交向量空间的基向量" 不,它们不是。即使您从切线计算双切线(可能“足够好”,但实际上并不正确),切线和法线也不必垂直。请记住:切线和双切线向量沿纹理坐标的模型空间方向指向。并且它们绝不需要与法线或彼此正交。
  • 很好,我忘记了在对网格进行正常平滑期间将基向量正交化作为附加处理步骤(我认为这是标准做法)。在我的情况下,向量总是正交的,但正如你所说,它们绝对不需要。
  • 通常,在构建切线时会正交化 TBN 矩阵,所以这很好。但是,框架的 惯用手 可能仍然是错误的。一种解决方案是将切线的 w 坐标中的手性打包为 ∓1,然后将双切线乘以该值。另一个解决方案是解雇你的艺术家。
  • 对于在顶点处平均法线以近似平滑曲面的典型情况,切线和双切线实际上应该垂直于法线(但不相互垂直)。真实的变化率矢量位于切平面(根据切平面的定义),法线垂直于该平面(根据表面法线的定义)。您对这些向量的基于离散网格的近似值可能不在数值上位于切平面内,但您可以使用 Gram-Schmidt 轻松解决此问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多