Unity Shader - Normal map (Bump mapping) 法线贴图(凹凸映射)

目录:Unity Shader - 知识点目录(先占位,后续持续更新)
原文:Normal map (Bump mapping)
版本:2019.1

Normal map (Bump mapping)

在这里插入图片描述
Normal maps(法线贴图)是Bump Map(凹凸贴图)类型的其一。它们是特殊的纹理,允许你给以个模型添加表面细节的凹、凸、抓痕,这样表现的就像真实的几何体效果。

例如,你想给一个表面添加凸出来的螺丝,就像飞机钢板。下面是一种方法:直接建模的方式(哪些螺丝都是实际的模型)。
A sheet of aircraft metal with details modeled as real geometry.
飞机钢板的金属,以真实几何体来显示细节。

依情况而定,使用如此微小细节的真实模型来实现不是一种好的方式。上图右边,你可以看看到为了实现一个螺丝而需要的多边形。一个高模表面会有很多细节,但同时又需要绘制非常多的多边形。为了避免这类问题,我们将使用一张高精度的法线贴图(一般从模型烘焙出来)映射在低模来显示表面的细节。

使用bump map(凹凸贴图)来程序细节,这将会让几何体变得更精简,表面的光照反射将可以调节纹理来呈现。这种方式在现代的图形硬件中可以处理得非常的快。你的金属表面可以是一个低模的平坦面,而螺丝,凹凸,抓痕都可以呈现出光效交互效果,因为使用了法线贴图。
The screws, grooves and scratches are defined in a normalmap, which modifies how light reflects off the surface of this low-poly plane, giving the impression of 3D detail. As well as the rivets and screws, a texture allows us to include far more detail like subtle bumps and scratches.
螺丝,凹凸,抓痕都定义在一张法线,在可低模中控制表面光照反射,来提升3D模型的视觉效果。

在现代游戏开发的美术工作流中,美术同学可以使用3D建模软件以高模来生成normal maps(法线贴图)。运行时我们将法线映射到低模,以此我们可以得到低模多边形但拥有了高模的表面效果。

How to create and use Bump Mpas

如何创建和使用凹凸贴图

凹凸贴图是相对老的技术了,但它是实时真实渲染中提升渲染细节的核心手段。Bump Maps通常也叫Normal Maps(法线贴图)或是Height Maps(高度图),但是他们还是稍微有些不一样,请往下面。

What are Surface Normals?

什么是表面法线?

解析说明normal mapping(法线映射)是怎么工作的,我们首先了解,什么叫"normal"(法线),以及实时光照中怎么使用。最基础的例子:一个模型上的每个多边形表面的光效,都是对应着该表面相对光源位置的角度来计算的。表面的角度可以用一条垂直于表面方向的线来代表,这条线的方向(是个向量)该表面我们称之为"surface normal"(表面法线),或是简称:normal(法线)。
Two 12-sided cylinders, on the left with flat shading, and on the right with smoothed shading
两个12面数的圆柱体,左边的是flat(平坦法线)的着色,右边的是smoothed(平滑法线)着色

上图中,左边的圆柱体使用基础的flat着色,每个多边形都根据法线与光源的相对角度来着色。每个多边形的光效都一样,因为这是使用flat着色(平坦着色算法)。两个圆柱体,显示边框:
Two 12-sided cylinders, on the left with flat shading, and on the right with smoothed shading
两个12面数的圆柱体,左边的是flat(平坦法线)的着色,右边的是smoothed(平滑法线)着色

右边的模型和左变得多边形数量一样多,但右边的显示多边形表面光阴光滑很多。为啥酱紫?这是因为每个光栅点上的surface normal(表面法线)都是在多个顶点间做了法线渐变过渡处理,所以表面上任意一点,他的光效反弹的表面法线都是渐变的平滑的,而不是以一个多边形表面决定所有决定该面所有法线方向。

