From 3b37d83521565c3742148623e6cf044bf44bebd8 Mon Sep 17 00:00:00 2001 From: kromzem Date: Wed, 25 Oct 2017 15:18:59 +0200 Subject: [PATCH 1/3] added "Perlin-Noise-Algorithm" --- Others/PerlinNoise.java | 1 + 1 file changed, 1 insertion(+) create mode 100644 Others/PerlinNoise.java diff --git a/Others/PerlinNoise.java b/Others/PerlinNoise.java new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Others/PerlinNoise.java @@ -0,0 +1 @@ + From 26f446eb33bd10486c0e4d14cc4fb1d557d21679 Mon Sep 17 00:00:00 2001 From: kromzem Date: Wed, 25 Oct 2017 15:22:16 +0200 Subject: [PATCH 2/3] added "Perlin-Noise-Algorithm" --- Others/PerlinNoise.java | 129 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/Others/PerlinNoise.java b/Others/PerlinNoise.java index 8b1378917..d8e04a857 100644 --- a/Others/PerlinNoise.java +++ b/Others/PerlinNoise.java @@ -1 +1,130 @@ +import java.util.Random; +import java.util.Scanner; +public class PerlinNoise { + static float[][] generatePerlinNoise(int width, int height, int octaveCount, float persistence, long seed) { + final float[][] base = new float[width][height]; + final float[][] perlinNoise = new float[width][height]; + final float[][][] noiseLayers = new float[octaveCount][][]; + + Random random = new Random(seed); + for(int x = 0; x < width; x++) { + for(int y = 0; y < height; y++) { + base[x][y] = random.nextFloat(); + } + } + + //calculate octaves + for(int octave = 0; octave < octaveCount; octave++) { + noiseLayers[octave] = generatePerlinNoiseLayer(base, width, height, octave); + } + + float amplitude = 1f; + float totalAmplitude = 0f; + + //calculate perlin noise + for(int octave = octaveCount - 1; octave >= 0; octave--) { + amplitude *= persistence; + totalAmplitude += amplitude; + + for(int x = 0; x < width; x++) { + for(int y = 0; y < height; y++) { + perlinNoise[x][y] += noiseLayers[octave][x][y] * amplitude; + } + } + } + + //normalize + for(int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + perlinNoise[x][y] /= totalAmplitude; + } + } + + return perlinNoise; + } + + static float[][] generatePerlinNoiseLayer(float[][] base, int width, int height, int octave) { + float[][] perlinNoiseLayer = new float[width][height]; + + int period = 1 << octave; + float frequency = 1f / period; + + for(int x = 0; x < width; x++) { + int x0 = (x / period) * period; + int x1 = (x0 + period) % width; + float horizintalBlend = (x - x0) * frequency; + + for(int y = 0; y < height; y++) { + int y0 = (y / period) * period; + int y1 = (y0 + period) % height; + float verticalBlend = (y - y0) * frequency; + + float top = interpolate(base[x0][y0], base[x1][y0], horizintalBlend); + float bottom = interpolate(base[x0][y1], base[x1][y1], horizintalBlend); + + perlinNoiseLayer[x][y] = interpolate(top, bottom, verticalBlend); + } + } + + return perlinNoiseLayer; + } + + static float interpolate(float a, float b, float alpha) { + return a * (1 - alpha) + alpha * b; + } + + public static void main(String[] args) { + Scanner in = new Scanner(System.in); + + final int width; + final int height; + final int octaveCount; + final float persistence; + final long seed; + final String charset; + final float[][] perlinNoise; + + System.out.println("Width (int): "); + width = in.nextInt(); + + System.out.println("Height (int): "); + height = in.nextInt(); + + System.out.println("Octave count (int): "); + octaveCount = in.nextInt(); + + System.out.println("Persistence (float): "); + persistence = in.nextFloat(); + + System.out.println("Seed (long): "); + seed = in.nextLong(); + + System.out.println("Charset (String): "); + charset = in.next(); + + + perlinNoise = generatePerlinNoise(width, height, octaveCount, persistence, seed); + final char[] chars = charset.toCharArray(); + final int length = chars.length; + final float step = 1f / length; + //output based on charset + for(int x = 0; x < width; x++) { + for(int y = 0; y < height; y++) { + float value = step; + float noiseValue = perlinNoise[x][y]; + + for (char c : chars) { + if (noiseValue <= value) { + System.out.print(c); + break; + } + + value += step; + } + } + + System.out.println(); + } + } +} From 6267420572a2e9f7d5334844e4387a47c9eee107 Mon Sep 17 00:00:00 2001 From: Kromzem Date: Fri, 27 Oct 2017 12:28:54 +0200 Subject: [PATCH 3/3] added some more comments --- Others/PerlinNoise.java | 44 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/Others/PerlinNoise.java b/Others/PerlinNoise.java index d8e04a857..1d0f795a3 100644 --- a/Others/PerlinNoise.java +++ b/Others/PerlinNoise.java @@ -1,20 +1,32 @@ import java.util.Random; import java.util.Scanner; +/** + * For detailed info and implementation see: Perlin-Noise + */ public class PerlinNoise { + /** + * @param width width of noise array + * @param height height of noise array + * @param octaveCount numbers of layers used for blending noise + * @param persistence value of impact each layer get while blending + * @param seed used for randomizer + * @return float array containing calculated "Perlin-Noise" values + */ static float[][] generatePerlinNoise(int width, int height, int octaveCount, float persistence, long seed) { final float[][] base = new float[width][height]; final float[][] perlinNoise = new float[width][height]; final float[][][] noiseLayers = new float[octaveCount][][]; Random random = new Random(seed); + //fill base array with random values as base for noise for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { base[x][y] = random.nextFloat(); } } - //calculate octaves + //calculate octaves with different roughness for(int octave = 0; octave < octaveCount; octave++) { noiseLayers[octave] = generatePerlinNoiseLayer(base, width, height, octave); } @@ -22,19 +34,21 @@ public class PerlinNoise { float amplitude = 1f; float totalAmplitude = 0f; - //calculate perlin noise + //calculate perlin noise by blending each layer together with specific persistence for(int octave = octaveCount - 1; octave >= 0; octave--) { amplitude *= persistence; totalAmplitude += amplitude; for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { + //adding each value of the noise layer to the noise + //by increasing amplitude the rougher noises will have more impact perlinNoise[x][y] += noiseLayers[octave][x][y] * amplitude; } } } - //normalize + //normalize values so that they stay between 0..1 for(int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { perlinNoise[x][y] /= totalAmplitude; @@ -44,25 +58,39 @@ public class PerlinNoise { return perlinNoise; } + /** + * @param base base random float array + * @param width width of noise array + * @param height height of noise array + * @param octave current layer + * @return float array containing calculated "Perlin-Noise-Layer" values + */ static float[][] generatePerlinNoiseLayer(float[][] base, int width, int height, int octave) { float[][] perlinNoiseLayer = new float[width][height]; - int period = 1 << octave; - float frequency = 1f / period; + //calculate period (wavelength) for different shapes + int period = 1 << octave; //2^k + float frequency = 1f / period; // 1/2^k for(int x = 0; x < width; x++) { + //calculates the horizontal sampling indices int x0 = (x / period) * period; int x1 = (x0 + period) % width; float horizintalBlend = (x - x0) * frequency; for(int y = 0; y < height; y++) { + //calculates the vertical sampling indices int y0 = (y / period) * period; int y1 = (y0 + period) % height; float verticalBlend = (y - y0) * frequency; + //blend top corners float top = interpolate(base[x0][y0], base[x1][y0], horizintalBlend); + + //blend bottom corners float bottom = interpolate(base[x0][y1], base[x1][y1], horizintalBlend); + //blend top and bottom interpolation to get the final blend value for this cell perlinNoiseLayer[x][y] = interpolate(top, bottom, verticalBlend); } } @@ -70,6 +98,12 @@ public class PerlinNoise { return perlinNoiseLayer; } + /** + * @param a value of point a + * @param b value of point b + * @param alpha determine which value has more impact (closer to 0 -> a, closer to 1 -> b) + * @return interpolated value + */ static float interpolate(float a, float b, float alpha) { return a * (1 - alpha) + alpha * b; }