# 一篇文章搞懂柏林噪声算法，附代码讲解 [ 译 ]

1

2

3

## 基本原理

`public double perlin(double x, double y, double z);`

`(1,1,0),(-1,1,0),(1,-1,0),(-1,-1,0), (1,0,1),(-1,0,1),(1,0,-1),(-1,0,-1), (0,1,1),(0,-1,1),(0,1,-1),(0,-1,-1)`

`grad.x * dist.x + grad.y * dist.y + grad.z * dist.z`

`dot(vec1,vec2) = cos(angle(vec1,vec2)) * vec1.length * vec2.length`

`1 * vec1.length * vec2.length`

`-1 * vec1.length * vec2.length`

`0 * vec1.length * vec2.length`

```// Below are 4 influence values in the arrangement:
// [g1] | [g2]
// -----------
// [g3] | [g4]
int g1, g2, g3, g4;
int u, v;   // These coordinates are the location of the input coordinate in its unit square.
// For example a value of (0.5,0.5) is in the exact center of its unit square.

int x1 = lerp(g1,g2,u);
int x2 = lerp(g3,h4,u);

int average = lerp(x1,x2,v);```

## 代码实现

```private static readonly int[] permutation = { 151,160,137,91,90,15,                 // Hash lookup table as defined by Ken Perlin.  This is a randomly
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,    // arranged array of all numbers from 0-255 inclusive.
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};

private static readonly int[] p;                                                    // Doubled permutation to avoid overflow

static Perlin() {
p = new int[512];
for(int x=0;x<512;x++) {
p[x] = permutation[x%256];
}
}```

`p[]`数组会在算法后续的哈希计算中使用到，用于确定一组输入最终挑选哪个梯度向量（从前面所列出的12个梯度向量中挑选）。后续代码会详细展示`p[]`数组的用法。

```public double perlin(double x, double y, double z) {
if(repeat > 0) {                                    // If we have any repeat on, change the coordinates to their "local" repetitions
x = x%repeat;
y = y%repeat;
z = z%repeat;
}

int xi = (int)x & 255;                              // Calculate the "unit cube" that the point asked will be located in
int yi = (int)y & 255;                              // The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that
int zi = (int)z & 255;                              // plus 1.  Next we calculate the location (from 0.0 to 1.0) in that cube.
double xf = x-(int)x;
double yf = y-(int)y;
double zf = z-(int)z;
// ...
}```

```public static double fade(double t) {
// Fade function as defined by Ken Perlin.  This eases coordinate values
// so that they will ease towards integral values.  This ends up smoothing
// the final output.
return t * t * t * (t * (t * 6 - 15) + 10);         // 6t^5 - 15t^4 + 10t^3
}

public double perlin(double x, double y, double z) {
// ...

// ...
}```

### 哈希函数

```public double perlin(double x, double y, double z) {
// ...

int aaa, aba, aab, abb, baa, bba, bab, bbb;
aaa = p[p[p[    xi ]+    yi ]+    zi ];
aba = p[p[p[    xi ]+inc(yi)]+    zi ];
aab = p[p[p[    xi ]+    yi ]+inc(zi)];
abb = p[p[p[    xi ]+inc(yi)]+inc(zi)];
baa = p[p[p[inc(xi)]+    yi ]+    zi ];
bba = p[p[p[inc(xi)]+inc(yi)]+    zi ];
bab = p[p[p[inc(xi)]+    yi ]+inc(zi)];
bbb = p[p[p[inc(xi)]+inc(yi)]+inc(zi)];

// ...
}

public int inc(int num) {
num++;
if (repeat > 0) num %= repeat;

return num;
}```

### 梯度函数

```public static double grad(int hash, double x, double y, double z) {
int h = hash & 15;                                    // Take the hashed value and take the first 4 bits of it (15 == 0b1111)
double u = h < 8 /* 0b1000 */ ? x : y;                // If the most significant bit (MSB) of the hash is 0 then set u = x.  Otherwise y.

double v;                                             // In Ken Perlin's original implementation this was another conditional operator (?:).  I

if(h < 4 /* 0b0100 */)                                // If the first and second significant bits are 0 set v = y
v = y;
else if(h == 12 /* 0b1100 */ || h == 14 /* 0b1110*/)  // If the first and second significant bits are 1 set v = x
v = x;
else                                                  // If the first and second significant bits are not equal (0/1, 1/0) set v = z
v = z;

return ((h&1) == 0 ? u : -u)+((h&2) == 0 ? v : -v); // Use the last 2 bits to decide if u and v are positive or negative.  Then return their addition.
}```

