2013-07-03 62 views
0

我看了整个互联网,并研究了柏林噪音,但是,我仍然感到困惑。使用柏林噪音生成2d瓷砖地图

我正在使用java和libgdx。我有一个Perlin类工作,并产生噪音,但我不确定它的价值是否正确。我如何检查它实际上是输出Perlin噪音?

如果我的实现是正确的,我不知道从哪里去做随机地形。我如何将Perlin噪音映射到瓷砖上?目前我有4个基本的瓷砖;水,沙子,岩石和草。

package com.bracco.thrive.world; 

import com.badlogic.gdx.Gdx; 
import com.badlogic.gdx.graphics.g2d.Sprite; 
import com.badlogic.gdx.graphics.g2d.SpriteBatch; 
import com.badlogic.gdx.graphics.g2d.TextureRegion; 
import com.badlogic.gdx.graphics.GL10; 
import com.badlogic.gdx.graphics.Texture; 
public class WorldGeneration { 

Perlin noise = new Perlin(); 
private SpriteBatch spriteBatch; 
//private boolean debug = false; 
private TextureRegion[] regions = new TextureRegion[4]; 
private Texture texture; 

float x = 110; 
float y = 120; 
float originX = 0; 
float originY = 16; 
float width = 16; 
float height = 16; 
float scaleX = 1; 
float scaleY = 1; 
float rotation = 1; 


@SuppressWarnings("static-access") 
public void createWorld(){ 
    spriteBatch = new SpriteBatch(); 
    texture = new Texture(Gdx.files.internal("assets/data/textures/basictextures.png")); 

    regions[0] = new TextureRegion(texture,0,0,16,16); //grass 
    regions[1] = new TextureRegion(texture,16,0,16,16); //water 
    regions[2] = new TextureRegion(texture,0,17,16,16); //sand 
    regions[3] = new TextureRegion(texture,17,17,16,16); //rock 
    float[][] seed = noise.GenerateWhiteNoise(50, 50); 
    for (int i = 0;i < seed.length; i++){ 
     for (int j = 0; j < seed[i].length; j++){ 
      System.out.println(seed[i][j] + " "); 
     } 
    } 
    float[][] seedE = noise.GenerateSmoothNoise(seed, 6); 
    for (int i = 0;i < seedE.length; i++){ 
      for (int j = 0; j < seedE[i].length; j++){ 
       System.out.println(seedE[i][j] + " "); 
      } 

    } 
    float[][] perlinNoise = noise.GeneratePerlinNoise(seedE, 8); 
    for (int i = 0;i < perlinNoise.length; i++){ 
      for (int j = 0; j < perlinNoise[i].length; j++){ 
       System.out.println(perlinNoise[i][j] + " "); 
      } 
     } 
} 

public void render(){ 
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); 
    spriteBatch.begin(); 
    //spriteBatch.draw(texture, 0, 0, 16, 16); 
    for (int i = 0; i < regions.length; i++){ 
     spriteBatch.draw(regions[i],75 * (i + 1),100); 
    } 
    spriteBatch.end(); 
} 



} 


