此柏林(Ken Perlin)非彼柏林(Berlin,the capital and largest city of Germany)……
柏林噪声(Perlin Noise)应该不用赘述了。
- Improving noise,Ken Perlin,https://mrl.nyu.edu/~perlin/paper445.pdf
这里直接把核心代码放上来。
def lerp(a, b, t):
return a + t * (b - a)
这是用来进行插值的lerp函数。不过请继续往下看。
def fade(t):
return t * t * t * (t * (t * 6 - 15) + 10)
直接lerp函数进行线性插值的效果并不好,因此我们使用这个fade函数,它的变化两头快,中间慢。
顺便一说,在https://easings.net/可以查到很多缓动函数。(无关)
def grad(hash, x, y):
#按位与运算取出hash的最后两位
h = hash & 3
#u和v基于h的值在x和y之间交换
u = x if h < 2 else y
v = y if h < 2 else x
#判断,取和
return (u if (h & 1) == 0 else -u) + (v if (h & 2) == 0 else -v)
计算梯度值。没什么好说的。
def perlin(x, y, p):
#提取坐标整数部分并保证取值范围
x0 = int(x) & 255
y0 = int(y) & 255
xi = x - int(x)
yi = y - int(y)
#计算插值需要的的平滑值
u = fade(xi)
v = fade(yi)
#确定网格每个点的索引并计算梯度
aa = p[x0] + y0
ab = p[x0] + y0 + 1
ba = p[x0 + 1] + y0
bb = p[x0 + 1] + y0 + 1
grad_aa = grad(p[aa], xi, yi)
grad_ab = grad(p[ab], xi, yi - 1)
grad_ba = grad(p[ba], xi - 1, yi)
grad_bb = grad(p[bb], xi - 1, yi - 1)
lerp_a = lerp(grad_aa, grad_ab, v)
lerp_b = lerp(grad_ba, grad_bb, v)
return lerp(lerp_a, lerp_b, u)
我们可以尝试将柏林噪声混入图像中。
验证码中瞎眼选项的来源?
回到一维情形,我们可以将柏林噪声与正弦函数混合
生成处处看似随机但是总体规律性起伏的数据。游戏中的山峦等随机生成就可以这么做(扩展维数即可)。加上“时间”这一维还可以生成海浪等。