Perlin Noise理解

时间:2017-06-03 09:03:47

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

我发现了两个解释Perlin Noise如何工作的教程,但是在第一个教程中我发现了不可理解的渐变之谜,而在第二个教程中我发现了冲浪的神秘面纱。

第一个案例

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

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

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

  

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

所以这意味着我们必须在一个渐变之间进行插值,该渐变表示为从0到1的过渡,以及一个渐变,表示为从-1到0的过渡。

这意味着每个渐变都不会从值为0的位置开始,并且不会在值为1的位置停止。它从-1开始到某处,在某处结束为2,或者它可能没有开始和结束点。我们只能看到0到1的范围,我无法理解为什么会这样。我们从那里采取连续渐变的想法?我认为我们每个条带只有0到1的渐变,这就是全部,不是吗? continuous gradient

当我向作者询问所有这些时,他回答说这是显而易见的事情

  

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

     

因此t0是左边格点处的零度   两个整数之间的区域的一侧。并且t1是渐变   在同一区域右侧的格点处为零。   通过在这两者之间进行插值来获得梯度噪声   格点之间的渐变。是的,这可以产生   负面结果,最终黑了。这就是下一步的原因   缩放并抵消结果。

现在我觉得我不可能理解这是如何运作的,所以我只能相信并重复更聪明的家伙。但希望终于死了,所以我求你以某种方式向我解释。

第二种情况

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

  

因此,我们可以专注于G的方向并始终使用   单位长度向量。如果我们钳制衰减内核的产品和   在2×2平方以外的所有点处,梯度为0,这给了我们   那个神秘的句子中提到的冲浪。

我不确定问题是由于我的数学或英语知识不足,所以我请你用简单的语言解释这实际意味着什么。

这是我到目前为止编写的一些代码,它涉及第二种情况

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()    

1 个答案:

答案 0 :(得分:0)

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 是.25那么 p 左边的整数是0 p 右边的整数是1.让我们分别调用这些整数 l r

然后t0是从 l p 的距离,t1是从 r p 的距离。 t1的距离为负,因为您必须向负方向移动才能从 r 移动到 p

如果我们继续执行此实现的perlin噪声部分,g0和g1是1维的伪随机梯度。再次,渐变可能会让人感到困惑,因为g0和g1是浮点数,但是渐变只是一个方向,在一个维度上,你只能是正数或负数,所以这些梯度是+1和-1。我们采用渐变和距离之间的点积,但在一个维度上,这只是乘法。点积的结果是两个浮点v0和v1。这些是我们的perlin噪声实现的影响值。最后,我们在这些影响值之间平滑插值以产生平滑的噪声函数。如果这有帮助,请告诉我! This perlin noise explanation对我理解此代码非常有帮助。