package com.bracco.thrive.world; 

    import java.util.Random; 

    public class Perlin { 

    public static float[][] GenerateWhiteNoise(int width,int height){ 

     Random random = new Random((long) (Math.round(Math.random() * 100 * Math.random() * 10))); //Seed to 0 for testing 
     float[][] noise = new float[width][height]; 

     for (int i = 0; i < width; i++) 
     { 
      for (int j = 0; j < height; j++){ 
       noise[i][j] = (float)(Math.random() % 1); 
      } 
     } 

     return noise; 
    } 

    float[][] GenerateSmoothNoise(float[][] baseNoise, int octave) 
    { 
     int width = baseNoise.length; 
     int height = baseNoise.length; 

     float[][] smoothNoise = new float[width][height]; 

     int samplePeriod = 1 << octave; // calculates 2^k 
     float sampleFrequency = 1.0f/samplePeriod; 

     for (int i = 0; i < width; i++) 
     { 
      //calculate the horizontal sampling indices 
      int sample_i0 = (i/samplePeriod) * samplePeriod; 
      int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around 
      float horizontal_blend = (i - sample_i0) * sampleFrequency; 

      for (int j = 0; j < height; j++) 
      { 
      //calculate the vertical sampling indices 
      int sample_j0 = (j/samplePeriod) * samplePeriod; 
      int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around 
      float vertical_blend = (j - sample_j0) * sampleFrequency; 

      //blend the top two corners 
      float top = Interpolate(baseNoise[sample_i0][sample_j0], 
       baseNoise[sample_i1][sample_j0], horizontal_blend); 

      //blend the bottom two corners 
      float bottom = Interpolate(baseNoise[sample_i0][sample_j1], 
       baseNoise[sample_i1][sample_j1], horizontal_blend); 

      //final blend 
      smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend); 
      } 
     } 

     return smoothNoise; 
    } 

    float Interpolate(float x0, float x1, float alpha) 
    { 
     return x0 * (1 - alpha) + alpha * x1; 
    } 

    float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount) 
    { 
     int width = baseNoise.length; 
     int height = baseNoise[0].length; 

     float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing 

     float persistance = 0.5f; 

     //generate smooth noise 
     for (int i = 0; i < octaveCount; i++) 
     { 
      smoothNoise[i] = GenerateSmoothNoise(baseNoise, i); 
     } 

     float[][] perlinNoise = new float[width][height]; 
     float amplitude = 1.0f; 
     float totalAmplitude = 0.0f; 

     //blend noise together 
     for (int octave = octaveCount - 1; octave >= 0; octave--) 
     { 
      amplitude *= persistance; 
      totalAmplitude += amplitude; 

      for (int i = 0; i < width; i++) 
      { 
       for (int j = 0; j < height; j++) 
       { 
       perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude; 
       } 
      } 
     } 

     //normalisation 
     for (int i = 0; i < width; i++) 
     { 
      for (int j = 0; j < height; j++) 
      { 
      perlinNoise[i][j] /= totalAmplitude; 
      } 
     } 

     return perlinNoise; 
    } 
} 
+3

您是否遇到错误?什么是错误?还是它不能按照你的意图工作?尝试制作一个你想要的东西和你想要的东西的截图。 – Dariusz

+0

我想你的问题是你想要某种像素着色器来覆盖你的基本纹理与噪音 - 我建议你重新形成你的问题更具体。我对像素着色器了解不多,但是如果没有它们,我想你需要用嘈杂的瓷砖创建新的纹理。 – kutschkem

+0

我没有看到你的代码中哪里你真的试图使用你的噪音。 – Jyro117

回答

4

