Perlin噪声算法
2023年3月5日 什么是噪声?如果您尝试了解程序生成中的任何内容,您一定会遇到噪声!那么,它究竟是什么?噪声不过是一组随机值。说实话,噪声的核心就是这些,但如您所猜测的,这并不简单。更技术性一点来说,噪声是一个函数。一个接受N个参数并根据某些规则(规则取决于我们所讨论的算法)生成一个值的函数。根据参数的数量,我们可以将噪声分为一维、二维、三维等。而它生成的值的范围也依赖于我们所谈论的算法。现在,对于每种类型的噪声都相信有多种用途,但在我看来,最容易处理的是二维噪声,因为实现算法时非常容易可视化。怎么做?通过纹理(图像)!一旦我们为二维建立了算法,我们可以将其推广到一维、三维等(至少大多数情况下)。好吧,那么我们如何使用噪声函数生成纹理呢?这里有一些伪代码:for ( int i = 0 ; i < image.height ; i ++ ) { for ( int j = 0 ; j < image.width ; j ++ ) { float n = noise ( ( float )j / image.width , ( float )i / image.height ); n = n / NOISE_MAX; // 在范围 [0, 1] 计算噪声 image.SetPixel (j, i, n, n, n); // 在像素 (j, i) 设置 (R, G, B) 值 } } 现在,让我们看看发生了什么。我们遍历每个像素,并将其设置为由噪声函数生成的值,输入的是 x 和 y 坐标。您可能会想,为什么我要将 x 和 y 坐标除以宽度和高度?这就是为了将它们标准化并将它们映射到 [0, 1) 范围(因为 i, j 从 0 开始,仅到 width - 1, height - 1)。为什么我们要这样做?我暂时无法回答,所以让我们先盲目跟随。将来,当我们谈论对这些噪声函数应用变换时,我们将看到如何转变这些参数以将噪声转化为我们想要的东西。但那是将来的事情。好吧,现在噪声函数呢?我们试着使用上篇文章中的 rand() 函数看看效果。float noise ( float x , float y ) { return rand (x + y); } 注意:我们在这里使用 x 和 y 坐标作为种子。输出:酷吧?不?好吧,您可以说它本身并不是很有趣,对吧?我是什么意思?所有的一切都是非常随机的,我们无法区分出任何特定的模式或特征。那么,我所说的有趣是什么意思?让我们看看,所以,现在似乎更有趣一些,对吧?因为您现在可以区分出一些特征或模式,但事情本身还是相当随机,对吧?这被称为一致噪声。它是我们之前使用 rand() 的噪声函数的光滑版本(伪随机噪声函数)。一致噪声函数有一些基本属性:传入相同的输入值将始终返回相同的输出值(几乎所有噪声算法都是如此) 输入值的微小变化将导致输出值的微小变化 输入值的大变化将导致输出值的随机变化 Perlin噪声算法 好吧,有几种算法用于生成一致噪声,我们将逐一介绍它们。但毫无疑问,最著名的噪声算法是Perlin噪声。引用维基百科的一些历史,Ken Perlin在1983年开发了Perlin噪声,这是由于他对当时计算机生成图像(CGI)“机械式”外观的沮丧。他在1985年的SIGGRAPH论文《图像合成器》中正式描述了他的发现。他在为迪士尼的计算机动画科幻电影《创》(1982年)工作后开发了该算法。1997年,Perlin因创建该算法而获得了技术成就的奥斯卡奖。 注意:这篇文章中Perlin噪声算法的实现来自这里 好吧,进入算法。所以,我们知道噪声函数的输入将是二维平面上的两个数字。所以,从上面的图表可以看到,二维平面中的每个点都在一个方形内,该方形的角落坐标是最接近该点坐标的整数。我们可以使用以下方式轻松获取方形的四个角坐标:我们将点设为 P=(x,y)P = (x, y) 现在,方形的角坐标为:P0=(floor(x),floor(y))P_0 = (floor(x), floor(y)) P1=(floor(x),floor(y)+1)P_1 = (floor(x), floor(y) + 1) P2=(floor(x)+1,floor(y))P_2 = (floor(x) + 1, floor(y)) P3=(floor(x)+1,floor(y)+1)P_3 = (floor(x)+1, floor(y)+1) 现在Perlin算法表示,对于这四个点中的每一个,我们都有一个随机的预计算单位向量。现在我们计算从这四个点到当前输入点P的向量。现在我们有4对向量(一个是预计算的
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