简谈Normal

九霄
发布于

很多初学者在这个法线这个问题上存在很多困惑,所以让我们来讨论一下法线向量!

"法线"指的是某物面朝的方向。我们在着色器中使用法线向量来进行漫反射光照、镜面反射、边缘高亮等效果的计算。但是由于所有方向都是相对的,不同的效果需要不同的参考点或"空间"。

相对于屏幕的方向是视图空间(view space)。

相对于场景的方向是世界空间(world space)。

相对于网格的方向是物体空间(object space)。

相对于单个片段的方向是切线空间(tangent space)。

让我们看看它们在实践中是如何工作的。

我们可以通过将法线转化为颜色来可视化它,其中X变为红色,Y变为绿色,Z变为蓝色。这就是法线贴图的基本思想。然而,在着色器中处理法线时,它们通常是具有单位长度的向量,也就是说,值的范围可以介于-1和1之间(绝对值为1)。由于不存在负颜色的概念,为了使整个范围可见,我们需要将法线值压缩到0和1之间,使颜色中的0.5实际上对应向量中的0。这可以通过将值乘以0.5然后加上0.5来实现。因此,如果你使用取色器从下面的图像中提取颜色,要将该值转换回所代表的向量,你需要将其乘以2,然后减去1。在这个基础上,我们可以看看不同类型的法线向量是怎样的。

物体空间的法线

在这里,我们看到的是物体法线向量。请注意,当我改变视角以查看角色后面时,网格的背面是黄色的,而当我固定视角而旋转角色时,网格的背面仍然是黄色的。

切线空间法线

这里我们有切线法线向量(tangent normals)。这些法线向量与每次运行片段函数时要着色的网格部分有关。基本上,如果将网格比喻为行星,切线法线将与站在其上的人的视角相关。

通常,我们从法线贴图中获取切线法线。法线贴图是使用RGB存储XYZ的二维纹理。它们无论应用在网格的哪个部分上,都能以相同的方式工作,这是关键所在。如果它们与其他锚点相关联,除了预定角度外,它们就无法正常工作。大多数情况下,切线法线与世界法线相加,以获得更详细的光照效果,但切线法线经常单独用于视差偏移或视差遮挡映射。

世界空间法线

这里我们看到的是世界法线向量(world normals)。请注意,当我从场景中不同位置观察网格时,我们看到不同的颜色,但是当网格在原地旋转时,我们看到的颜色是相同的。世界法线是相对于场景的原点(游戏的"世界")的。

世界法线在将正在着色的对象与场景中的其他物体进行比较时非常有用,比如光源(这样我们可以确定哪些部分应该明亮,哪些部分应该在阴影中),或者观察方向(用于镜面反射、边缘高光等)时。

视图空间法线

这些是视图空间法线向量(view normals)。请注意,无论我的视角放置位置如何或物体的旋转如何,对象的颜色保持不变。这些值与屏幕锁定。

视图法线向量非常适用于凸出的外部轮廓、基于着色器的广告牌效果、在深度纹理不可用时的伪深度效果等。如果你习惯于在GLSL中进行射线行进(raymarching),那么这就是你在这种情况下使用的法线向量类型。

10
评论 2
收藏 1
  • Piccolo小助手
    感谢分享,棒棒哒!Piccolo社区欢迎你~
  • 御币Soft
    御币Soft
    感谢!这几张可视化图非常直观。另外补充一下在游戏开发中传入引擎的法线资源通常是切线法线tangent normals的形式,这是因为切线法线可以比较容易地在模型拉伸变形后计算出依然垂直于模型表面的新法线。而其他法线会在拉伸后变得和表面不垂直,无法正确计算光照。
    2