2013-10-04 103 views
3

所以我試圖生成perlin噪聲並將其保存爲圖像文件。我已經正確保存了圖像,但噪音看起來不像佩林噪音。Java中的Perlin噪聲問題

這裏是我的代碼:

package com.egs.survivalsim.util; 

import java.awt.Color; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 

import javax.imageio.ImageIO; 

import com.egs.survivalsim.MainComponent; 

public class Noise { 

    MainComponent main; 

    public double noise(int x,int y){ 
     x = x + y * 57; 
     x = ((x << 13)^x); 
     double t = (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff; 
     return 1 - t * 0.000000000931322574615478515625; 
    } 

    public double sNoise(int x, int y){ 
     double corners = (noise(x - 1, y - 1) + noise(x + 1, y - 1) + noise(x - 1, y + 1) + noise(x + 1, y + 1)) * 0.0625; 
     double sides = (noise(x - 1, y) + noise(x + 1, y) + noise(x, y - 1) + noise(x, y + 1)) * 0.125; 
     double center = noise(x, y) * 0.25; 
     return corners + sides + center;   
    } 

    public double lInterpoleLin(double a, double b, double x){ 
     return a * (1 - x) + b * x;  
    } 

    public double lInterpoleCos(double a, double b, double x){ 
     double ft = x * 3.1415927; 
     double f = (1 - Math.cos(ft)) * 0.001; 
     return a * (1 - f) + b * f; 
    } 

    public double iNoise(double x, double y){ 
     int iX = (int) x; 
     int iY = (int) y; 
     double dX = x - iX; 
     double dY = y - iY; 
     double p1 = sNoise(iX, iY); 
     double p2 = sNoise(iX + 1, iY); 
     double p3 = sNoise(iX, iY + 1); 
     double p4 = sNoise(iX + 1, iY + 1); 
     double i1 = lInterpoleCos(p1 ,p2 ,dX); 
     double i2 = lInterpoleCos(p3, p4, dX); 
     return lInterpoleCos(i1, i2, dY); 
    } 

    public double pNoise(double x, double y, double persistence, int octave){ 
     double result; 
     double amplitude = 1; 
     int frequence = 1; 
     result = 0; 
     for(int n = 0; n < octave; n++){ 
      frequence <<= 1; 
      amplitude *= persistence; 
      result += iNoise(x * frequence, y * frequence) * amplitude; 
     } 
     return result; 
    } 

    public void startNoise(MainComponent main){ 
     System.out.println("Generating noise map"); 
     this.main = main; 
     System.out.println("Width: " + main.worldWidth); 
     System.out.println("Height: " + main.worldHeight); 
     BufferedImage image = new BufferedImage(main.worldWidth, main.worldHeight, BufferedImage.TYPE_INT_RGB); 
     for(int y = 0; y < main.worldHeight; y++){ 
      for(int x = 0; x < main.worldWidth; x++){ 
       double c = pNoise((double) x - main.worldWidth, (double) y - main.worldHeight, 0.2, 2); 

       c *= 128.0; 
       c += 127.0; 
       if(c > 255.0){ 
        c = 255.0; 
       } 
       if(c < 0.0){ 
        c = 0.0; 
       } 

       int r = (int) c; 
       int g = (int) c; 
       int b = (int) c; 

       if(c>128) 
        r>>=1; 
        if(c>128) 
        b>>=1; 


       int color = new Color(r, g, b).getRGB(); 

       image.setRGB(x, y, color); 
       main.noiseArray[x][y] = (int) c; 
      } 
     } 

     File fileImage = new File("noise.png"); 
     try { 
      ImageIO.write(image, "png", fileImage); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Noise map generated"); 
    } 
} 
+2

這是代碼直接進入StackOverflow問題的首選實踐。我們希望這個問題(和答案)從現在開始有意義,誰知道pastbin鏈接將保持有效多久? –

+0

@BobGilmore優秀點。我插入了代碼和小(<21 KB)圖像。 –

回答

1

沒有,這的確看起來有點怪。首先,噪音的產生似乎存在一個問題。其次,我不知道你爲什麼要製作彩色圖像。最快可能的解決方案是查看最新的出版物Ken Perlin,並查看他的reference implementation

用一個簡單的複製&粘貼和幾行額外的java代碼,你會看到一個漂亮的圖像。

enter image description here

請注意,我真的只是砍死下來,這意味着我按比例取樣範圍手動,使其看起來不錯,因爲我不知道在該範圍內的培林噪聲是價值觀,我只是重新縮放數組以適合範圍[0,255]。

在下面的代碼中,只有main是重要的。其餘的是從Perlin複製的。

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

public class Noise { 

    static final int p[] = new int[512], 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 
    }; 

    static { 
    for (int i = 0; i < 256; i++) p[256 + i] = p[i] = permutation[i]; 
    } 

    static public double noise(double x, double y, double z) { 
    int X = (int) Math.floor(x) & 255,     // FIND UNIT CUBE THAT 
     Y = (int) Math.floor(y) & 255,     // CONTAINS POINT. 
     Z = (int) Math.floor(z) & 255; 
    x -= Math.floor(x);        // FIND RELATIVE X,Y,Z 
    y -= Math.floor(y);        // OF POINT IN CUBE. 
    z -= Math.floor(z); 
    double u = fade(x),        // COMPUTE FADE CURVES 
     v = fade(y),        // FOR EACH OF X,Y,Z. 
     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, 

    return 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)))); 
    } 

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

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

    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); 
    } 

    public static void main(String[] args) { 
    final int WIDTH = 2 * 256, HEIGHT = 256; 

    double[] data = new double[WIDTH * HEIGHT]; 
    int count = 0; 

    for (int y = 0; y < HEIGHT; y++) { 
     for (int x = 0; x < WIDTH; x++) { 
     data[count++] = PerlinNoise.noise(20.0 * x/WIDTH, 10.0 * y/HEIGHT, 0); 
     } 
    } 

    double minValue = data[0], maxValue = data[0]; 
    for (int i = 0; i < data.length; i++) { 
     minValue = Math.min(data[i], minValue); 
     maxValue = Math.max(data[i], maxValue); 
    } 

    int[] pixelData = new int[WIDTH * HEIGHT]; 
    for (int i = 0; i < data.length; i++) { 
     pixelData[i] = (int) (255 * (data[i] - minValue)/(maxValue - minValue)); 
    } 

    BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_BYTE_GRAY); 
    img.getRaster().setPixels(0, 0, WIDTH, HEIGHT, pixelData); 

    File output = new File("image.jpg"); 
    try { 
     ImageIO.write(img, "jpg", output); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    } 
}