很多时候,向规则的事物里添加一些“杂乱无章”的效果往往会有意想不到的效果。而这些“杂乱无章”的效果来源就是噪声。在本节中,我们将会学习如何使用噪声来模拟火焰消融、波光粼粼、云雾飘渺等各种特效。
1 消融效果
消融 (dissolve) 效果常见于游戏中的角色死亡、地图烧毁等效果。在这些效果中,消融往往从不同的区域开始,并向看似随机的方向扩张,最后整个物体都将消失不见。消融效果的原理非常简单,概括来说就是噪声纹理+透明度测试。我们使用对噪声纹理采样的结果和某个控制消融程度的阈值比较,如果小于阈值,就使用 clip 函数把它对应的像素裁剪掉,这些部分就对应了图中被“烧毁”的区域。而镂空区域边缘的烧焦效果则是将两种颜色混合,再用 pow 函数处理后,与原纹理颜色混合后的结果。
1 | Shader "Unity Shaders Book/Chapter 15/Dissolve" { |
接下来编写一个 cs 脚本来随着时间控制材质的 _BurnAmount 属性:
1 | using UnityEngine; |
最终的效果如下:
2 水波效果
在模拟实时水面的过程中,我们往往也会使用噪声纹理。此时,噪声纹理通常会用作一个高度图,以不断修改水面的法线方向。为了模拟水不断流动的效果,我们会使用和时间相关的变量来对噪声纹理进行采样,当得到法线信息后,再进行正常的反射+折射计算,得到最后的水面波动效果。在本节中,我们将会使用一个由噪声纹理得到的法线贴图,实现一个包含菲涅耳反射的水面效果。
首先我们定义一个平面作为水面,类似于之前我们利用反射和折射实现透明玻璃的效果,我们使用一张立方体纹理 (Cubemap) 作为环境纹理,模拟反射;使用 GrabPass 来获取当前屏幕的渲染纹理,并使用切线空间下的法线方向对像素的屏幕坐标进行偏移,再使用该坐标对渲染纹理进行屏幕采样,从而模拟近似的折射效果。但与之前的实现不同,水波的法线纹理是由一张噪声纹理生成而得,而且会随着时间不断平移变化,模拟波光粼粼的效果。此外,我们没有使用一个定值来混合反射和折射的颜色,而是使用之前提到的菲涅耳系数来动态决定混合系数,我们使用如下公式计算菲涅尔系数:
$$
fresnel = pow(1-max(0,\vec v ·\vec n),4)
$$
其中 $\vec v$ 和 $\vec n$ 分别对应了视角方向和法线方向,他们之间的夹角越小,得到的菲涅尔系数就越小,反射越弱,折射越强。
1 | // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' |
为了用噪声纹理生成法线纹理,我们在该噪声纹理的属性面板中把纹理类型改为 Normal map,并勾选 Create from grayscale,使其从灰度值生成法线纹理:
渲染效果如下:
此时我们的视线方向和水面法线夹角大,反射强,折射弱,我们更容易看到水面的颜色,而水面的颜色是环境反射颜色和水波本身颜色的结合;当我们减小视线方向和水面法线夹角时,效果如下:
此时反射弱,折射强,我们不容易看到水面本身的颜色,更容易透过水面看到折射后的扭曲的地面。
3 再谈全局雾效
我们之前学习了如何使用深度纹理来实现一种基于屏幕后处理的全局雾效。我们由深度纹理重建每个像素在世界空间下的位置,再使用一个基于高度的公式来计算雾效的混合系数,最后使用该系数来混合雾的颜色和原屏幕颜色。这样实现的效果在同一高度下雾的浓度是相同的,但很多时候我们希望可以模拟一种不均匀的雾效,同时让雾不断飘动,使雾看起来更加飘渺,这就可以通过使用噪声纹理来实现。
大部分代码和之前的全局雾效一样,只不过加入了噪声相关的参数和属性,并在 Shader 的片元着色器中对雾效混合系数的计算添加了噪声的影响。
首先是 cs 脚本:
1 | using UnityEngine; |
然后是 Shader:
1 | Shader "Unity Shaders Book/Chapter 15/Fog With Noise" { |
渲染效果如下:
4 噪声纹理从何而来
噪声纹理一般属于程序纹理,它们都是由计算机利用某些算法生成的。Perlin 噪声和Worley 噪声是两种最常使用的噪声类型,上面的全局雾效使用的噪声纹理就是由 Perlin 噪声生成而来。 Perlin 噪声可以用于生成更自然的噪声纹理,而 Worley 噪声则通常用于模拟诸如石头、水、纸张等多孔噪声。更多关于噪声纹理的内容可以查看 Understanding Perlin Noise 以及其他博客。