【问题标题】:Perlin noise artifactsPerlin 噪声伪影
【发布时间】:2017-02-27 05:03:06
【问题描述】:

我采用了Wikipedia Perlin Noise Algorithm 并在 Python 中实现了它,代码如下:

import random
import math
from PIL import Image
from decimal import Decimal


IMAGE_SIZE = 200
PERLIN_RESOLUTION = 10
GRADIENT = []


for x in range(PERLIN_RESOLUTION + 1):
    GRADIENT.append([])
    for y in range(PERLIN_RESOLUTION + 1):
        angle = random.random() * 2 * math.pi
        vector = (
            Decimal(math.cos(angle)),
            Decimal(math.sin(angle))
        )
        GRADIENT[x].append(vector)


def lerp(a0, a1, w):
    return (1 - w)*a0 + w*a1


def dotGridGradient(ix, iy, x, y):

    dx = x - Decimal(ix)
    dy = y - Decimal(iy)

    return (dx*GRADIENT[iy][ix][0] + dy*GRADIENT[iy][ix][1])


def perlin(x, y):
    if x > 0.0:
        x0 = int(x)
    else:
        x0 = int(x) - 1
    x1 = x0 + 1
    if y > 0.0:
        y0 = int(y)
    else:
        y0 = int(y) - 1
    y1 = y0 + 1

    sx = x - Decimal(x0)
    sy = y - Decimal(y0)

    n0 = dotGridGradient(x0, y0, x, y)
    n1 = dotGridGradient(x1, y0, x, y)
    ix0 = lerp(n0, n1, sx)
    n0 = dotGridGradient(x0, y1, x, y)
    n1 = dotGridGradient(x1, y1, x, y)
    ix1 = lerp(n0, n1, sx)
    value = lerp(ix0, ix1, sy)

    return value


image = Image.new('RGB', (IMAGE_SIZE, IMAGE_SIZE))
pixels = image.load()
for i in range(IMAGE_SIZE):
    x = Decimal(i) / IMAGE_SIZE
    for j in range(IMAGE_SIZE):
        y = Decimal(j) / IMAGE_SIZE
        value = perlin(x * 10, y * 10)
        greyscale = (value + 1) * 255 / 2
        pixels[i, j] = (greyscale, greyscale, greyscale)
image.save('artifacts.png', 'PNG')

这是脚本创建的结果图像:

我一定是在这里遗漏了一些东西,你可以很清楚地看到顶点。谁能告诉我出了什么问题?

【问题讨论】:

    标签: python python-imaging-library perlin-noise


    【解决方案1】:

    你需要使用smoothstep而不是线性插值。

    def smoothstep(a0, a1, w):
        value = w*w*w*(w*(w*6 - 15) + 10)
        return a0 + value*(a1 - a0)
    

    【讨论】:

    • 嗨,非常感谢您的回复,WhatEvDev。我试过了,它似乎工作得很好。我想接受你的回答,但在我这样做之前你能解释一下为什么这个函数更好(以及为什么网上有这么多示例算法似乎使用 lerp,比如维基百科)。
    • 以线性插值为例,因为它是最简单的插值 (value = w)。如果您将 1D Perlin Noise 与 lerp 一起使用,您将获得多边形曲线。为了获得平滑的结果,您需要在点之间进行平滑插值。为此,您需要一个在 0 和 1 处具有零一阶导数(也可能是二阶导数)的函数。如果您使用 1D Perlin Noise with smoothstep,您将获得平滑曲线。
    猜你喜欢
    • 1970-01-01
    • 2013-09-23
    • 2014-02-15
    • 2019-04-30
    • 2020-06-06
    • 2011-09-20
    • 1970-01-01
    • 2021-06-30
    • 2013-07-23
    相关资源
    最近更新 更多