2014-10-28 304 views
1

我一直在試驗perlin noie世代的遊戲,我想編程,但我遇到了一些奇怪的結果。當我讓我的代碼運行,並繪製灰度我獲得下面的圖片結果:Perlin噪聲發生器的奇怪結果

enter image description here

我基於Perlin雜維基百科頁面和參考頁面(下面的鏈接)的一個我的代碼。基於半隨機向量的預生成網格,可以生成每點Perlin噪聲點。

public static double[][] generateMap(long seed, int width, int height) { 
    double[][] map = new double[width][height]; 
    double[][][] grid = generateGrid(seed, (int) (width/10)+1, (int) (height/10)+1); 
    double max = Double.MIN_VALUE; 
    for (int i = 0; i < map.length; i++) { 
     for (int j = 0; j < map[0].length; j++) { 
      double p = perlinNoise(((double) i)/10, ((double) j)/10, grid); 
      map[i][j] = p; 
      max = (max < p) ? p : max; 
     } 
    } 
    for (int i = 0; i < map.length; i++) { 
     for (int j = 0; j < map[0].length; j++) { 
      map[i][j] = map[i][j]/max; 
     } 
    } 
    return map; 
} 

private static double perlinNoise(double x, double y, double[][][] grid) { 
    int x0 = ((x < 0) ? (int) x-1 : (int) x); 
    int y0 = ((y < 0) ? (int) y-1 : (int) y); 
    int x1 = x0 + 1; 
    int y1 = y0 + 1; 

    double tx = x - (double)x0; 
    double ty = y - (double)y0; 
    double wx = tx*tx*(3-2*tx); 
    double wy = ty*ty*(3-2*ty); 

    double l0, l1, ix, iy, p; 
    l0 = dotGrid(x0, y0, x, y, grid); 
    l1 = dotGrid(x1, y0, x, y, grid); 
    ix = cerp(l0, l1, wx); 
    l0 = dotGrid(x0, y1, x, y, grid); 
    l1 = dotGrid(x1, y1, x, y, grid); 
    iy = cerp(l0, l1, wx); 
    p = cerp(ix, iy, wy); 

    return p; 
} 

private static double lerp(double a, double b, double w) { 
    return (1.0f - w)*a + w*b; 
} 

private static double cerp(double a, double b, double w) { 
    double ft = w * 3.1415927; 
    double f = (1 - Math.cos(ft)) * 0.5; 
    return a*(1-f) + b*f; 
} 

private static double dotGrid(int i, int j, double x, double y, double[][][] grid) { 
    double dx = x - i; 
    double dy = y - j; 
    return (dx*grid[i][j][0] + dy*grid[i][j][1]); 

} 

private static double[][][] generateGrid(long seed, int width, int height) { 
    Random r = new Random(seed); 
    double[][][] grid = new double[width][height][2]; 
    for (int i = 0; i < grid.length; i++) { 
     for (int j = 0; j < grid[0].length; j++) { 
      double x = r.nextFloat(); 
      double y = r.nextFloat(); 
      double v = Math.sqrt((x*x) + (y*y)); 
      grid[i][j][0] = x/v; 
      grid[i][j][1] = y/v; 
     } 
    } 
    return grid; 
} 

對於那些想測試我的代碼也將包括我的渲染方法:

private void drawMap(double[][] map, Graphics g) { 
    for (int i = 0; i < map.length; i++) { 
     for (int j = 0; j < map[0].length; j++) { 
      float d = (float) Math.abs(map[i][j]); 
      d = (d > 1.0f) ? 1.0f : d; 
      Color c = new Color(d, d, d); 
      g.setColor(c); 
      g.fillRect(i, j, 1, 1); 
     } 
    } 
} 

我希望有人能告訴我爲什麼我在我的噪點來得到這些奇怪的迷宮一樣的結構和如何擺脫它們。

來源:

