最近一直在研究法线映射的问题,所以通过Carlos Lemos的一系列关于法线的文章来加强一下大家的理解。
多年来,我一直在努力理解法线映射以及在使用法线映射过程中通常出现的问题。我发现大多数的解释通常都过于技术性、不完整或难以理解,不符合我的口味,所以我决定尝试一下,解释一下我收集到的信息。
1法线(Normals)
最初的3D模型看起来像这样:
这很好,但它有一个明显的局限性:它看起来太多边面了。
第一个明显的解决方案是添加更多多边形,使曲面更加均匀和平滑,直到多边形看起来像一个单一的平滑曲面。事实证明,这需要大量的多边形,才能使球体等曲面看起来平滑。
需要另一种解决方案,于是法线的概念就诞生了。
让我们从一个多边形的中心画一条线,完全垂直于它的表面。我们将这一条线称为一个令人困惑的名字:法线。该法线的目的是控制曲面指向的位置,以便当光线从该曲面反弹时,它将使用该法线计算产生的反弹。当光线击中多边形时,我们比较光线与多边形法线的角度。光线将使用与法线方向相同的角度反弹回来:
换句话说,光线反弹相对于多边形法线来说是对称的。这就是大多数反弹在现实世界中的工作方式。默认情况下,所有多边形都会反射完全垂直于其曲面的光线(就像在现实生活中那样),因为默认情况下,多边形法线是;垂直于多边形表面。如果法线中有间隙,我们会将它们视为单独的曲面,因为光线会在一个方向或另一个方向上反弹。
现在,如果我们有两个连接的面,我们可以告诉计算机平滑一个多边形法线到另一个多边形法线之间的过渡,使法线逐渐与最近的多边形法线对齐。这样,当光线直接击中一个多边形的中心时,光线将沿着法线方向直线反弹。但是在面之间,法线方向是平滑的,弯曲了光的反弹方式。
我们将把过渡视为一个单一的表面,因为光线将以平滑的方式从一个多边形反弹到另一个多边形,并且不会有间隙。实际上,光线从这些多边形平滑反弹,效果就会像它有大量多边形时一样。
这就是我们在设置光滑组(3ds Max、Blender)或将边设置为软硬边(Modo、Maya)时所控制的:我们告诉程序哪些面之间的过渡需要平滑,哪些面之间的过渡需要硬转折。
下面是同一个球体的比较,它具有坚硬和平滑的过渡,都具有288个多边形:
我们可以设置一个类似于长方体的东西,使其所有顶点都具有平均法线。3D软件将尝试平滑其表面,使其看起来像一个单一的平滑表面。这对于3D程序来说非常有意义,但它看起来非常奇怪,因为我们有一些东西应该有几个单独的表面(比如盒子的每个面),但程序试图将其显示为一个单一的光滑表面。、
这就是为什么我们在3D软件中通常有一个平滑角度的设置:如果我们有两个连接的多边形的角度大于此平滑角度,它们的过渡将是软的,而连接的多边形的角度小于平滑角度将是硬的。这样,曲面之间的极端角度将显示为不同的面,就像在现实世界中一样。
因此,我们在模型中使用法线来控制面之间的过渡,但我们可以更进一步。
因为我们正在改变光从物体反弹的方式,所以我们也可以让一个非常简单的物体像一个复杂的物体那样反弹光。这是一张法线贴图。我们使用贴图来弯曲从3D对象反射的光的方向,使其看起来比实际情况更复杂。
一个现实生活中的例子是那些当年买薯片赠送的全息图(至少在西班牙是这样)。它们是完全平坦的,但反射光的方式与3D对象类似,使其看起来比实际情况更复杂。在3D世界中,这些效果更好,但仍有一些局限性(因为曲面仍然是平的)。
2顶点法线(Vertex Normals)
虽然我们确实使用多边形的法线来处理其他一些事情,但实际上我们并没有使用多边形法线来控制模型曲面的平滑。而我们是通过使用顶点法线来控制法线的平滑。这基本上是相同的想法,但有点复杂。
每个顶点都可以关联一个或多个法线。如果它有一条法线,我们称之为平均顶点法线(averaged vertex normal),如果它有多条法线,我们称之为分割顶点法线(split vertex normal)。
让我们用一条边来连接两个多边形。如果两个面之间的过渡是平滑的(我们在Maya/Modo中将其设置为“软边”,或者在Max/Blender中两者都具有相同的光滑组),则每个顶点都有一条法线,这是多边形法线的平均值(这就是为什么它被称为“平均顶点法线”)。重要提示:目前来讲,每个3D程序都使用自己的方法计算平均顶点法线,这意味着在一个程序上计算的法线贴图在另一个3D程序中可能看起来完全不同。我将在这份分享的第二部分对此进行详细解释。
如果过渡是硬的(硬边或光滑组不同),每个顶点都有几个法线:每个连接的顶点一个法线,并与其法线对齐。这会在法线中留下一个间隙,看起来像两个不同的曲面。这就是我们所说的分裂顶点法线。
正如你可能猜到的,如果我们想控制法线贴图,控制顶点法线是至关重要的。幸运的是,我们真的不需要直接修改法线,甚至不需要看到它们,但知道这是如何工作的将有助于我们理解为什么我们会这样做,并更多地解释我们可能看到的问题。
3烘焙法线贴图
在烘焙法线贴图时,我们基本上是告诉烘焙程序修改低多边形法线遵循的方向,以便匹配高多边形模型的方向;所以导致lowpoly模型可以像highpoly模型一样反射光线。所有这些信息都存储在称为法线贴图的纹理上。让我们来看一个例子。
假设我们有这样一个lowpoly。一个具有4个顶点和一个UV集的平面,我们的烘焙程序将使用该平面创建法线贴图。
它必须从这个highpoly接收法线信息,它的法线更复杂。
请记住,我们只是传递法线信息,所以UV、材质、拓扑、变换等完全不相关。经验法则:如果你的highpoly看起来很好,这意味着它的法线很好,应该用于烘焙足够好。
我们的烘焙程序将采用lowpoly,并按照lowpoly的法线方向投射光线(这就是我们需要控制lowpoly法线的原因)。这些光线的长度有限,以避免从很远的面(通常称为烘焙距离或cage包裹器距离)获取法线信息。当这些光线与高多边形碰撞时,烘焙程序会计算如何弯曲这些光线,使其遵循与高多边形相同的法线方向,并将该信息存储到法线贴图中。
下面是这个例子的烘焙结果:
我们的引擎使用一种纹理来修改lowpoly法线,因此光线会在这个lowpoly模型上反弹,就像它是highpoly版本一样。请记住,这是一种纹理,不会影响lowpoly的轮廓剪影(如果光线未击中模型,则无法修改光线从模型反弹的方式)。
4法线可以存储为贴图
虽然可以通过查看法线贴图来读取了解我们的lightpoly,但法线贴图显然不是规则纹理。这是因为它们不携带颜色信息,而是法线信息。这也意味着法线贴图不应被视为常规纹理,我们能看出来它们具有特殊的压缩和gamma校正设置。
可以将法线贴图视为一组3个灰度纹理,存储在单个图像上:
第一幅图像告诉引擎,当从右侧照亮时,该模型应该如何反弹灯光,并将其存储在法线贴图纹理的红色通道中。
第二幅图像告诉引擎,当从下方照亮时,模型应该如何反弹灯光,并将其存储在法线贴图纹理的绿色通道中。有些程序使用上面而不是下面,所以我们可以使用“left-handed”和“right-handed”法线贴图,这可能会导致一些问题,我们将在后面看到。
第三个图像告诉引擎,当从前面照亮时,模型应该如何反弹灯光,并存储在法线贴图纹理的蓝色通道中。由于大多数东西从正面发光时看起来都是白色的,所以法线贴图通常看起来是蓝色的。
当我们将所有三幅图像合并到一幅图像上时,我们得到了一幅法线贴图。请记住,这个解释并非100%准确,但它有望帮助您理解法线贴图中的信息,并更好地理解它的作用。
5总结
法线是用来定义光线如何从曲面反弹的向量。它们可以用于控制面之间的过渡(通过平均连接顶点的法线以进行平滑过渡,或分割顶点以进行硬转折过渡),但它们也可以重新定向,以使低多边形模型像更复杂的模型那样反弹灯光。该信息存储在图像的3个单独通道中,3D程序读取该信息,以了解模型表面应朝哪个方向看。
现在我们已经大致了解了法线是什么,以及法线贴图是如何工作的,下一篇章将讲述如何把这些细节从高多边形烘焙到低多边形去。
,