Perlin Noise(摘)

标签:
杂谈 |
分类: 计算机图形学 |
本文资源来自libnoise网站和GPU Gems一书。
一.什么是Coherent noise
Coherent noise由coherent noise函数生成,具备三个特点:
1)
2)
3)
http://images.cnblogs.com/cnblogs_com/arenak/coherentnoise.pngNoise(摘)" />
coherent-noise函数输出
http://images.cnblogs.com/cnblogs_com/arenak/noise.pngNoise(摘)" />
non-coherent-noise函数输出
如何生成Coherent noise将会在第四部分给出。
二.什么是Perlin Noise
Perlin Noise是几个Coherent noise的叠加,这几个coherent noise间的关系是:频率递增,振幅递减。
下图中为f为频率,a为振幅。
http://images.cnblogs.com/cnblogs_com/arenak/perlin1.pngNoise(摘)" />
http://images.cnblogs.com/cnblogs_com/arenak/perlin2.pngNoise(摘)" />
http://images.cnblogs.com/cnblogs_com/arenak/perlin3.pngNoise(摘)" />
http://images.cnblogs.com/cnblogs_com/arenak/perlin4.pngNoise(摘)" />
以上几个噪声的和就组成了Perlin噪声:
http://images.cnblogs.com/cnblogs_com/arenak/perlin.pngNoise(摘)" />
Ken Perlin在1983年发明Perlin噪声,1985年发表相应文章。
三.Perlin噪声中的各个术语
1.
由多个coherent noise组成一个Perlin噪声,每一个coherent noise就称为一个octave.
octave越多,Perlin噪声就越细致,但计算时间也越长。
2.
每个Coherent noise函数所能输出的最大值,在有名的libnoise库中振幅为n的函数输出范围为-n~n。
3.
单位长度内Coherent noise函数循环的次数,每次循环的起点函数输出为0。
两个连续octave间频率frequency递增的速度的度量。
当前octave的频率f
5.
两个连续octave间振幅amplitude递增的速度的度量。
当前octave的振幅A * Persistence
=
6.
用于改变Coherent noise函数的输出。改变Seed值,则Coherent noise函数的输出改变。
四.如何生成Coherent noise
Perlin噪声由Coherent noise叠加生成,那么只要知道了如何生成Coherent noise ,就能生成Perlin噪声了。下面将逐步说明。
1.
给定一个整数作为输入,则一维Integer-noise函数输出一个伪随机浮点数(通常在-1到1之间)。N维Integer-noise函数需要n个整数作为输入,输出仍是一个伪随机浮点数(通常在-1到-1之间)。
http://images.cnblogs.com/cnblogs_com/arenak/intnoise.pngNoise(摘)" />
下面是一个这样的函数:
double IntegerNoise (int n)
{
}
2.
线形插值linear interpolation:
lerp(a,
函数如下:
double CoherentNoise (double x)
{
}
二维函数用双线性插值bilinear interpolation,三维函数用三线性插值trilinear interpolation。
下图是一维插值后的输出:
http://images.cnblogs.com/cnblogs_com/arenak/coherentnoise1.pngNoise(摘)" />
二维输出:
http://images.cnblogs.com/cnblogs_com/arenak/coherentnoise2d.pngNoise(摘)" />
线性插值的缺点在于生成的纹理有creasing瑕疵,也就是说界线太明显,图像不自然。在生成凹凸纹理时尤其明显,如下图:
http://images.cnblogs.com/cnblogs_com/arenak/bumpvalue.pngNoise(摘)" />
3.
线性插值的方法保证了插值函数的输出在插值点上取得了正确的结果,但不能保证插值函数在插值点上的导数值。
利用Hermit插值可以在保证函数输出的基础上保证插值函数的导数在插值点上为0,这样就提供了平滑性。
插值点为0、1,结果值为0、1,导数为0、0,则可以求得Hermit插值函数为s(x) =
-2x3
用立方插值(S曲线插值)代替线性插之后的代码为:
double CoherentNoise (double x)
{
}
如果再使插值函数的二阶导数值在插值点处为0,则可以进一步平滑。五次插值函数:s(x) =
6x5
http://images.cnblogs.com/cnblogs_com/arenak/bumpvalue.pngNoise(摘)" />