以2D图解说明,在三个多边形表面上的flat-shaded(平坦着色)就像这样:
Flat shading on three polygons, viewed as a 2D diagram
三多边形的Flat着色,以2D图解显示

表面法线以橙色箭头显示。这是用于计算表面反射光源效果使用的,每个多边形的表面反射光源肯定是一样的,因为每个表面法线都是相同的方向。因此才叫"flat shading",所以左边圆柱体多边形显示光阴过渡都是硬边。(所谓硬:过渡不平滑,很生硬)

平滑着色的圆柱体与平坦着色不一样,下图:
Smooth shading on three polygons, viewed as a 2D diagram
以2D图解显示,平滑着色的三多边形

多边形上的表面法线都是渐变的过渡,以平滑表面法线过渡,提升了着色表面曲线显示效果(图中绿线)。这不会影响网格多边形,仅仅是影响在该表面中光照计算的效果。这个平滑的表面不是真实存在的,你可以从圆柱体,Top view(定视图),Bottom view(底视图)看到多边形的表面其实还是平坦的,只是大多数角度看过去是平滑的表面。

使用这种平滑的着色,法线数据是存于每个vertex(顶点)的,所以改变一个顶点的法线数据将会影响周围临近顶点的表面法线差值过渡效果。在上图中,红色角度代表存储在每个顶点的法线方向,橙色代表的是多边形的临近顶点的差值法线方向。

What is Normal mapping?

什么是法线映射?

法线映射存储着表面法线的修改信息,就是使用一张纹理来存储模型表面法线如何修改的信息。一张法线贴图其实就一张图片,此图映射着模型的表面信息,就像常规的颜色纹理,然而法线贴图中的每个像素(称为:纹素)代表着表面法线的偏移信息,与真实的平坦表面法线很不相同(使用差值过渡)。
Normal mapping across three polygons, viewed as a 2D diagram
以2D图解显示,三多边形的法线映射

此图解中,以2D显示模型三多边形表面,每个橙色箭头对应着法线贴图中一个像素的映射数据。图中下面的像素条,就是法线映射纹理中单个像素切片的内容。在中间那段,你可以看到法线被修改了,这些法线数据就影响多边形表面的凹凸效果。这些凹凸想过只有在光照到表面是,才会看到,因为修改的法线信息用于光照计算用的。

这些源法线贴图一般颜色都是偏蓝色的色调,且不含任何的光影信息,这是因为这些颜色本身不用于像普通文理直接显示纹路用。而是,每个纹素的RGB代表着X,Y,Z的向量,然后应用于多边形上的表面法线的差值平滑过渡。
An example normal map texture
法线贴图纹理的例子

这是个简单的法线贴图,包含了矩形和文本的凹凸信息。这个法线贴图可以导入Unity后设置在使用了Standard Shader的材质中的法线贴图槽位中。当材质中加入了颜色贴图(Albedo贴图)并将法线贴图应用到上面的圆柱体中,结果如下:
The example normal map applied to the surface of the cylinder mesh used above
上面的圆柱体应用了法线贴图的例子

再次提醒,这不会影响原来真实的网格,仅仅影响表面上的光照效果的计算。这表面上的文字和矩形的凹凸效果其实不是真实存在的,你可以种模型的侧边看到真实的表面(真实的表面:还是平坦的),然而大多数的视觉角度看圆柱体都会表面浮雕效果的细节。

How do i get or make normal maps?

该如何获得或制作这样的法线贴图呢?

通常,法线贴图是由美术同学使用3D软件和模型一起生成的,且多数是你从Albedo贴图中复制出来调整的。有时是手动画的,有时是中3D软件中渲染出来的。

