Skip to content

Commit 258e64d

Browse files
author
Christian Bender
authored
Merge pull request TheAlgorithms#265 from Kromzem/master
Perlin-Noise-Algorithm added
2 parents d2c9443 + 6267420 commit 258e64d

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

Others/PerlinNoise.java

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import java.util.Random;
2+
import java.util.Scanner;
3+
4+
/**
5+
* For detailed info and implementation see: <a href="http://devmag.org.za/2009/04/25/perlin-noise/">Perlin-Noise</a>
6+
*/
7+
public class PerlinNoise {
8+
/**
9+
* @param width width of noise array
10+
* @param height height of noise array
11+
* @param octaveCount numbers of layers used for blending noise
12+
* @param persistence value of impact each layer get while blending
13+
* @param seed used for randomizer
14+
* @return float array containing calculated "Perlin-Noise" values
15+
*/
16+
static float[][] generatePerlinNoise(int width, int height, int octaveCount, float persistence, long seed) {
17+
final float[][] base = new float[width][height];
18+
final float[][] perlinNoise = new float[width][height];
19+
final float[][][] noiseLayers = new float[octaveCount][][];
20+
21+
Random random = new Random(seed);
22+
//fill base array with random values as base for noise
23+
for(int x = 0; x < width; x++) {
24+
for(int y = 0; y < height; y++) {
25+
base[x][y] = random.nextFloat();
26+
}
27+
}
28+
29+
//calculate octaves with different roughness
30+
for(int octave = 0; octave < octaveCount; octave++) {
31+
noiseLayers[octave] = generatePerlinNoiseLayer(base, width, height, octave);
32+
}
33+
34+
float amplitude = 1f;
35+
float totalAmplitude = 0f;
36+
37+
//calculate perlin noise by blending each layer together with specific persistence
38+
for(int octave = octaveCount - 1; octave >= 0; octave--) {
39+
amplitude *= persistence;
40+
totalAmplitude += amplitude;
41+
42+
for(int x = 0; x < width; x++) {
43+
for(int y = 0; y < height; y++) {
44+
//adding each value of the noise layer to the noise
45+
//by increasing amplitude the rougher noises will have more impact
46+
perlinNoise[x][y] += noiseLayers[octave][x][y] * amplitude;
47+
}
48+
}
49+
}
50+
51+
//normalize values so that they stay between 0..1
52+
for(int x = 0; x < width; x++) {
53+
for (int y = 0; y < height; y++) {
54+
perlinNoise[x][y] /= totalAmplitude;
55+
}
56+
}
57+
58+
return perlinNoise;
59+
}
60+
61+
/**
62+
* @param base base random float array
63+
* @param width width of noise array
64+
* @param height height of noise array
65+
* @param octave current layer
66+
* @return float array containing calculated "Perlin-Noise-Layer" values
67+
*/
68+
static float[][] generatePerlinNoiseLayer(float[][] base, int width, int height, int octave) {
69+
float[][] perlinNoiseLayer = new float[width][height];
70+
71+
//calculate period (wavelength) for different shapes
72+
int period = 1 << octave; //2^k
73+
float frequency = 1f / period; // 1/2^k
74+
75+
for(int x = 0; x < width; x++) {
76+
//calculates the horizontal sampling indices
77+
int x0 = (x / period) * period;
78+
int x1 = (x0 + period) % width;
79+
float horizintalBlend = (x - x0) * frequency;
80+
81+
for(int y = 0; y < height; y++) {
82+
//calculates the vertical sampling indices
83+
int y0 = (y / period) * period;
84+
int y1 = (y0 + period) % height;
85+
float verticalBlend = (y - y0) * frequency;
86+
87+
//blend top corners
88+
float top = interpolate(base[x0][y0], base[x1][y0], horizintalBlend);
89+
90+
//blend bottom corners
91+
float bottom = interpolate(base[x0][y1], base[x1][y1], horizintalBlend);
92+
93+
//blend top and bottom interpolation to get the final blend value for this cell
94+
perlinNoiseLayer[x][y] = interpolate(top, bottom, verticalBlend);
95+
}
96+
}
97+
98+
return perlinNoiseLayer;
99+
}
100+
101+
/**
102+
* @param a value of point a
103+
* @param b value of point b
104+
* @param alpha determine which value has more impact (closer to 0 -> a, closer to 1 -> b)
105+
* @return interpolated value
106+
*/
107+
static float interpolate(float a, float b, float alpha) {
108+
return a * (1 - alpha) + alpha * b;
109+
}
110+
111+
public static void main(String[] args) {
112+
Scanner in = new Scanner(System.in);
113+
114+
final int width;
115+
final int height;
116+
final int octaveCount;
117+
final float persistence;
118+
final long seed;
119+
final String charset;
120+
final float[][] perlinNoise;
121+
122+
System.out.println("Width (int): ");
123+
width = in.nextInt();
124+
125+
System.out.println("Height (int): ");
126+
height = in.nextInt();
127+
128+
System.out.println("Octave count (int): ");
129+
octaveCount = in.nextInt();
130+
131+
System.out.println("Persistence (float): ");
132+
persistence = in.nextFloat();
133+
134+
System.out.println("Seed (long): ");
135+
seed = in.nextLong();
136+
137+
System.out.println("Charset (String): ");
138+
charset = in.next();
139+
140+
141+
perlinNoise = generatePerlinNoise(width, height, octaveCount, persistence, seed);
142+
final char[] chars = charset.toCharArray();
143+
final int length = chars.length;
144+
final float step = 1f / length;
145+
//output based on charset
146+
for(int x = 0; x < width; x++) {
147+
for(int y = 0; y < height; y++) {
148+
float value = step;
149+
float noiseValue = perlinNoise[x][y];
150+
151+
for (char c : chars) {
152+
if (noiseValue <= value) {
153+
System.out.print(c);
154+
break;
155+
}
156+
157+
value += step;
158+
}
159+
}
160+
161+
System.out.println();
162+
}
163+
}
164+
}

0 commit comments

Comments
 (0)