Perlin noise

   Perlin noise的目的是为了产生一系列可重复,伪随机的信号,在游戏中我们可以利用产生的perlin noise来混合地形使用,例如沙地和草地的混合,如下图所示,第三张黑白颜色图就是perlin noise产生的(http://devmag.org.za/2009/04/25/perlin-noise/)。

  Perlin noise的产生是从一维扩展到三维的。首先从一维说起,假如我们需要得到一维点x的noise,首先我们取x附近的两个整数点的noise值,然后利用插值函数得到该点的noise。具体计算如下:

//注释掉的为原始的插值函数,非二次连续,高频突变。
float fade(float t) {
  // return t*t*(3.0-2.0*t); // Old fade, yields discontinuous second derivative
  return t*t*t*(t*(t*6.0-15.0)+10.0); // Improved fade, yields C2-continuous noise
}

#define lerp(t, a, b) ( a + t * (b - a) )

float Xdelta = X- (int)X;

//X0,X1为最靠近X两个点的噪声值,G为存放各个整数点的噪声值。
float X0 =G[int(x)];
float X1 = G[int(x)+1];   

//返回值
float noise = lerp(fade(Xdelta),X0,X1);

   

二维的noise获取如上图所示,首先获取平面周围四个点的noise值,然后计算四个点的贡献度,最后插值计算出改点的noise(http://webstaff.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf),代码注释如下。

float noise2(vec2 vec)
{
//图中的i,j。
 vec2 pf = frac(vec);
;
//相近的四个点随机梯度值(noise 值) vec2 gradient00 = G2[perm[pf.x][perm[pf.y]]; vec2 gradient01 = G2[perm[pf.x]][perm[pf.y+1]]; vec2 gradient10 = G2[perm[pf.x+1]][perm[pf.y]]; vec2 gradient11 = G2[perm[pf.x+1]][perm[pf.y+1]]; //四个点nosie的贡献值。 float n00 = dot(grad00, vec); float n10 = dot(grad10, Pf - vector2(1.0, 0.0)); float n01 = dot(grad01, Pf - vector2(0.0, 1.0)); float n11 = dot(grad11, Pf - vector2(1.0, 1.0)); //x方向的插值计算。 // Blend contributions along y vec2 n_x = lerp2(vector2(n00, n01), vec2(n10, n11), fade(Pf.x)); //y方向的插值计算。 // Blend contributions along y float n_xy = lerp2(n_x.x, n_x.y, fade(Pf.y)); // We're done, return the final noise value. return n_xy; }

三维perlin noise需要计算空间周围的八个点的nosie值,然后插值获取最终值,计算方式如下。

 // Classic Perlin noise, 3D version
 public static double noise(double x, double y, double z) {
 // Find unit grid cell containing point
 //查找最接近的X,Y,Z
 int X = fastfloor(x);
 int Y = fastfloor(y);
 int Z = fastfloor(z);
 
 //计算插值。
 // Get relative xyz coordinates of point within that cell
 x = x - X;
 y = y - Y;
 z = z - Z;
 
 // Wrap the integer cells at 255 (smaller integer period can be introduced here)
 X = X & 255;
 Y = Y & 255;
 Z = Z & 255;
 //随机索引
// Calculate a set of eight hashed gradient indices
 int gi000 = perm[X+perm[Y+perm[Z]]] % 12;
 int gi001 = perm[X+perm[Y+perm[Z+1]]] % 12;
 int gi010 = perm[X+perm[Y+1+perm[Z]]] % 12; 
 int gi011 = perm[X+perm[Y+1+perm[Z+1]]] % 12;
 int gi100 = perm[X+1+perm[Y+perm[Z]]] % 12;
 int gi101 = perm[X+1+perm[Y+perm[Z+1]]] % 12;
 int gi110 = perm[X+1+perm[Y+1+perm[Z]]] % 12;
 int gi111 = perm[X+1+perm[Y+1+perm[Z+1]]] % 12;
 
 
 //计算梯度值
 // Calculate noise contributions from each of the eight corners
 double n000= dot(grad3[gi000], x, y, z);
 double n100= dot(grad3[gi100], x-1, y, z);
 double n010= dot(grad3[gi010], x, y-1, z);
 double n110= dot(grad3[gi110], x-1, y-1, z);
 double n001= dot(grad3[gi001], x, y, z-1);
 double n101= dot(grad3[gi101], x-1, y, z-1);
 double n011= dot(grad3[gi011], x, y-1, z-1);
 double n111= dot(grad3[gi111], x-1, y-1, z-1);
 // Compute the fade curve value for each of x, y, z
 double u = fade(x);
 double v = fade(y);
 double w = fade(z);
 // Interpolate along x the contributions from each of the corners
 //计算x方向插值。
 double nx00 = mix(n000, n100, u);
 double nx01 = mix(n001, n101, u);
 double nx10 = mix(n010, n110, u);
 double nx11 = mix(n011, n111, u);
 
 //计算y方向插值。
 // Interpolate the four results along y
 double nxy0 = mix(nx00, nx10, v);
 double nxy1 = mix(nx01, nx11, v);
 //计算z方向插值。
 // Interpolate the two last results along z
 double nxyz = mix(nxy0, nxy1, w);
 
 return nxyz;
 }

 

posted @ 2015-11-06 23:26  VAN_H  阅读(628)  评论(0编辑  收藏  举报