2014-10-28 131 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已获得专利。