柏林噪声问题:结果中清晰可见的线条

Perlin noise problem: clearly visible lines in result

我一直在 python 中实现 perlin 噪音生成器。 它工作得很好,除了结果中清晰可见的线条。

问题似乎与我在 X 方向的渐变之间切换的位置有关。

代码如下:

from random import randint, seed
from PIL import Image
from numpy import asarray, interp, uint8

seed(1)
gradients = []
for x in range(20):
    gradients.append([])
    for y in range(20):
        gradients[x].append([randint(-1,1), randint(-1,1)])

def getInfluenceValue(x,y,Xgrad,Ygrad):
    return ((gradients[Xgrad][Ygrad][0] * (x-Xgrad)) + (gradients[Xgrad][Ygrad][1]*(y-Ygrad)))
    
def lerp(v0,v1,t):
    return (1 - t) * v0 + t * v1;

def fade(t):
    return 3*pow(t,2) - 2*pow(t,3)

def perlin(x, y):
    X0 = int(x) 
    Y0 = int(y)
    X1 = X0+1
    Y1 = Y0+1
    sx = fade(float(x) - float(X0));
    sy = fade(float(y) - float(Y0));
    topLeftDot = getInfluenceValue(x,y,X0,Y1)
    topRightDot = getInfluenceValue(x,y,X1,Y1) 
    bottomLeftDot = getInfluenceValue(x,y,X0,Y0)
    bottomRightDot = getInfluenceValue(x,y,X1,Y0)

    return lerp(lerp(topLeftDot, topRightDot, sx), lerp(bottomLeftDot, bottomRightDot, sx), sy)

tmp_list = []
for x in range(1000):
    tmp_list.append([])    
    for y in range(1000):
        tmp_list[x].append(perlin(x/100.0, y/100.0))

data = asarray(tmp_list)
rescaled = interp(data, (data.min(), data.max()), (0, 255)).astype(uint8)
Image.fromarray(rescaled).save('test.png')

结果如下:

我已经尝试替换 lerp 函数并且我使用了其他淡入淡出函数。但问题依然存在。这是怎么回事?

PS。我在 Whosebug 上看到了关于 perlin 噪声生成的“块状”结果的其他问题,但由于这个结果在 1 direction/dimension 中似乎只是“块状”,我认为问题与这些问题无关。

为了回答您的问题,我不确定这是否是整个问题,但我确实看到一个错误。在 X 中,您沿着 sx 从 X0 到 X1 进行插补。但是在 Y 中,您沿着 sy 从 Y1 到 Y0 进行插补。在 topLeftDot-bottomRightDot 变量中交换 Y1/Y0 应该可以解决这个问题。或者,切换哪些变量位于 lerp return 行的哪些部分。如果这不能解决问题,请尝试反转 X0/X1。我想知道为什么你的图像显示的不连续性打破了 X 轴而不是打破了 Y 轴。

补充一下,我看到您正在使用整数转换将 x,y 转换为 X0 和 Y0。这适用于正数,但可能不适用于负数。有关详细信息,请参阅

最后,我的一般建议:Perlin 是一种旧的噪声处理方法,往往会产生非常 grid-aligned 的结果。一旦你的噪声开始工作,或者如果你查看其他 Perlin 噪声图像,你可能会发现 a lot of the parts of the noise are aligned 45 or 90 degrees (Perlin is top row). This can be a rewarding programming exercise, but if you're going further than a programming exercise then I would suggest coding or using a good Simplex or Simplex-related noise implementation. See for an elaboration on implementing 2D simplex noise out of Perlin, or this 如果你想在你的项目中使用 easy-to-import Simplex-related 噪声。

看起来唯一的问题是 bottom-top 在 Y-interpolation 中被颠倒了。 这导致 vertical 条带,因为根据代码的设置方式,Y 是 horizo​​ntal 轴。

将 return 语句切换为“底部”在前 “顶部”在后:

return lerp(lerp(bottomLeftDot, bottomRightDot, sx), lerp(topLeftDot, topRightDot, sx), sy)

生成以下 Perlin 噪声图像: