2013-07-02 81 views
1

我使用珀林噪聲來生成2D高度圖。起初我手動嘗試了一些參數,並發現振幅,持續性,...對我的工作很好的組合。佩林噪聲值範圍

現在我正在開發該程序,我添加了用戶更改地圖參數併爲自己製作新地圖的功能,但現在我發現對於某些參數(大多數八度和頻率),值不在我曾經看到的範圍。我認爲如果一組振幅= 20,我從它得到的值(高度)將在[0,20]或[-10,10]或[-20,20]範圍內,但現在我看到振幅是不是控制輸出範圍的唯一參數。

我的問題是:是否有一個精確的數學公式(幅,倍頻,頻率和持續性的函數)來計算的範圍內,或者我應該走了不少的樣品(如100,000),並檢查最小值和最大值他們猜測的近似範圍?

注意:下面的代碼是一個perlin噪聲的實現,其中一個stackoverflow的傢伙把它放在C中,我將它移植到java中。

PerlinNoiseParameters.java

public class PerlinNoiseParameters { 

    public double persistence; 
    public double frequency; 
    public double amplitude; 
    public int octaves; 
    public int randomseed; 

    public PerlinNoiseParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) { 
     this.ChangeParameters(persistence, frequency, amplitude, octaves, randomseed); 
    } 

    public void ChangeParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) { 
     this.persistence = persistence; 
     this.frequency = frequency; 
     this.amplitude = amplitude; 
     this.octaves = octaves; 
     this.randomseed = 2 + randomseed * randomseed; 
    } 
} 

PerlinNoiseGenerator.java

public class PerlinNoiseGenerator { 

    PerlinNoiseParameters parameters; 

    public PerlinNoiseGenerator() { 
    } 

    public PerlinNoiseGenerator(PerlinNoiseParameters parameters) { 
     this.parameters = parameters; 
    } 

    public void ChangeParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) { 
     parameters.ChangeParameters(persistence, frequency, amplitude, octaves, randomseed); 
    } 

    public void ChangeParameters(PerlinNoiseParameters newParams) { 
     parameters = newParams; 
    } 

    public double get(double x, double y) { 
     return parameters.amplitude * Total(x, y); 
    } 

    private double Total(double i, double j) { 
     double t = 0.0f; 
     double _amplitude = 1; 
     double freq = parameters.frequency; 

     for (int k = 0; k < parameters.octaves; k++) { 
      t += GetValue(j * freq + parameters.randomseed, i * freq + parameters.randomseed) 
        * _amplitude; 
      _amplitude *= parameters.persistence; 
      freq *= 2; 
     } 

     return t; 
    } 

    private double GetValue(double x, double y) { 
     int Xint = (int) x; 
     int Yint = (int) y; 

     double Xfrac = x - Xint; 
     double Yfrac = y - Yint; 

     double n01 = Noise(Xint - 1, Yint - 1); 
     double n02 = Noise(Xint + 1, Yint - 1); 
     double n03 = Noise(Xint - 1, Yint + 1); 
     double n04 = Noise(Xint + 1, Yint + 1); 
     double n05 = Noise(Xint - 1, Yint); 
     double n06 = Noise(Xint + 1, Yint); 
     double n07 = Noise(Xint, Yint - 1); 
     double n08 = Noise(Xint, Yint + 1); 
     double n09 = Noise(Xint, Yint); 
     double n12 = Noise(Xint + 2, Yint - 1); 
     double n14 = Noise(Xint + 2, Yint + 1); 
     double n16 = Noise(Xint + 2, Yint); 
     double n23 = Noise(Xint - 1, Yint + 2); 
     double n24 = Noise(Xint + 1, Yint + 2); 
     double n28 = Noise(Xint, Yint + 2); 
     double n34 = Noise(Xint + 2, Yint + 2); 

     double x0y0 = 0.0625 * (n01 + n02 + n03 + n04) + 0.1250 
       * (n05 + n06 + n07 + n08) + 0.2500 * n09; 

     double x1y0 = 0.0625 * (n07 + n12 + n08 + n14) + 0.1250 
       * (n09 + n16 + n02 + n04) + 0.2500 * n06; 

     double x0y1 = 0.0625 * (n05 + n06 + n23 + n24) + 0.1250 
       * (n03 + n04 + n09 + n28) + 0.2500 * n08; 

     double x1y1 = 0.0625 * (n09 + n16 + n28 + n34) + 0.1250 
       * (n08 + n14 + n06 + n24) + 0.2500 * n04; 

     double v1 = Interpolate(x0y0, x1y0, Xfrac); 
     double v2 = Interpolate(x0y1, x1y1, Xfrac); 

     double fin = Interpolate(v1, v2, Yfrac); 

     return fin; 
    } 

    private double Interpolate(double x, double y, double a) { 
     double negA = 1.0 - a; 
     double negASqr = negA * negA; 
     double fac1 = 3.0 * (negASqr) - 2.0 * (negASqr * negA); 
     double aSqr = a * a; 
     double fac2 = 3.0 * aSqr - 2.0 * (aSqr * a); 

     return x * fac1 + y * fac2; 
    } 

    private double Noise(int x, int y) { 
     int n = x + y * 57; 
     n = (n << 13)^n; 
     int t = (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff; 
     return 1.0 - (double) t * 0.931322574615478515625e-9; 
    } 
} 
+0

