- Notifications
You must be signed in to change notification settings - Fork 19.9k
/
Copy pathPerlinNoise.java
171 lines (140 loc) · 5.7 KB
/
PerlinNoise.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
packagecom.thealgorithms.others;
importjava.util.Random;
importjava.util.Scanner;
/**
* For detailed info and implementation see: <a
* href="http://devmag.org.za/2009/04/25/perlin-noise/">Perlin-Noise</a>
*/
publicfinalclassPerlinNoise {
privatePerlinNoise() {
}
/**
* @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
*/
staticfloat[][] generatePerlinNoise(intwidth, intheight, intoctaveCount, floatpersistence, longseed) {
finalfloat[][] base = newfloat[width][height];
finalfloat[][] perlinNoise = newfloat[width][height];
finalfloat[][][] noiseLayers = newfloat[octaveCount][][];
Randomrandom = newRandom(seed);
// fill base array with random values as base for noise
for (intx = 0; x < width; x++) {
for (inty = 0; y < height; y++) {
base[x][y] = random.nextFloat();
}
}
// calculate octaves with different roughness
for (intoctave = 0; octave < octaveCount; octave++) {
noiseLayers[octave] = generatePerlinNoiseLayer(base, width, height, octave);
}
floatamplitude = 1f;
floattotalAmplitude = 0f;
// calculate perlin noise by blending each layer together with specific persistence
for (intoctave = octaveCount - 1; octave >= 0; octave--) {
amplitude *= persistence;
totalAmplitude += amplitude;
for (intx = 0; x < width; x++) {
for (inty = 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 (intx = 0; x < width; x++) {
for (inty = 0; y < height; y++) {
perlinNoise[x][y] /= totalAmplitude;
}
}
returnperlinNoise;
}
/**
* @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
*/
staticfloat[][] generatePerlinNoiseLayer(float[][] base, intwidth, intheight, intoctave) {
float[][] perlinNoiseLayer = newfloat[width][height];
// calculate period (wavelength) for different shapes
intperiod = 1 << octave; // 2^k
floatfrequency = 1f / period; // 1/2^k
for (intx = 0; x < width; x++) {
// calculates the horizontal sampling indices
intx0 = (x / period) * period;
intx1 = (x0 + period) % width;
floathorizintalBlend = (x - x0) * frequency;
for (inty = 0; y < height; y++) {
// calculates the vertical sampling indices
inty0 = (y / period) * period;
inty1 = (y0 + period) % height;
floatverticalBlend = (y - y0) * frequency;
// blend top corners
floattop = interpolate(base[x0][y0], base[x1][y0], horizintalBlend);
// blend bottom corners
floatbottom = 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);
}
}
returnperlinNoiseLayer;
}
/**
* @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
*/
staticfloatinterpolate(floata, floatb, floatalpha) {
returna * (1 - alpha) + alpha * b;
}
publicstaticvoidmain(String[] args) {
Scannerin = newScanner(System.in);
finalintwidth;
finalintheight;
finalintoctaveCount;
finalfloatpersistence;
finallongseed;
finalStringcharset;
finalfloat[][] 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);
finalchar[] chars = charset.toCharArray();
finalintlength = chars.length;
finalfloatstep = 1f / length;
// output based on charset
for (intx = 0; x < width; x++) {
for (inty = 0; y < height; y++) {
floatvalue = step;
floatnoiseValue = perlinNoise[x][y];
for (charc : chars) {
if (noiseValue <= value) {
System.out.print(c);
break;
}
value += step;
}
}
System.out.println();
}
in.close();
}
}