Question

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.

Was it helpful?

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!!

OTHER TIPS

this loop makes octaves from 2d noise. same loop would work for 3d perlin...

   function octaves( vtx: Vector3 ): float
    {
        var total = 0.0;    
        for (var i:int = 1; i < 7; i ++)//num octaves
        {
            total+= PerlinNoise(Vector3 (vtx.x*(i*i),0.0,vtx.z*(i*i)))/(i*i);
        }

        return total;//added multiple perlins into noise with 1/2/4/8 etc ratios

    }

the best thing i have seen for learning perlin is the following code. instead of hash tables, it uses sin based semi random function. using 2-3 octaves it becomes high quality perlin... the amazing thing is that i ran 30 octave of this on a realtime landscape and it didnt slow down, whereas i used 1 voronoi once and it was slowing. so... amazing code to learn from.

#ifndef __noise_hlsl_
#define __noise_hlsl_

// hash based 3d value noise
// function taken from https://www.shadertoy.com/view/XslGRr
// Created by inigo quilez - iq/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

// ported from GLSL to HLSL

float hash( float n )
{
    return frac(sin(n)*43758.5453);
}

float noise( float3 x )
{
    // The noise function returns a value in the range -1.0f -> 1.0f

    float3 p = floor(x);
    float3 f = frac(x);

    f       = f*f*(3.0-2.0*f);
    float n = p.x + p.y*57.0 + 113.0*p.z;

    return lerp(lerp(lerp( hash(n+0.0), hash(n+1.0),f.x),
                   lerp( hash(n+57.0), hash(n+58.0),f.x),f.y),
               lerp(lerp( hash(n+113.0), hash(n+114.0),f.x),
                   lerp( hash(n+170.0), hash(n+171.0),f.x),f.y),f.z);
}

note that sin is expensive on CPU, instead you would use:

function hash ( n: float ): float
{//random -1, 1
    var e = ( n *73.9543)%1;
    return  (e*e*142.05432)%2-1;// fast cpu random by me :) uses e*e rather than sin
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top