其值得注意的是,結果來自per林噪聲大量歸零,所以即使[-10,10]是全頻範圍,你只能定期看到該範圍的中心,例如[-5,5]。我相信如果你採取了一個下流的樣本數量,範圍將始終是[-amplitude,amplitude] –

+0

@RichardTingle,所以你建議採樣方法,因爲它更實際可用。對? –

+0

是的,沒有。我有一個簡單的噪聲發生器作爲我的程序的一部分(單純噪聲是珀林噪聲的升級),如果我要求1000個樣本,最小/最大值爲-0.67/0.77,最小/最大值爲100000個樣本爲-0.83 /0.80,如果我要求10000000個樣本的-0.84/0.87。 –

回答

1

這不是個八度和頻率影響振幅,不能直接至少一個問題。這是整數溢出的問題。因爲你將它添加到x和y座標介紹你的隨機種子(這是不尋常的,我不認爲這是通常的執行力度)

t += GetValue(j * freq + parameters.randomseed, i * freq + parameters.randomseed)* _amplitude; 

和隨機種子可能是巨大的(可能是附近的INT的全尺寸),因爲

this.randomseed = 2 + randomseed * randomseed; 

所以,如果你輸入J和我你最終是通過在GetValue(double x, double y)比爲int的最大大小通過了雙打,在這一點上,當大的值您致電

int Xint = (int) x; 
int Yint = (int) y; 

XINT和YInt不會像X和Y的任何東西(因爲x和y可能是巨大的!)等

double Xfrac = x - Xint; 
double Yfrac = y - Yint; 

可能是很多更大的是1,允許不介於-1和1的值被退回。

使用合理的和小的值使用你的代碼我的範圍是-1和1(振幅1)


作爲asside之間,在通常的java方法名methodName,不MethodName

如果有用的話,請在這裏找到另一個java perlin噪聲的實現: http://mrl.nyu.edu/~perlin/noise/

+0

謝謝!所以我應該看看肯佩林的真正實施!關於'camelNotation':當我將源代碼從C移植到java時,我忘了重構這些名字,無論如何感謝您的建議:) –

+0

@Mjafar真棒,對不起「我有一個答案」,然後沉默了半個小時 –

+0

沒有需要抱歉!實際上與此同時我正在研究項目的另一部分,我沒有注意到時間的流逝!你也很忙,我不期待即時的答案!謝謝 :) –