http://en.wikipedia.org/wiki/Perlin_noise

http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html

回答

7

有兩個小問題,這加起來給你看有趣的模式。我用C語言測試了網格大小爲21x21,輸出大小爲200x200和隨機種子爲1234的東西,但事情應該在Java中同樣適用。

我比較原始圖像(不同的模式,由於種子,但基本上和你的一樣):

original

的第一個問題是generateGrid()由於您選擇初始隨機值。通過使用nextFloat()你是有限的值從0到1,而不是-1所需範圍爲1。要解決這個很簡單:

double x = r.nextFloat()*2.0 - 1.0; 
double y = r.nextFloat()*2.0 - 1.0; 

,並應讓你像:

fixed 1

這是一個有趣的模式,可能對某些情況有用,但不是「正常的」柏林噪音。下一個問題是您將地圖值縮放爲一種顏色。你正在服用的絕對值,但我相信一個更好的方法是升檔和像generateMap()功能(未測試)重新調整:

double max = Double.MIN_VALUE; 
double min = Double.MAX_VALUE; 

for (int i = 0; i < map.length; i++) { 
    for (int j = 0; j < map[0].length; j++) { 
     double p = perlinNoise(((double) i)/10, ((double) j)/10, grid); 
     map[i][j] = p; 
     max = (max < p) ? p : max; 
     min = (min > p) ? p : min; 
    } 
} 

for (int i = 0; i < map.length; i++) { 
    for (int j = 0; j < map[0].length; j++) { 
     map[i][j] = (map[i][j] - min)/(max - min); //Limit 0 to 1 
    } 
} 

應限制映射值0-1值,這使得您的輸出代碼也非常簡單。這導致一個更好的柏林噪聲輸出:

fixed 2

我認爲這是「正常」的柏林噪聲,至少我看不到任何其他的問題,無法得到任何通過測試更好。爲了獲得「更好」的噪音,你必須一起增加多個噪音頻率。

圖像色彩縮放函數的另一個噪聲值我見過的Perlin噪聲只需要-1.0爲黑色和1。0是白色的,讓你像:

fixed 3

這基本上是一樣的最後一個,但有些不夠對比。真的如何將噪聲值縮放到一種顏色取決於你。佩林噪聲的一個很好的資源是LibNoise library。它是C++,但很容易閱讀,並有很多資源。

+0

感謝您的幫助,它顯着改善了我的代碼輸出。然而,我還不完全滿足。我可能應該在我的第一篇文章中說明了這一點,但我正在尋找一種更多像陰雲一樣蓬鬆的輸出,而不是我現在得到的東西。我已經考慮過使用八度音的方法,這裏解釋:http://freespace.virgin.net/hugo.elias/models/m_perlin.htm,但不知何故,我覺得這種方法效率很低。 – Exevan 2014-10-28 15:58:23

+0

是的,爲了得到「雲」,你必須一起添加多個柏林噪音八度。 – uesp 2014-10-28 16:25:07

3

請記住,Perlin噪聲是一種較舊的算法,即使通過uesp提供的修復,仍然會通過將其所有特徵與基本軸和45度對角線一起顯示在視覺上顯着的網格僞影。在我看來,現在沒有什麼理由使用柏林噪音了。

看看一些所謂的OpenSimplex噪音:布林和OpenSimplex(的3D功能,2D片)之間https://gist.github.com/KdotJPG/b1270127455a94ac5d19

比較射擊

enter image description here

  • 左噪音(X,Y ,0)灰度
  • 接下來是噪聲(x,y,0)> 0?白色:黑色
  • 接下來是| noise(x,y,0)| > 0.1?白:黑
  • 接下來是噪聲(X,Y,0.5)灰度

注意OpenSimplex噪聲和單工噪聲是兩個不同的算法。在大多數實現中,單純形噪聲比OpenSimplex具有更多的僞像,並且3D +中的Simplex已獲得專利。