```// Source: http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html
public static double grad(int hash, double x, double y, double z)
{
switch(hash & 0xF)
{
case 0x0: return  x + y;
case 0x1: return -x + y;
case 0x2: return  x - y;
case 0x3: return -x - y;
case 0x4: return  x + z;
case 0x5: return -x + z;
case 0x6: return  x - z;
case 0x7: return -x - z;
case 0x8: return  y + z;
case 0x9: return -y + z;
case 0xA: return  y - z;
case 0xB: return -y - z;
case 0xC: return  y + x;
case 0xD: return -y + z;
case 0xE: return  y - x;
case 0xF: return -y - z;
default: return 0; // never happens
}
}```

`(1,1,0),(-1,1,0),(1,-1,0),(-1,-1,0), (1,0,1),(-1,0,1),(1,0,-1),(-1,0,-1), (0,1,1),(0,-1,1),(0,1,-1),(0,-1,-1)`

### 插值整合

```public double perlin(double x, double y, double z) {
// ...

double x1, x2, y1, y2;
x1 = lerp(    grad (aaa, xf  , yf  , zf),           // The gradient function calculates the dot product between a pseudorandom
grad (baa, xf-1, yf  , zf),             // gradient vector and the vector from the input coordinate to the 8
u);                                     // surrounding points in its unit cube.
x2 = lerp(    grad (aba, xf  , yf-1, zf),           // This is all then lerped together as a sort of weighted average based on the faded (u,v,w)
u);
y1 = lerp(x1, x2, v);

x1 = lerp(    grad (aab, xf  , yf  , zf-1),
grad (bab, xf-1, yf  , zf-1),
u);
x2 = lerp(    grad (abb, xf  , yf-1, zf-1),
u);
y2 = lerp (x1, x2, v);

return (lerp (y1, y2, w)+1)/2;                      // For convenience we bind the result to 0 - 1 (theoretical min/max before is [-1, 1])
}

// Linear Interpolate
public static double lerp(double a, double b, double x) {
return a + x * (b - a);
}```

### 利用倍频实现更自然的噪声

frequency=2<sup>i<sup/>

amplitude=persistence<sup>i<sup/>

```public double OctavePerlin(double x, double y, double z, int octaves, double persistence) {
double total = 0;
double frequency = 1;
double amplitude = 1;
double maxValue = 0;  // Used for normalizing result to 0.0 - 1.0
for(int i=0;i<octaves;i++) {
total += perlin(x * frequency, y * frequency, z * frequency) * amplitude;

maxValue += amplitude;

amplitude *= persistence;
frequency *= 2;
}

}```

## 小结

0 条评论

• ### FZU 2095 水面高度

Problem 2095 水面高度 Accept: 40    Submit: 256 Time Limit: 1000 mSec    Memory L...

• ### Stack Overflow 上的这些问题，加快了程序员的 "秃头" 速度...

自 2008 年成立以来，Stack Overflow 一直在拯救所有类型的开发人员。自那时以来，开发人员提出了数百万个关于开发领域的问题。

• ### ​什么问题最让程序员头秃？我们分析了11种语言的11000个问题

我们选择了 11 种最流行的编程语言（以 Stack Overflow 标签的频率来衡量），并进行了一项研究，旨在揭示这些问题中的某些共性和差异。

• ### 哪些开发问题最让程序员“头秃”？我们分析了Stack Overflow的11000个问题

自 2008 年成立以来，Stack Overflow 一直在拯救所有类型的开发人员。自那时以来，开发人员提出了数百万个关于开发领域的问题。

• ### ​哪些开发问题最让程序员“头秃”？我们分析了Stack Overflow的11000个问题

自 2008 年成立以来，Stack Overflow 一直在拯救所有类型的开发人员。自那时以来，开发人员提出了数百万个关于开发领域的问题。

• ### VSCode插件MSSQL教程（昨天提了一下）

什么数据库都木有（系统自带的不算） ? 插件自己安装一下 ? 按F1，输命令 ? ? 连接就输入名字，创建就空着 ? ? 用户名和密码 ? ? 下次就不用再输了...

• ### 人机交互、大数据分析：移动互联网的技术创新探索

有一群人注定为改变世界而活，有一群人正在为影响10亿人而战。5月31日下午，在“奇点大学中国区学员选拔大赛总决赛”的赛场上，从数百个参赛者中脱颖而出，来自移动应...

• ### 2-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案数据篇(数据库简单说明)

这里有个教程   http://www.cnblogs.com/best/p/6517755.html