【问题标题】:Perlin Noise understanding柏林噪声理解
【发布时间】:2017-11-04 15:36:21
【问题描述】:

我找到了两篇解释 Perlin Noise 工作原理的教程,但在第一篇教程中我发现了渐变的不可理解的奥秘,而在第二篇教程中我发现了 surflet 的奥秘。

第一种情况

第一个教程位于catlikecoding.com/unity/tutorials/noise。首先,autor 解释了值噪声,这是完全可以理解的,因为我们需要做的就是绘制一个随机颜色的网格,然后在颜色之间进行插值。

但是当涉及到 Perlin Noise,我们必须处理渐变,而不是单色。起初我认为渐变是颜色,所以如果我们有两个渐变并且我们想在它们之间进行插值,我们必须取第一个渐变的相应点并将其与第二个渐变的相应点进行插值。但是如果梯度相同,我们将得到与梯度相同的结果。

在教程中,作者以另一种方式实现了它。如果我们有一个由填充相同渐变的列组成的一维网格,并且每个渐变可以表示为从 0 到 1 的过渡(这里 0 是黑色,1 是白色)。然后作者说

现在每个条纹都有相同的渐变,除了它们是偏移的 从彼此。所以对于每一个 t0,它右边的梯度是 t1 = t0 - 1。让我们平滑地对它们进行插值。

这意味着我们必须在表示为从 0 到 1 的过渡的梯度和表示为从 -1 到 0 的过渡的梯度之间进行插值。

这意味着每个渐变都不会从值为 0 的位置开始,也不会在值为 1 的位置停止。它从 -1 的某个位置开始,在 2 的某个位置结束,或者它可能没有开始和结束点。我们只能看到 0 到 1 的范围,我不明白为什么会这样。我们从哪里得到连续梯度的概念?我以为每个条带只有从 0 到 1 的渐变,仅此而已,不是吗?

当我向作者询问这一切时,他回答说这是显而易见的

右侧的渐变是视觉参考。这是渐变 下一个更高的整数。你是对的,它对 左边。他们都这样做。

所以 t0 是左侧格点处为零的梯度 两个整数之间的区域的一侧。 t1 是梯度 在同一区域右侧的格点处为零。 通过在这两者之间进行插值获得梯度噪声 格点之间的梯度。是的,这可以产生 负面结果,最终变成黑色。这就是为什么下一步是 缩放和偏移结果。

现在我觉得这对我来说是不可能理解的,所以我只能相信并在更聪明的人之后重复。但是希望最后死去,所以我请求你以某种方式向我解释一下。

第二种情况

第二个教程位于eastfarthing.com/blog/2015-04-21-noise/,它比上一个教程要复杂得多。 我遇到的唯一问题是我无法理解下一段以及之后发生的事情

因此,鉴于此,我们可以只关注 G 的方向并始终使用 单位长度向量。如果我们钳制衰减核的乘积并且 在 2×2 正方形之外的所有点的梯度为 0,这给了我们 那个神秘句子中提到的 surflet。

我不确定问题出在我糟糕的数学还是英语知识上,所以我请你用简单的话解释一下这实际上是什么意思。

这是我到目前为止写的一些代码,它与第二种情况有关

import sys
import random
import math
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSlot

