写在前面:
对Metal技术感兴趣的同学,可以关注我的专题:Metal专辑
也可以关注我个人的简书账号:张芳涛
所有的代码存储的Github地址是:Metal
正文
让我们来看看我们在第14部分中停下的地方。使用我们上次工作的同一个Playground
,我们今天将学习noise
效果。 来自维基百科:
Noise refers to any random fluctuations of data that makes the perception of an expected signal, difficult. Value noise is a type of noise commonly used as a procedural texture primitive in computer graphics. This method consists of the creation of a lattice of points which are assigned random values. The noise function then returns the interpolated number based on the values of the surrounding lattice points. Multiple octaves of this noise can be generated and then summed together in order to create a form of fractal noise.
Noise
最明显的特征是随机性。 由于MSL
不提供随机功能,我们自己创建一个。 我们需要的是[0,1]
之间的随机数。 我们可以通过使用fract
函数来获得它,该函数返回数字的小数部分:
float random(float2 p)
{
return fract(sin(dot(p, float2(15.79, 81.93)) * 45678.9123));
}
noise()
函数将双线性插值格子(网格)并返回平滑值。 双线性插值允许我们将1D
随机函数转换为基于2D
网格的值:
float noise(float2 p)
{
float2 i = floor(p);
float2 f = fract(p);
f = f * f * (3.0 - 2.0 * f);
float bottom = mix(random(i + float2(0)), random(i + float2(1.0, 0.0)), f.x);
float top = mix(random(i + float2(0.0, 1.0)), random(i + float2(1)), f.x);
float t = mix(bottom, top, f.y);
return t;
}
我们首先使用i沿网格点移动,使用f
作为网格点之间的偏移。 然后我们用公式3f ^ 2 - 2f ^ 3
计算一个立方Hermite
样条,并创建一个S
形曲线,其值在[0,1]
之间。 接下来,我们沿着网格的底部和顶部插入值,最后我们在这两个水平点之间插入垂直线以获得噪声的最终值。
接下来,我们创建一个Fractional Brownian Motion
(分数布朗运动)函数,多次调用我们的noise()
函数并将结果相加。
float fbm(float2 uv)
{
float sum = 0;
float amp = 0.7;
for(int i = 0; i < 4; ++i)
{
sum += noise(uv) * amp;
uv += uv * 1.2;
amp *= 0.4;
}
return sum;
}
通过以不同的幅度添加各种(在这种情况下为四个)这种噪声的八度音程(如开头所述),我们可以生成一个简单的类云模式。 我们还有一件事要做:在内核内部替换定义距离之后的所有行,使用以下代码:
uv = fmod(uv + float2(timer * 0.2, 0), float2(width, height));
float t = fbm( uv * 3 );
output.write(distance < 0 ? float4(float3(t), 1) : float4(0), gid);
我们再次添加timer
uniform
以动画内容。 输出图像应如下所示:
它看起来很酷,但仍然不够现实。 为了使它看起来更逼真,我们需要了解并应用纹理。如果您有兴趣,可以阅读更多关于bilinear filtering,关于value noise和关于Fractional Brownian motion的信息。 您还可以看到Cubic Hermit Spline的示例。
网友评论