Search code examples
2dinterpolationsmoothingnoiseperlin-noise

Perlin Noise Assistance


Ok so I found this article and I am confused by some parts of it. If anyone can explain this process in more depth to me I would greatly appreciate it because I have been trying to code this for 2 months now and still have not gotten a correct version working yet. I am specifically confused about the Persistence part of the article because I mostly do not understand what the author is trying to explain about it and at the bottom of the article he talks about a 2D pseudo code implementation of this but the PerlinNoise_2D function does not make sense to me because after the random value is smoothed and interpolated, it is an integer value but the function takes float values? Underneath the persistence portion there is the octaves part. I do not quite understand because he "adds" the smoothed functions together to get the Perlin function. What does he mean by"adds" because you obviously do not add the values together. So if anyone can explain these parts to me I would be very happy. Thanks.

Here is my code:

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class TerrainGen extends JPanel {

public static int layers = 3;
public static float[][][][] noise = new float[16][16][81][layers];
public static int[][][][] octaves = new int[16][16][81][layers];
public static int[][][][] perlin = new int[16][16][81][layers];
public static int[][][] perlinnoise = new int[16][16][81];
public static int SmoothAmount = 3;
public static int interpolate1 = 0;
public static int interpolate2 = 10;
public static double persistence = 0.25;

//generate noise
//smooth noise
//interpolate noise
//perlin equation

public TerrainGen() {
    for(int t = 0; t < layers; t++) {
        for(int z = 0; z < 81; z++) {
            for(int y = 0; y < 16; y++) {
                for(int x = 0; x < 16; x++) {
                    noise[x][y][z][t] = GenerateNoise();
                }
            }
        }
    }

    for(int t = 0; t < layers; t++) {
        SmoothNoise(t);
    }

    for(int t = 0; t < layers; t++) {
        for(int z = 0; z < 81; z++) {
            for(int y = 0; y < 16; y++) {
                for(int x = 0; x < 16; x++) {
                    octaves[x][y][z][t] = InterpolateNoise(interpolate1, interpolate2, noise[x][y][z][t]);
                }
            }
        }
    }

    for(int t = 0; t < layers; t++) {
        PerlinNoise(t);
    }
}

public static Random generation = new Random(5);
public float GenerateNoise() {
    float i = generation.nextFloat();
    return i;
}

public void SmoothNoise(int t) {
    //Huge smoothing algorithm
}

//Cosine interpolation
public int InterpolateNoise(int base, int top, float input) {
    return (int) ((1 - ((1 - Math.cos(input * 3.1415927)) * 0.5)) + top * ((1 - Math.cos(input * 3.1415927)) * 0.5));
}

public void PerlinNoise(int t) {
    double f = Math.pow(2.0, new Double(t));
    double a = Math.pow(persistence, new Double(t));
    for(int z = 0; z < 81; z++) {
        for(int y = 0; y < 16; y++) {
            for(int x = 0; x < 16; x++) {
                perlin[x][y][z][t] = (int) ((octaves[x][y][z][t] * f) * a);
            }
        }
    }
}

public static void main(String [] args) {
    JFrame frame = new JFrame();
    frame.setSize(180, 180);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    TerrainGen test = new TerrainGen();
    frame.add(test);
    frame.setVisible(true);
}

public static int size = 5;
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    int i = 0;
    for(int t = 0; t < 9; t++) {
        for(int z = 0; z < 9; z++) {
            for(int y = 0; y < 16; y++) {
                for(int x = 0; x < 16; x++) {
                    g.setColor(new Color(perlin[x][y][i][0] * 10, perlin[x][y][i][0] * 10, perlin[x][y][i][0] * 10));
                    g.fillRect((z * (16 * size)) + (x * size), (t * (16 * size)) + (y * size), size, size);
                }
            }
            i++;
        }
    }
    repaint();
}
}

And I did not include the smoothing part because that was about 400 lines of code to smooth between chunks.


Solution

  • What the article calls persistence is how the amplitude of the higher frequency noises "falls off" when they are combined.

    "octaves" are just what the article calls the noise functions at different frequencies.

    You take 1.0 and repeatedly multiply by the persistence to get the list of amplitudes to multiply each octave by - e.g. a persistence of 0.8 gives factors 1.0, 0.8, 0.64, 0.512.

    The noise is not an integer, his function Noise1 produces noise in the range 0..1 - i.e. variable n is an Int32 bit it returns a float.

    The input paramters are integers i.e. The Noise1 function is only evaluated at (1, 0) or (2, 2). After smoothing/smearing the noise a bit in SmoothNoise_1 the values get interpolated to produce the values inbetween.

    Hope that helped!!