Skip to content

Perlin-Noise-Algorithm added #265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 2, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions Others/PerlinNoise.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import java.util.Random;
import java.util.Scanner;

/**
* For detailed info and implementation see: <a href="http://devmag.org.za/2009/04/25/perlin-noise/">Perlin-Noise</a>
*/
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 with different roughness
for(int octave = 0; octave < octaveCount; octave++) {
noiseLayers[octave] = generatePerlinNoiseLayer(base, width, height, octave);
}

float amplitude = 1f;
float totalAmplitude = 0f;

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

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];

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

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

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