10.WebGL Shader 噪声

https://www.bilibili.com/video/BV1bb4y1a7Bu/?spm_id_from=333.337.search-card.all.click&vd_source=01ae3fc576acbf5bd3e59f3307bb594f

背景

其实早在80年代之前,随机数是基本能满足我们日常需求的,但是随着人们应用的越加广泛,其问题也也越发明显。我们接下来我们首先介绍下random函数和noise函数的区别。

random(a)noise(a)
参数含义随机值范围挖矿点坐标
随机值范围传入值参数指定0~1
随机值分部均匀分部类似正态分部
其他几乎每次输出的值都不一样相同位置挖出的值一样

简单解释下这四部分内容:

(1)参数含义意义:random传入的值代表随机值范围,也就是返回的值所在的范围区间,这块大家可以去自行举例法测试,或者大家在其他语言中一定也有random函数,其参数含义也大致如此。noise函数参数代表传入的值,我们称为“挖矿点”,通过传入变量值,最终返回相应的结果值。

(2)随机值范围意义:random由传入的参数值确定,而noise在0~1之间。如下图所示:

在这里插入图片描述

(3)随机值分部意义:random返回的值是均匀分部的,noise返回的值是近似于正态分部。

(4)其他意义:random输出的值每次都不一样,noise如果传入的值是固定的,其返回的结果也是相同的。这里我们可以利用初级课程中学到的通过颜色值调试glsl代码去做详细的输出打印,伪代码如下所示:

for(int i=0;i<10;i++){
float a = random(100);
}
for(int i=0;i<10;i++){
float a = noise(100);
}

Ken Perlin(这哥们为了解决在电影中特效问题,发明了一个算法,也就是因为这个算法获得了奥斯卡金奖)发明的自然噪声生成算法。接下来我们详细介绍下该算法的应用情况。

1D噪声

我们是在前面给大家讲了关于随机数的算法,其大致图像如下图所示:
在这里插入图片描述

Perlin Noise的图像大致如下所示,但是这个图像我最开始在背景里面给大家讲解过,只要传入的值是固定的,返回的值也是固定的,这就是不同与随机数的区别。

在这里插入图片描述

接下来解释下噪声函数生产的核心代码:

float i = floor(x);  // 整数
float f = fract(x);  // 小数
float u = f * f * (3.0 - 2.0 * f ); 
y = mix(rand(i), rand(i + 1.0), u); 

if均是为了将x上的像素值分割成整数和小数。函数float u = f * f * (3.0 - 2.0 * f ); 实际上一个三次多项式函数,近似于smoothstep函数,目的是为了将值进行平滑过渡,mix函数是rand(i)与 rand(i + 1.0)进行插值。其函数图像如下所示:

在这里插入图片描述

***注:***这里面我觉得巧妙之处就是将x进行分割,增加随机性,最后实际上还是应用x,表达的y之间的关系。实现x与y一对一对应关系。

2D噪音

上述我们介绍了1维噪音生产计划,noise(x),下面我们介绍二维噪音生产计划noise(x,y),任意输入一个x,y即可得到相应的noise值,我们现在看到的就是将x,y值返回的noise映射成黑白灰的样子:

在这里插入图片描述

如果将x,y对应的值看成height,就会有下面的效果:

在这里插入图片描述

同样的,2Dnoise也可以像1Dnoise一样在平面上无限延伸,我们实际上在游戏里生成的地形,就是这样生成的,由此看来2D的noise函数和1D的noise函数本质上没有区别,只不过多了一个维度。下面是2Dnoise的不同表现形式:

在这里插入图片描述

如果表现灰度就是第一个,表现颜色就是第一行第二列,表现速度方向就是第二行第一列,表现高度就是最后一个。

3D噪音

noise 在3D中的应用也是类似的,通过输入三个变量值noise(x,y,z),如下图所示:

在这里插入图片描述

假如在某一位置,x,y固定,即通过x,y确定了某一平面,同时随着z轴变化,x,y所形成的投影不断变化;同样道理,x,z的值是固定的,随着y值的变化,x,z行成的平面不断变化,最后也生成了平面图例。

FBM

有时候单一频率的噪声不足以满足需求,会需要使用多级噪声累加的结果来实现程序化生成,这种方式我们称之为Fractal Brownian Motion,简称FBM,下图展示了FBM的基本形式,简单来说就是将多个不同频率的噪声按照不同的振幅进行混合:

float fBm(float x)
{
	// Properties
	int octaves = 1;//int(iMouse.x * 0.01);
	float lacunarity = 2;
	float gain = 0.5;
	// Initial values
	float amplitude = 1;
	float frequency = 1;
	float value = 0;
	// Loop of octaves
	for (int i = 0; i < octaves; ++i)
	{
		value += amplitude * noise(frequency * x);
		frequency *= lacunarity;
		amplitude *= gain;
	}
	return value;
}

FBM的关键在于多个不同频率的noise的叠加到一起,其中for循环是用来产生多个noise,至于不同频率的noise一般可以关注以下这个公式:
f l o a t r e s = a ∗ n o i s e ( b ∗ x ) ; float res= a * noise(b * x); floatres=anoise(bx);
其中a和b两个参数是关键,我们可以尝试动态改变一下这个参数。

总结

noise不管是1D、2D、3D,可以比喻成在茫茫大地上存储的矿石,无穷无尽。通过noise函数输入的索引,可以获取任意位置的金矿,索引坐标可以是1D、2D、3D。可以把其中一个维度理解为时间。
(1)Noise 使用方法: 用开采出来的数值控制各种属性。
(2)如果你想将noise生成的值赋值给不同的属性,一定要错开不同的 Noise 取值区间,来避免变化趋势相同,一般我们是在noise输入参数上乘上某值,让输入的参数范围相距更远。

具体我们来看一下下面这个案例。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值