如何从3D软件中渲染出法线,这超出了我们要讲的内容范围,3D美术同学将会导出两个版本的模型 - 高精度模型(高模)包含了所有多边形细节,而低模是给游戏运行时准备的。高精度模型因细节太多而不能在游戏中优化(网格太多三角面),只是用于3D建模软件生成法线贴图用的。低模则省略了很多几何体的细节,现在都存在了法线贴图中,所以可以使用法线贴图来渲染。典型的例子是在角色上的衣服显示皱纹,纽扣,接缝处的效果。

还有一些软件可以分析一整照片纹理,并从中提取出一张法线贴图。假设源纹理是带有一个方向光的光照信息,亮的与暗的区域假设就对应着表面的角度。然而,在使用bump map(凹凸贴图)时,确保你的Albedo纹理是不含光照信息的,理想的就仅含表面颜色信息而不含光照信息,因为光照信息将会在Unity中,以光源方向,表面角度和凹凸信息来计算的。

这有两个例子,一个是简单的重复的石墙纹理和对应着的法线贴图,另个是角色纹理集对应的法线贴图:
A stone wall texture and its corresponding normal map texture
石墙纹理和对应的法线纹理
A character texture atlas, and its corresponding normal map texture atlas
角色纹理集合对应的法线贴图集

What’s the difference between Bump Maps, Normal Maps and Height Maps?

Bump Maps, Normal Maps和Height Maps的区别?

Normal Maps(法线贴图)和Height Maps(高度贴图)都是属于Bump Map(凹凸贴图)。它们都包含了代表简模多边形表面的细节数据,但它们存储数据的方式不一样。
On the left, a height map for bump mapping a stone wall. On the right, a normal map for bump mapping a stone wall.
左边的是石墙凹凸贴图的高度贴图。右边的是石墙凹凸贴图的法线贴图。

在上面,左边的你可以看到石墙的凹凸映射的高度贴图。一张高度贴图是简单的黑白图,每个像素代表着表面应该提升多少(负数代表下降)的量。越白的像素颜色,对应着提升的更高。

另一张法线贴图是RGB纹理,每个像素代表着表面的不同的方向,都是相对于没有修改表面数据的值来存储的。这些纹理都偏蓝紫色调,因为RGB值存储的是向量值。

现代的3D图形硬件都会使用Normal Maps,因为它们包含了表面如何反射光线的法线向量调整值。Unity也接受Height Maps来作为Bump Mapping,为了使用这些贴图,必须在导入纹理时设置转换成Nomral Maps类型的纹理。

Why the bluey-purple colours?

为何是偏蓝紫色呢?

注意着不是使用法线贴图的必要内容。如果需要时可以跳过的部分。然而,如果你真想了解:RGB颜色用于存储X,Y,Z方向向量,Z表达上"up"(向上:与Unity中的Y向上不一样)。另外,纹理上的值都从0.5为初始值,这样就可以存储所有的向量方向了(因为0位初始值得话,那么方向偏移将都指定正区间的,而中0.5定为初始值,小于0.5都是负区间值,大于就是正区间值,这样,3D空间中的方向都可以指定了,但是还是与精度相关,这里就不纠结了)。因为要将RGB转化为一个向量方向,你必须先x2,在减1。例如,一个RGB(0.5,0.5,1)或是#8080FF(16进制)对应向量结果是:(0,0,1),该向量是"up"(向上)的法线映射,代表着模型表面的法线方向没有偏移。这就是你在之前例子中看到的平坦区域的颜色。
A normal map using only #8080FF, which translates to a normal vector of 0,0,1 or “straight up”. This applies no modification to the surface normal of the polygon, and therefore produces no change to the lighting. Any pixels which are different to this colour results in a vectors that point in a different direction - which therefore modify the angle that is used to calculate light bounce at that point.
一张全为#8080FF数据的法线贴图,转化为向量就是0,0,1。这对于多边形的表面法线来说是没有修改的,因此不会对光照有变化。任意一个不同于这颜色的像素都意味着该点有不一样的方向,该点在计算光照反弹时可用该点对应的方向偏移值更改表面法线角度。

