GPU Gems1 - 5 改良的Perlin噪声的实现

Perlin 噪声

KenPerlin(1985a,2002)KenPerlin(1985a,2002) 定义的噪声函数是最常用的噪声函数,称为 Perlin 噪声。PerlinPerlin 噪声在全部 (x,y,z)(x,y,z) 整形顶点处的参数值都为 00,变化源自各顶点间的梯度向量,然后再进行平滑插值。

                                                          计算四个顶点的导数,再进行平滑的表面插值

perlin噪声应当满足的性质:

  •         1. 旋转统计不变性。(不管我们怎么旋转它的域,它都有同样的统计特性)
  •         2. 频率带通有一定界限。(它没有明显的大或者小的特征,而是在一定范围内)
  •         3. 平移统计不变性。(不管我们如何平移它的域,它都有同样的统计特性)

计算方法

   1.预处理:考虑x,y,z空间中所有点的集合(坐标为整数),我们称这个集合为整数格。现在我们为整数格的每个点附一个(x,y,z)上的伪随机梯度值,也就是一个向量,并且要将其 处理成单位向量。

   2.如果(x,y,z)处在整数格上,那么此处的噪声就是d。

   3.如果(x,y,z)不在整数格上,我们计算光滑插值系数。

  具体的插值方法如下,以二维为例,我们要找到这个点周围的四个整数点,然后我们得到四个值,横坐标为bx0 ~ bx1,纵坐标为by0 ~ by1。点到bx0在x轴上的距离为rx0,到by0在y轴上的距离为ry0。perlin给出了一个缓和曲线使得线性插值连贯。能使得一阶导数连续的缓和曲线函数 (最初的版本) : s_curve(t) ( t * t * (3. - 2. * t) )之后分别将rx0和ry0传入缓和曲线,得到一个新的值sx和sy。

 接下来做一个双线性插值,sx和sy就是第一步线性插值的系数,但是计算得到系数之后,我们还需要插值的起点和终点。他们的计算方法如下:

  •  求(rx0,ry0)与左上角点的梯度b00的点乘,得到起点u,求(rx0 + 1,ry0)与右上角点的梯度b10的点乘,得到终点v,以uv为两端,sx为插值系数,做线性插值,得到a
  •   求(rx0,ry0 + 1)与左下角点的梯度b01的点乘,得到起点u,求(rx0 + 1,ry0 + 1)与右下角点的梯度b11的点乘,得到终点v,以uv为两端,sx为插值系数,做线性插值,得到b
  •   最终,对a和b进行线性插值,插值系数为sy,得到最终的结果。

         以上算法步骤中,先对x轴还是先对y轴插值其实是无所谓的。最终得到的柏林噪声分布在 -1 ~ 1之间,我们可以把它映射到我们需要的颜色区别(比如0 ~ 255 或 0 ~ 1)得到对应的颜色。

二维拓展到三维,柏林噪声的生成方法伪代码可以概括如下:

    Float Noise(Float x, Float y, Float z) {
        <计算八个顶点整数坐标,以及偏移量>
        <计算梯度权值>
        <权重进行三线性插值>
    }

GEM这篇文章提到的改进点概括起来是两点:

1.更换曲线函数为二次偏导连续的:s_curve(t) ( t * t * t * (6 * t * t - 15 * t + 10) ),从而解决使用噪声的导数时出现失真的视觉效果,例如制作凹凸贴图时。

2.将256大小的伪随机查找表改成大小为12,值为立方体12条边中点。从而解决噪声函数的结果中产生不希望的高频