原文:
White Noise
Summary
在很多效果中需要用到随机数来生成纹理图案、又或者其他东西。下面我们以白色噪声图为例,来展示随机数用途。后面我们还会介绍其他使用随机数生成的具有一定组织结构的图案,例如泊林噪声图、和vornoi
噪声图。本文是采用表面着色器来实现的,所以建议你先阅读我关于表面着色器的介绍。
Scalar noise from 3d Input
在着色器中,我们很难将上一帧画面的数据保存到下一帧,因此我们的随机数必须依赖于着色器中可访问的参数,这样无论什么时候我们都可以得到固定的随机值。这里我们使用世界坐标来生成随机值。当然如果你想让你的噪声图动起来,可以引入时间变量。
因此我们需要在表面着色器的输入结构中加入世界坐标。另外因为我们打算通过随机数生成纹理图案,所以我们不需要纹理变量,相应的UV坐标也可以删除了。
1 | struct Input { |
接下来我们将实现随机噪声值生成函数,这样我们可以通过该函数很方便的制造随机数。首先我们的函数接收三维坐标参数,然后返回一个0-1之间的小数。将向量转换为标量最简单的方法就是点乘,但是点乘的结果可能非常大,所以我们使用frac
函数只截取其中的小数部分。
1 | float rand(float3 vec){ |
如果我们在表面着色器函数中使用我们的随机函数,并以世界坐标为参数,将结果写入Albedo
参数中,那么我们可以立马看到我们的随机值遍布在模型表面。
1 | void surf (Input i, inout SurfaceOutputStandard o) { |
上面生成的噪声图有一个问题,就是看起来并不是那么随机,我们可以看到有很多条纹图案。虽然这个”随机函数“是我随便写的,但是它执行很快,也能满足我们当前一些简单的随机需求。我们再将上面的伪随机值乘以一个非常大的值,然后截取结果的小数部分,这样可以产生非常细的条纹,几乎观察不到。
1 | float rand(float3 vec){ |
但是又有一个问题,就是乘以一个非常大的数,其结果很容易超出浮点数表示范围,例如我们的模型离世界原点非常远。
为了修复这个问题,我们可以在乘积之前,将点乘结果限定在非常小的范围,这里我使用三角函数。因为三角函数是在特殊的计算单元中执行,所以其性能消耗只比加减乘除高点。
1 | //基于向量计算随机值 |
Different Input and Output
为了产生多维随机向量,我们可以沿着不同方向生成随机数,然后将结果合并成向量。但是不同方向的随机参数必须不同,这样不同方向的随机值才能不同。最简单的方法是将上面的固定向量改成变量,然后不同方向的随机值需要传入不同的向量。我们可以将上面的固定向量作为我们这个向量变量的默认参数,这样还可以以上面的方式调用。因为现在有一维、和三维随机数生成函数,所以我们需要给他们分别命名。
1 | //生成一维随机数 |
要生成三维随机数,我们可以将上面的方法调用三次。每次得到向量的一个维度值,每个维度使用不同的方向向量。这样我们可以得到一个彩色的随机噪声图。之所以将上面的方法执行三遍,而不是另外写一个直接生成三维向量的随机方法,是因为我们想让生成的随机向量的三个维度的值相互独立。
1 | //生成三维随机向量 |
1 | void surf (Input i, inout SurfaceOutputStandard o) { |
上面是使用三维向量来生成随机数,我们也可以使用二维向量,只要把前面的三维向量改成二维向量就行。还可以使用标量,不过原先的点乘操作就用不上了。我们可以一次性将这些函数都实现,然后放在一个include
文件中,这样以后都不用再重写这些方法了。
1 | //一维随机数 |
然后我们将上面的随机生成的函数都放到一个叫WhiteNoise.cginc
的文件中。并且在我们的着色器中引用它。
1 |
为了防止我们多次误引用同一个文件,我们可以使用宏命令来规避这个问题。
1 |
|
Cells
现在我们实现了通过世界坐标来生成随机颜色,这些颜色块非常小,当我们移动物体时,颜色也会快速变化。如果我们想让颜色块变大,我们可以将空间进行划分,所有处在同一块中的点使用同一个随机值。我们这里可以使用取整的方法,这样所有整数之间的小数对应的点都将使用同一随机值。
1 | void surf (Input i, inout SurfaceOutputStandard o) { |
现在我们得到泾渭分明的色块,然后我们可以修改色块的大小。
1 | Properties { |
1 | float3 _CellSize; |
我们这将世界坐标除以色块尺寸。
1 | void surf (Input i, inout SurfaceOutputStandard o) { |
Source
1 | Shader "Tutorial/024_white_noise/random" { |
1 | Shader "Tutorial/024_white_noise/cells" { |
1 |
|
希望我的教程能够对你有所帮助。
你可以在以下链接找到源码:
https://github.com/ronja-tutorials/ShaderTutorials/blob/master/Assets/024_White_Noise/WhiteNoise.cginc
https://github.com/ronja-tutorials/ShaderTutorials/blob/master/Assets/024_White_Noise/white_noise_random.shader
https://github.com/ronja-tutorials/ShaderTutorials/blob/master/Assets/024_White_Noise/white_noise_cells.shader
希望你能喜欢这个教程哦!如果你想支持我,可以关注我的推特,或者通过ko-fi、或patreon给两小钱。总之,各位大爷,走过路过不要错过,有钱的捧个钱场,没钱的捧个人场:-)!!!