值为(0.43, 0.91, 0.80)将得到(-0.14, 0.82, 0.6)的向量,这将把表面法线修改得相当陡。这个颜色对应着石墙中那些在石头之间顶部比较明亮的区域。这会让石头边缘的光源计算非常不同于平坦表面的效果。
The bright cyan areas in the normalmap for these stones show a steep modification to the polygon’s surface normals at the top edge of each stone, causing them to catch the light at the correct angle.
A stone wall with no bumpmap effect. The edges and facets of the rock do not catch the directional sun light in the scene.
没有凹凸贴图效果的石墙。

The same stone wall with bumpmapping applied. The edges of the stones facing the sun reflect the directional sun light very differently to the faces of the stones, and the edges facing away.
同样的石墙,但这个是带有凹凸贴图应用的。石头表面反射太阳光都不相同。
The same bumpmapped stone wall, in a different lighting scenario. A point light torch illuminates the stones. Each pixel of the stone wall is lit according to how the light hits the angle of the base model (the polygon), adjusted by the vectors in the normal maps. Therefore pixels facing the light are bright, and pixels facing away from the light are darker, or in shadow.
同样是应用了凹凸贴图的石墙,但灯光不同的场景。一个点光源的火炬照亮着使用。石墙上的每个光栅像素光照计算都是根据法线贴图向量修改了模型表面与光源方向进行的。因此法线朝向向光源的都亮起来了,反之则越来越暗,甚至都基本是阴影中。

How to import and use Normal Maps and Height Maps

如何导入和使用法线贴图和高度贴图

法线贴图放到项目中的Assets文件夹下就能导入。然而你需要告诉Unity,这是张法线贴图。你可以在Inspector更改"Texture Type"设置为"Normal Map"。
在这里插入图片描述
导入黑白的高度贴图与法线贴图基本一样,需要可勾选"Create from Greyscale"选项。
在这里插入图片描述
勾上"Create From Greyscale"选项后,Bumpiness在法线贴图中控制法线倾斜度,在高度贴图中使用将控制高度系数。底bumpiness数值是意味着凹凸效果没那么强。反之很强。
Low and High Bumpiness settings when importing a height map as a normal map, and the resulting effect on the model.
Bumpiness数值的底和高,在模型上的效果。

你可以将你的法线贴图资源设置到材质中的Inspector的法线贴图槽位中。Standard Shader有一个法线槽位,需要旧版本的shader也支持法线贴图。
Placing a normal map texture into the correct slot in a material using the Standard Shader
使用Standard Shader,设置了一个法线贴图文理在正确的材质槽位中

如果你导入了一张法线贴图或是高度贴图,然后没有将其设置为法线贴图(之前提及的Texture Type: Normal Map),材质的Inspector将会警告和提示修复,如下:
The “Fix Now” warning appears when trying to use a normalmap that has not been marked as such in the inspector.
"Fix Now"警告按钮将会在法线槽位设置了Texture Type不是Normal Map的纹理时出现

点击"Fix Now"效果将和手动设置Texture Type:Normal Map效果一致。如果你设置的纹理是个法线贴图类型的纹理将能正常工作。然而,如果是灰度图的高度贴图,这将不会自动检测并提示,所以高度贴图你必须将"Create from Greyscale"选项勾上。

Secondary Normal Maps

你也许留意到Standard Shader材质Inspector下方有个第二个Normal Map槽位。这将允许你使用另一张法线贴图来创建额外的细节。例如,你可以在第一张法线贴图控制车辆上的凹凸细节,而第二张法线贴图用于控制车上的刮痕,将第二张法线贴图的效果放大一些刮痕就更明显了,这将可以提高更多的表面细节。这样法线贴图分层控制细节,可以减少单个法线贴图大小的,也可以用于控制细节开光(只要不设置就默认关闭)。

猜你喜欢

转载自blog.csdn.net/linjf520/article/details/91407398