法线贴图 (Normal Map) 是一种凹凸贴图 (Bump Map)。它们是一种特殊的纹理,可让您将表面细节(如凹凸、凹槽和划痕)添加到模型,从而捕捉光线,就像由真实几何体表示一样。
Unity uses Y+ normal maps, sometimes known as OpenGL format.
例如,您可能希望显示一个表面,在表面上有凹槽和螺钉或铆钉,比如飞机机身。为实现此目的,一种方法是将这些细节建模为几何体,如下所示。
根据具体情况,将这些微小的细节建模为“真实”几何体通常并非一种好的思路。在右侧,您可以看到构成单个螺丝头的细节所需的多边形。在具有大量精细表面细节的大型模型上,这种方案需要绘制极大数量的多边形。为了避免这种情况,我们应使用法线贴图来表示精细的表面细节,而使用分辨率较低的多边形表面来表示模型的较大形状。
如果我们改用凹凸贴图来表示此细节,则表面几何体可以变得简单得多,并且细节将通过纹理呈现,用纹理来调节表面如何反射光。现代图形硬件可以非常快速地完成此过程。现在,金属表面可变为一个简单多边形平面,而螺钉、铆钉、凹槽和划痕将捕捉光线,并会因为纹理而显得有深度。
在现代游戏开发的美术制作流程中,美术师将使用他们的 3D 建模应用程序基于超高分辨率的源模型生成法线贴图。然后将法线贴图映射到可直接用于游戏的较低分辨率的模型版本,从而使用法线贴图渲染原始的高分辨率细节。
Bump mapping is a relatively old graphics technique, but is still one of the core methods required to create detailed realistic real-time graphics. Bump Maps are also commonly referred to as Normal Maps or Height Maps, however these terms have slightly different meanings which will be explained below.
To really explain how normal mapping works, we will first describe what a “normal” is, and how it is used in real-time lighting. Perhaps the most basic example would be a model where each surface polygon is lit simply according to the surface angles relative to the light. The surface angle can be represented as a line protruding in a perpendicular direction from the surface, and this direction (which is a vector) relative to the surface is called a “surface normal”, or simply, a normal.
在上图中,左圆柱体具有基本的平面着色,并且每个多边形根据其与光源的相对角度进行着色。每个多边形上的光照在多边形区域内保持恒定,因为该表面是平坦的。以下是显示了线框网格的同样两个圆柱体:
右侧的模型与左侧的模型具有相同数量的多边形,但是显示为平滑着色;多边形上的光照产生了曲面外观。为什么会这样?原因是用于反射光线的每个点处的表面法线沿着多边形的宽度逐渐变化,所以对于表面上的任何给定点,光反射表现为好像该表面是弯曲的而不是实际的平坦恒定多边形。
以 2D 图的形式查看时,平面着色圆柱体外侧的三个表面多边形将如下所示:
表面法线用橙色箭头表示。这些值用于计算光线如何从表面反射,所以您可以看到光线沿着每个多边形的长度具有相同响应,因为表面法线指向相同的方向。因此就会产生“平面着色”,这也是左圆柱体的多边形看起来有硬边的原因。
然而,对于平滑着色的圆柱体,表面法线在平面多边形上发生变化,如下所示:
法线方向在平面多边形表面上逐渐变化,因此表面上的着色产生了平滑曲线的印象(如绿线所示)。这不会影响网格的实际多边形性质,只会影响在平面表面上计算光照的方式。这种明显的曲面并不存在,以掠射角观察这些面时将揭示出平面多边形的真实性质,但从大多数视角看,圆柱体看起来具有平滑的曲面。
使用这种基本平滑着色时,实际上只根据每个顶点来存储确定法线方向的数据,因此该表面上的变化值是从一个顶点到下一个顶点之间进行插值的。在上图中,红色箭头表示每个顶点存储的法线方向,橙色箭头表示多边形区域上的内插法线方向的示例。
法线贴图使表面法线的这种修改更进一步,使用纹理来存储有关如何修改模型上的表面法线的信息。法线贴图是映射到模型表面的图像纹理,类似于常规颜色纹理,但法线贴图纹理中的每个像素(称为纹理像素)表示平面法线方向与平面(或平滑插值)多边形“真实”表面法线之间的偏差。
该图再次以 2D 形式表示 3D 模型的表面上的三个多边形,每个橙色箭头对应于法线贴图纹理中的像素。下面的是法线贴图纹理的单像素切片。在中心位置,您可以看到法线已被修改,在多边形的表面上呈现出几个凹凸的外观。因为这些修改过的法线将用于光照计算,所以这些凹凸只会由于表面上的光照显示情况而变得明显。
原始法线贴图文件中可见的颜色通常具有蓝色色调,并且不包含任何实际的浅色或深色着色,这是因为这些颜色本身不打算按原样显示。实际上,每个纹理像素的 RGB 值表示方向矢量的 X、Y 和 Z 值,并作为对多边形表面的基本内插平滑法线的修改而应用。
This is a simple normal map, containing the bump information for some raised rectangles and text. This normal map can be imported into Unity and placed into Normal Map slot of the Standard Shader. When combined in a material with a colour map (the Albedo map) and applied to the surface of the cylinder mesh above, the result looks like this:
同样,这不会影响网格的实际多边形性质,只会影响在表面上计算光照的方式。表面上明显凸起的字幕和形状并不存在,以掠射角观察这些面时将揭示出平面表面的真实性质,但从大多数视角看,圆柱体现在看起来具有从表面凸起的浮雕细节。
法线贴图通常与模型或纹理一起由 3D 或纹理美术师制作而成,并且通常镜像出反照率贴图的布局和内容。有时,法线贴图是手工制作的,有时是从 3D 应用程序中渲染出来的。
如何从 3D 应用程序渲染法线贴图超出了本文档的范畴,但基本概念是 3D 美术师将制作模型的两个版本:一个以多边形包含所有细节的高分辨率模型,还有一个可立即用于游戏的低分辨率模型。高分辨率模型的细节化程度太高,无法在游戏中以最佳状态运行(网格中有太多三角形),但需要在 3D 建模应用程序中用于生成法线贴图。然后,低分辨率版本的模型可以忽略非常精细的几何细节,这些细节现在已存储在法线贴图中,因此可以使用法线贴图来渲染该模型。一个典型的用例就是显示角色服装上的折痕、按钮、搭扣和接缝的凹凸细节。
有一些软件包可以分析常规摄影纹理中的光照,并从中提取法线贴图。为此,需要假设原始纹理从恒定方向接受光照,还要分析明暗区域并假设其与倾斜表面对应。但是,当实际使用凹凸贴图时,您需要确保反照率纹理没有来自图像中任何特定方向的光线(理想情况下应表示完全没有光线的表面的颜色),因为 Unity 将根据光线方向、曲面角度和凹凸贴图信息计算出光照信息。
下面提供了两个例子,一个是简单的重复石墙纹理及其对应的法线贴图,另一个是角色的纹理图集及其对应的法线贴图:
法线贴图和高度贴图都是凹凸贴图的类型。二者都包含一些数据用于表示较简单多边形网格的表面上的明显细节,但各自却以不同的方式存储这些数据。
在上方左侧,您可以看到用于石墙凹凸贴图的高度贴图。高度贴图是一种简单的黑白纹理,其中每个像素表示该点在表面上看起来应该凸起的程度。像素颜色越白,该区域看起来越高。
法线贴图是 RGB 纹理,其中每个像素表示表面看起来应该面向的方向的差异(相对于其未经修改的表面法线)。由于矢量存储在 RGB 值中的方式,这些纹理往往为蓝紫色调。
Modern real-time 3D graphics hardware rely on Normal Maps, because they contain the vectors required to modify how light should appear to bounce of the surface. Unity can also accept Height Maps for bump mapping, but they must be converted to Normal Maps on import in order to use them.
了解这一点对于使用法线贴图并不重要!跳过这一段是可以的。但是,如果真的想知道,请参考以下信息:RGB 颜色值用于存储矢量的 X、Y、Z 方向,其中的 Z 为“向上”(与 Unity 通常使用 Y 作为“向上”的惯例相反)。此外,纹理中的值视为经过减半处理,即添加了 0.5 的系数。这样就能存储所有方向的矢量。因此,为了将 RGB 颜色转换为矢量方向,必须乘以 2,然后减去 1。例如,RGB 值 (0.5, 0.5, 1) 或十六进制的 #8080FF 将得到矢量 (0,0,1),这便是用于法线贴图的“向上”,并表示模型表面没有变化。这就是您在此页面前面的法线贴图“示例”的平面区域中看到的颜色。
一个 (0.43, 0.91, 0.80) 值将得出 (–0.14, 0.82, 0.6) 矢量,这是对表面的大幅修改。在石墙法线贴图的明亮青色区域中一些石头边缘可以看到这样的颜色。最终结果是,这些边缘按照非常不同的与石头较平坦面的角度捕捉光线。
法线贴图
像往常一样,可通过将纹理文件放入 Assets 文件夹的方式导入法线贴图。但是,需要告诉 Unity,此纹理为法线贴图。为此,可在导入检视面板 (Inspector) 设置中将“Texture Type”设置更改为“Normal Map”。
要将黑白高度贴图作为法线贴图导入,除了需要选中“Create from Greyscale”选项外,过程几乎完全相同。
选中“Create From Greyscale”后,检视面板中将显示 Bumpiness 滑动条。从高度贴图中的高度进行转换时,可使用此滑动条来控制法线贴图中的角度剧烈程度。较低的凹凸值意味着,即使高度贴图中的鲜明对比度也会转换为平缓的角度和凹凸。较高的值会产生夸张的凹凸和对凹凸的高对比度光照响应。
在资源中放入法线贴图后,可将其放入检视面板中的材质 Normal Map 字段。标准着色器有一个 Normal Map 字段,许多较旧的旧版着色器也支持法线贴图。
如果导入了法线贴图或高度贴图,但未将其标记为法线贴图(通过选择 Texture Type: Normal Map,如上所述),材质检视面板将发出有关此问题的警告并提供修复此问题的解决方案,如下所示:
单击“Fix Now”与在纹理检视面板设置中选择 Texture Type: Normal Map 具有相同的效果。如果您的纹理确实是发现地图,此操作将起作用。但是,如果是灰度高度贴图,系统不会自动检测到这一情况,因此对于高度图,必须始终在纹理的 Inspector 窗口中选中“Create from Greyscale”选项。
您可能还注意到,标准着色器的材质检视面板下方较远位置还有第二个 Normal Map 字段。此选项允许您使用额外的法线贴图来创建额外的细节。您可以使用与常规 Normal Map 字段相同的方式将法线贴图添加到此字段中,但此处的意图是您应当使用不同的平铺比例或频率,从而使两个法线贴图以不同的比例一起生成高细节级别。例如,常规法线贴图可能定义墙壁或车辆上的镶板细节,并使用面板边缘的凹槽。辅助法线贴图可为表面上的划痕和磨损提供非常精细的凹凸细节,因此能够使用基础法线贴图的比例的 5 至 10 倍进行平铺。这些细节可能非常精细,只有仔细检查时才能看到。要在基础法线贴图上有这么多细节,基础法线贴图必须非常大,但是通过将二者放在不同比例下,可使用两个相对较小的法线贴图纹理来实现较高的整体细节级别。