柏林噪声
的正确性关于如果你的柏林噪声是 '正确的';最简单的方法来查看您的perlin噪声(或基于perlin噪声几个八度的技术上的分形噪声)正在工作是使用perlin噪声的值生成灰度图像,该图像应该看起来像某种景观(起伏的山丘,或取决于你选择的持久性的参数山(以及在较少程度八度音阶的数目)Perlin杂的一些实例是:

低Persisance:
Persisance of 0.5

高Persisance:
Persisance of 0.7

高Persisance(缩小):
enter image description here

这些灰度图像由下面的代码

import java.awt.Color; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO; 

public class ImageWriter { 
    //just convinence methods for debug 

    public static void greyWriteImage(double[][] data){ 
     //this takes and array of doubles between 0 and 1 and generates a grey scale image from them 

     BufferedImage image = new BufferedImage(data.length,data[0].length, BufferedImage.TYPE_INT_RGB); 

     for (int y = 0; y < data[0].length; y++) 
     { 
      for (int x = 0; x < data.length; x++) 
      { 
      if (data[x][y]>1){ 
       data[x][y]=1; 
      } 
      if (data[x][y]<0){ 
       data[x][y]=0; 
      } 
       Color col=new Color((float)data[x][y],(float)data[x][y],(float)data[x][y]); 
      image.setRGB(x, y, col.getRGB()); 
      } 
     } 

     try { 
      // retrieve image 
      File outputfile = new File("saved.png"); 
      outputfile.createNewFile(); 

      ImageIO.write(image, "png", outputfile); 
     } catch (IOException e) { 
      //o no! 
     } 
    } 


    public static void main(String args[]){ 
     double[][] data=new double[2][4]; 
     data[0][0]=0.5; 
     data[0][5]=1; 
     data[1][0]=0.7; 
     data[1][6]=1; 

     greyWriteImage(data); 
    } 
} 

此代码假定每个条目将介于0产生和1,但perlin噪音通常产生-1和1之间,根据你的implimentation规模。假设你的Perlin杂会给对任意x的值,y,则可以使用下面的代码

//generates 100 by 100 data points within the specified range 

    double iStart=0; 
    double iEnd=500; 
    double jStart=0; 
    double jEnd=500; 

    double[][] result=new double[100][100]; 

    for(int i=0;i<100;i++){ 
     for(int j=0;j<100;j++){ 
      int x=(int)(iStart+i*((iEnd-iStart)/100)); 
      int y=(int)(jStart+j*((jEnd-jStart)/100)); 
      result[i][j]=0.5*(1+perlinNoise.getNoise(x,y)); 
     } 
    } 

    ImageWriter.greyWriteImage(result); 

我的执行力度预计整数x和y运行此。随意修改,如果这不是你

映射到瓷砖
的情况下,这完全取决于你,你需要定义Perlin的噪声值的一定范围内产生一定的瓷砖。然而,请注意perlin噪声偏向于0.假设2D可以通过半景观地比较景观类比,低值=水,低值=沙,中等值=草,高值=雪,可以获得很好的结果。

另外请注意,在一些实现中(例如,我的世界生物群系和洞穴),将几个随机值组合在一起创建一个总体结果。见https://softwareengineering.stackexchange.com/questions/202992/randomization-of-biomes/203040#203040

思路改进
如果您发现Perlin杂一代太慢再考虑单纯的噪音,它具有非常相似的特性,但更有效(尤其是在高dimentions)。单纯形噪声在数学上要复杂得多。

3

我意识到这是一个有点老的问题,但我想发布我的解决方案,因为我发现很难找到工作示例。

我也在研究这个问题,起初我发现你的代码有用,因为它在外观上缝合工作,但是当我想改变图像的大小时,光滑的噪声不能适当地缩放,我找不到一种修复你的代码的方法。

经过更多的研究,我发现你的SmoothNoise非常狡猾的实现,所以我重新实现它从一个可靠的来源(http://lodev.org/cgtutor/randomnoise.html)。

这里是我的噪声级,它可以产生与任何一种噪音的工作:

package com.heresysoft.arsenal.utils; 

public class Noise 
{ 

    public static double[] blend(double[] noise1, double[] noise2, double persistence) 
    { 
     if (noise1 != null && noise2 != null && noise1.length > 0 && noise1.length == noise2.length) 
     { 
      double[] result = new double[noise1.length]; 
      for (int i = 0; i < noise1.length; i++) 
       result[i] = noise1[i] + (noise2[i] * persistence); 
      return result; 
     } 

     return null; 
    } 

    public static double[] normalize(double[] noise) 
    { 
     if (noise != null && noise.length > 0) 
     { 
      double[] result = new double[noise.length]; 

      double minValue = noise[0]; 
      double maxValue = noise[0]; 
      for (int i = 0; i < noise.length; i++) 
      { 
       if (noise[i] < minValue) 
        minValue = noise[i]; 
       else if (noise[i] > maxValue) 
        maxValue = noise[i]; 
      } 

      for (int i = 0; i < noise.length; i++) 
       result[i] = (noise[i] - minValue)/(maxValue - minValue); 

      return result; 
     } 

     return null; 
    } 

    public static double[] perlinNoise(int width, int height, double exponent) 
    { 
     int[] p = new int[width * height]; 
     double[] result = new double[width * height]; 
     /*final int[] permutation = {151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 
            190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 
            20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 
            220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 
            200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 
            118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 
            154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 
            218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 
            214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 
            72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180};*/ 

     for (int i = 0; i < p.length/2; i++) 
      p[i] = p[i + p.length/2] = (int) (Math.random() * p.length/2);//permutation[i]; 

     for (int i = 0; i < width; i++) 
     { 
      for (int j = 0; j < height; j++) 
      { 
       double x = i * exponent/width;        // FIND RELATIVE X,Y,Z 
       double y = j * exponent/height;        // OF POINT IN CUBE. 
       int X = (int) Math.floor(x) & 255;     // FIND UNIT CUBE THAT 
       int Y = (int) Math.floor(y) & 255;     // CONTAINS POINT. 
       int Z = 0; 
       x -= Math.floor(x);        // FIND RELATIVE X,Y,Z 
       y -= Math.floor(y);        // OF POINT IN CUBE. 
       double u = fade(x);        // COMPUTE FADE CURVES 
       double v = fade(y);        // FOR EACH OF X,Y,Z. 
       double w = fade(Z); 
       int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z,  // HASH COORDINATES OF 
         B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z;  // THE 8 CUBE CORNERS, 

       result[j + i * width] = lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, Z), // AND ADD 
                  grad(p[BA], x - 1, y, Z)), // BLENDED 
                lerp(u, grad(p[AB], x, y - 1, Z), // RESULTS 
                  grad(p[BB], x - 1, y - 1, Z))),// FROM 8 
              lerp(v, lerp(u, grad(p[AA + 1], x, y, Z - 1), // CORNERS 
                  grad(p[BA + 1], x - 1, y, Z - 1)), // OF CUBE 
                lerp(u, grad(p[AB + 1], x, y - 1, Z - 1), grad(p[BB + 1], x - 1, y - 1, Z - 1)))); 
      } 
     } 
     return result; 
    } 

    public static double[] smoothNoise(int width, int height, double zoom) 
    { 
     if (zoom > 0) 
     { 
      double[] noise = whiteNoise(width, height); 
      double[] result = new double[width * height]; 
      for (int i = 0; i < width; i++) 
      { 
       for (int j = 0; j < height; j++) 
       { 
        double x = i/zoom; 
        double y = j/zoom; 

        // get fractional part of x and y 
        double fractX = x - (int) x; 
        double fractY = y - (int) y; 

        // wrap around 
        int x1 = ((int) x + width) % width; 
        int y1 = ((int) y + height) % height; 

        // neighbor values 
        int x2 = (x1 + width - 1) % width; 
        int y2 = (y1 + height - 1) % height; 

        // smooth the noise with bilinear interpolation 
        result[j + i * width] = fractX * fractY * noise[y1 + x1 * width] 
              + fractX * (1 - fractY) * noise[y2 + x1 * width] 
              + (1 - fractX) * fractY * noise[y1 + x2 * width] 
              + (1 - fractX) * (1 - fractY) * noise[y2 + x2 * width]; 
       } 
      } 

      return result; 
     } 

     return null; 
    } 

    public static double[] turbulence(int width, int height, double zoom) 
    { 
     // http://lodev.org/cgtutor/randomnoise.html 
     double[] result = new double[width * height]; 
     double initialZoom = zoom; 

     while (zoom >= 1) 
     { 
      result = blend(result, smoothNoise(width, height, zoom), zoom); 
      zoom /= 2.0; 
     } 

     for (int i = 0; i < result.length; i++) 
      result[i] = (128.0 * result[i]/initialZoom); 

     return result; 
    } 

    public static double[] whiteNoise(int width, int height) 
    { 
     double[] result = new double[width * height]; 
     for (int i = 0; i < width * height; i++) 
      result[i] = Math.random(); 
     return result; 
    } 

    private static double fade(double t) 
    { 
     return t * t * t * (t * (t * 6 - 15) + 10); 
    } 

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

    private static double grad(int hash, double x, double y, double z) 
    { 
     int h = hash & 15;      // CONVERT LO 4 BITS OF HASH CODE 
     double u = h < 8 ? x : y,     // INTO 12 GRADIENT DIRECTIONS. 
       v = h < 4 ? y : h == 12 || h == 14 ? x : z; 
     return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); 
    } 

} 

下面是如何使用smoothNoise函数的一个例子:

 double[] data = Noise.normalize(Noise.smoothNoise(width, height, 32)); 

     for (int i = 0; i < data.length; i++) 
      data[i] = 255*data[i]; 

     BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); 
     img.getRaster().setPixels(0, 0, width, height, data); 

这里是一个如何使用湍流功能的示例:

 double[] data = Noise.normalize(Noise.turbulence(width, height, 32)); 

     for (int i = 0; i < data.length; i++) 
      data[i] = 255*data[i]; 

     BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); 
     img.getRaster().setPixels(0, 0, width, height, data); 

下面是一个如何使用per linNoise功能:

 double[] data = Noise.normalize(Noise.perlinNoise(width, height, 7)); 

     for (int i = 0; i < data.length; i++) 
      data[i] = 255 * data[i]; 

     BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); 
     img.getRaster().setPixels(0, 0, width, height, data);