佩林噪音很奇怪

时间:2014-01-21 04:21:30

标签: vb.net perlin-noise

我正在尝试在VB.Net中实现2D Perlin Noise。我花了一整天的时间来寻找解释这个主题的来源,其中最值得注意的是Hugo Elias

这篇文章。

大多数实施进展顺利。除了一个在VB.Net中似乎不起作用的非常重要的部分,导致溢出。

function Noise1(integer x, integer y)
    n = x + y * 57
    n = (n<<13) ^ n;
    return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);    
end function

在VB.net中,我将其翻译为

Private Function Noise(tX As Integer, tY As Integer) As Double
    'Return a double between -1 & 1 according to a fixed random seed
    Dim n As Integer = tX + tY * 57
    n = (n << 13) Xor n
    Return (1.0 - ((n * (n * n * 15731 + 789221) + BaseSeed) And &H7FFFFFFF) / 1073741824.0)
End Function

导致溢出的原因。

因为这个想法似乎只是简单地生成介于-1和1之间的小数。我已经创建了这个基于坐标和BaseSeed创建整数的小函数。 BaseSeed(999999)是我在游戏特定部分创造的每一种噪音的基础。

Private Function Noise(tX As Integer, tY As Integer) As Double

    Dim tSeed As Integer
    tSeed = WrapInteger(789221, BaseSeed, (tX * 1087) + (tY * 2749))
    RandomGenerator = New Random(tSeed)
    Return (RandomGenerator.Next(-10000, 10001) / 10000)

End Function

WrapInteger只是确保数字始终在整数范围内,以避免溢出错误。

Public Function WrapInteger(ByVal Lenght As Integer, ByVal Position As Integer, ByVal Movement As Integer) As Integer
    Lenght += 1
    Return ((Position + Movement) + (Lenght * ((Abs(Movement) \ Lenght) + 1))) Mod Lenght
End Function

当我用0.25,6八度的持续时间和2的起始频率发射它时,这就是我得到的。这是我缩放的128x128像素位图。

Result

任何人都知道为什么它如此线性?当我看到这张照片时,我感觉它与真相并不相同,就像它只能在一维中工作一样。所有的沉淀。

下面你会找到我的整个PerlinNoise课程。我认为剩下的就好了,但我把它添加到参考目的。此外,我还没能在互联网上找到Perlin Noise的单一VB实现。所以我想如果我能解决这个问题,它可能对其他人有所帮助。在StackOverflow上似乎有很多关于Perlin噪音故障的问题

Public Class cdPerlinNoise
Private RandomGenerator As Random
Private BaseSeed As Integer
Private Persistence As Double
Private Frequency As Integer
Private Octaves As Integer

Public Sub New(tSeed As Integer, tPersistence As Double, tOctaves As Integer, tFrequency As Integer)
    Frequency = tFrequency
    BaseSeed = tSeed
    Persistence = tPersistence
    Octaves = tOctaves
End Sub

Private Function Noise(tX As Integer, tY As Integer) As Double
    Dim tSeed As Integer
    tSeed = WrapInteger(789221, BaseSeed, (tX * 1087) + (tY * 2749))
    RandomGenerator = New Random(tSeed)
    Return (RandomGenerator.Next(-10000, 10001) / 10000)
End Function

Private Function SmoothNoise(tX As Integer, tY As Integer) As Double
    Dim Corners As Double = (Noise(tX - 1, tY - 1) + Noise(tX + 1, tY - 1) + Noise(tX - 1, tY + 1) + Noise(tX + 1, tY + 1)) / 16
    Dim Sides As Double = (Noise(tX - 1, tY) + Noise(tX + 1, tY) + Noise(tX, tY - 1) + Noise(tX, tY + 1)) / 8
    Return (Noise(tX, tY) / 4) + Corners + Sides
End Function

Private Function InterpolateCosine(tA As Double, tB As Double, tX As Double) As Double
    Dim f As Double = (1 - Cos(tX * 3.1415927)) * 0.5
    Return tA * (1 - f) + tB * f
End Function

Private Function Interpolate2D(tX As Double, tY As Double) As Double
    Dim WholeX As Integer = CInt(Fix(tX))
    Dim RemainsX As Double = tX - WholeX
    Dim WholeY As Integer = CInt(Fix(tY))
    Dim RemainsY As Double = tY - WholeY

    Dim v1 As Double = SmoothNoise(WholeX, WholeY)
    Dim v2 As Double = SmoothNoise(WholeX + 1, WholeY)
    Dim v3 As Double = SmoothNoise(WholeX, WholeY + 1)
    Dim v4 As Double = SmoothNoise(WholeX + 1, WholeY + 1)

    Dim i1 As Double = InterpolateCosine(v1, v2, RemainsX)
    Dim i2 As Double = InterpolateCosine(v3, v4, RemainsX)

    Return InterpolateCosine(i1, i2, RemainsY)

End Function

Public Function PerlinValue(tX As Double, tY As Double) As Double
    Dim Total As Double = 0
    Dim Frequency As Double
    Dim Amplitude As Double
    For i = 0 To Octaves - 1
        Frequency = Frequency ^ i
        Amplitude = Persistence ^ i
        Total = Total + (Interpolate2D(tX * Frequency, tY * Frequency) * Amplitude)
    Next
    Return Total
End Function

Public Function ScaleNoise(ByVal tX As Double, ByVal tY As Double, ByVal OutputLow As Double, ByVal OutputHigh As Double) As Double
    Dim Range1 As Double
    Dim Range2 As Double
    Dim Result As Double
    Range1 = 1 - -1
    Range2 = OutputHigh - OutputLow
    '(B*C - A*D)/R1 + n1*(R2/R1)
    Result = (((1 * OutputLow) - (-1 * OutputHigh)) / Range1) + ((PerlinValue(tX, tY) * (Range2 / Range1)))
    If Result < OutputLow Then
        Return OutputLow
    ElseIf Result > OutputHigh Then
        Return OutputHigh
    Else
        Return Result
    End If
End Function

End Class

0 个答案:

没有答案