class Example(QWidget):

    def __init__(self):
        super(Example, self).__init__()
        self.gx=1
        self.gy=0
        self.lbl=QLabel()
        self.tlb = None
        self.image = QImage(512, 512, QImage.Format_RGB32)
        self.hbox = QHBoxLayout()
        self.pixmap = QPixmap()
        self.length = 1
        self.initUI()

    def mousePressEvent(self, QMouseEvent):
        px = QMouseEvent.pos().x()
        py = QMouseEvent.pos().y()

        size = self.frameSize()

        self.gx = px-size.width()/2
        self.gy = py-size.height()/2

        h = (self.gx**2+self.gy**2)**0.5

        self.gx/=h
        self.gy/=h

        self.fillImage()

    def wheelEvent(self,event):
        self.length+=(event.delta()*0.001)
        print(self.length)


    def initUI(self):    
        self.hbox = QHBoxLayout(self)
        self.pixmap = QPixmap()
        self.move(300, 200)
        self.setWindowTitle('Red Rock')

        self.addedWidget = None

        self.fillImage()

        self.setLayout(self.hbox)

        self.show()  

    def fillImage(self):

        step = 128
        for x in range(0, 512, step):
            for y in range(0, 512, step):

                rn = random.randrange(0, 360)
                self.gx = math.cos(math.radians(rn))
                self.gy = math.sin(math.radians(rn))

                for x1 in range(0, step):

                    t = -1+(x1/step)*2
                    color =  (1 - (3 - 2*abs(t))*t**2) 

                    for y1 in range(0, step):

                        t1 = -1+(y1/step)*2
                        color1 = (1 - (3 - 2*abs(t1))*t1**2)
                        result = (255/2)+(color * color1 * (t*self.gx+t1*self.gy) )*(255/2)
                        self.image.setPixel(x+x1, y+y1, qRgb(result, result, result))


        self.pixmap = self.pixmap.fromImage(self.image)

        if self.lbl == None:
            self.lbl = QLabel(self)
        else:
            self.lbl.setPixmap(self.pixmap)

        if self.addedWidget == None:
            self.hbox.addWidget(self.lbl)
            self.addedWidget = True

        self.repaint()
        self.update()


def main():

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()    

【问题讨论】:

    标签: python-3.x image-processing perlin-noise


    【解决方案1】:
    float Noise::perlin1D(glm::vec3 point, float frequency)
    {
        // map the point to the frequency space
        point *= frequency;
    
        // get the base integer the point exists on
        int i0 = static_cast<int>(floorf(point.x));
    
        // distance from the left integer to the point
        float t0 = point.x - static_cast<float>(i0);
    
        // distance from the right integer to the point
        float t1 = t0 - 1.f;
    
        // make sure the base integer is in the range of the hash function
        i0 &= hashMask;
    
        // get the right integer (already in range of the hash function)
        int i1 = i0 + 1;
    
        // choose a pseudorandom gradient for the left and the right integers
        float g0 = gradients1D[hash[i0] & gradientsMask1D];
        float g1 = gradients1D[hash[i1] & gradientsMask1D];
    
        // take the dot product between our gradients and our distances to
        // get the influence values. (gradients are more influential the closer they are to the point)
        float v0 = g0 * t0;
        float v1 = g1 * t1;
    
        // map the point to a smooth curve with first and second derivatives of 0
        float t = smooth(t0);
    
        // interpolate our influence values along the smooth curve 
        return glm::mix(v0, v1, t) * 2.f;
    }
    

    这里是相关代码的注释版本。但为 c++ 重写。显然,所有功劳都归于catlikecoding

    我们给函数一个点p。让我们假设点 p 是小数,例如如果 p 是 0.25,那么 p 左边的整数是 0,而整数p的右边是1。我们分别称这些整数为lr

    那么t0是lp的距离,t1是rp的距离。 t1 的距离为负,因为您必须沿负方向移动才能从 rp

    如果我们继续这个实现的 perlin 噪声部分,g0 和 g1 是一维的伪随机梯度。由于 g0 和 g1 是浮点数,因此这里的梯度可能再次令人困惑,但梯度只是一个方向,在一维中只能是正数或负数,因此这些梯度是 +1 和 -1。我们取梯度和距离之间的点积,但在一维中,这只是简单的乘法。点积的结果是两个浮点数 v0 和 v1。这些是我们的柏林噪声实现的影响值。最后,我们在这些影响值之间进行平滑插值,以产生平滑的噪声函数。让我知道这是否有帮助! This perlin noise explanation 对我理解这段代码很有帮助。

    【讨论】:

      猜你喜欢
      • 2021-04-29
      • 2012-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-25
      相关资源
      最近更新 更多