ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/noise.C
Revision: 1.3
Committed: Fri Apr 22 07:56:46 2011 UTC (13 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +23 -18 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 *
6 * Deliantra is free software: you can redistribute it and/or modify it under
7 * the terms of the Affero GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the Affero GNU General Public License
17 * and the GNU General Public License along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 * The authors can be reached via e-mail to <support@deliantra.net>
21 */
22
23 #include "noise.h"
24
25 /////////////////////////////////////////////////////////////////////////////
26
27 noise2d::noise2d (uint32_t seed)
28 {
29 seedable_rand_gen rng (seed);
30
31 for (int i = 0; i < 256; ++i)
32 {
33 vec2d rv;
34 rv[0] = rng () - 0.5f;
35 rv[1] = rng () - 0.5f;
36
37 // normalise
38 float mag = 1.f / sqrtf (rv[0] * rv[0] + rv[1] * rv[1]);
39
40 rv[0] *= mag;
41 rv[1] *= mag;
42
43 rvec[i][0] = rv[0];
44 rvec[i][1] = rv[1];
45 }
46
47 rvmap[0].seed (rng);
48 rvmap[1].seed (rng);
49 }
50
51 float
52 noise2d::noise (float x, float y)
53 {
54 int ix = floorf (x); float fx = x - ix;
55 int iy = floorf (y); float fy = y - iy;
56
57 float v = 0;
58
59 for (int j = -1; j <= 2; ++j)
60 for (int i = -1; i <= 2; ++i)
61 {
62 float Ax = fx - i;
63 float Ay = fy - j;
64
65 float d = Ax * Ax + Ay * Ay;
66
67 if (d < 4)
68 {
69 float t1 = 1 - d / 4;
70 float t2 = t1 * t1;
71 float t4 = t2 * t2;
72
73 float p = (4 * t1 - 3) * t4;
74
75 int h = rvmap[0](ix + i) ^ rvmap[1](iy + j);
76 float G0 = rvec[h & 0xff][0];
77 float G1 = rvec[h & 0xff][1];
78 //vec2d G = rvec[h & 0xff];
79
80 v += (Ax * G0 + Ay * G1) * p;
81 }
82 }
83
84 return clamp (v * 2, -.9999999f, .9999999f);
85 }
86
87 #if 0||ABSTRACTION_PENALTY_IS_GONE
88 float
89 noise2d::noise (float x, float y)
90 {
91 vec2d X = vec2d (x, y);
92 gen_vec<2,int> I = floor (X);
93 vec2d F = X - I;
94
95 float v = 0;
96
97 for (int j = -1; j <= 2; ++j)
98 for (int i = -1; i <= 2; ++i)
99 {
100 vec2d A = F - vec2d (i, j);
101
102 float d = A * A;
103
104 if (d < 4)
105 {
106 int h = rvmap [0](I[0] + i) ^ rvmap [1](I[1] + j);
107 float *G = rvec [h & 0xff];
108
109 float t1 = 1 - d / 4;
110 float t2 = t1 * t1;
111 float t4 = t2 * t2;
112
113 float p = (4 * t1 - 3) * t4;
114 v += A * vec2d (G[0], G[1]) * p;
115 }
116 }
117
118 return clamp (v * 2, -.9999999f, .9999999f);
119 }
120 #endif
121
122 /////////////////////////////////////////////////////////////////////////////
123
124 noise3d::noise3d (uint32_t seed)
125 {
126 seedable_rand_gen rng (seed);
127
128 for (int i = 0; i < 256; ++i)
129 {
130 for (int j = 0; j < 3; ++j)
131 rvec [i][j] = rng () - 0.5f;
132
133 // normalise
134 float mag = 1.f / sqrtf (rvec [i][0] * rvec [i][0]
135 + rvec [i][1] * rvec [i][1]
136 + rvec [i][2] * rvec [i][2]);
137
138 rvec [i][0] *= mag;
139 rvec [i][1] *= mag;
140 rvec [i][2] *= mag;
141 }
142
143 rvmap [0].seed (rng);
144 rvmap [1].seed (rng);
145 rvmap [2].seed (rng);
146 }
147
148 float
149 noise3d::noise (float x, float y, float z)
150 {
151 int ix = floorf (x); float fx = x - ix;
152 int iy = floorf (y); float fy = y - iy;
153 int iz = floorf (z); float fz = z - iz;
154
155 float v = 0;
156
157 for (int j = -1; j <= 2; ++j)
158 for (int i = -1; i <= 2; ++i)
159 for (int k = -1; k <= 2; ++k)
160 {
161 float Ax = fx - i;
162 float Ay = fy - j;
163 float Az = fz - k;
164
165 float d = Ax * Ax + Ay * Ay + Az * Az;
166
167 if (d < 4)
168 {
169 int h = rvmap [0](ix + i) ^ rvmap [1](iy + j) ^ rvmap [2](iz + k);
170 float *G = rvec [h & 0xff];
171
172 float t1 = 1 - d / 4;
173 float t2 = t1 * t1;
174 float t4 = t2 * t2;
175
176 // (4t⁵ - 3t⁴)
177 float p = (4 * t1 - 3) * t4;
178 v += (Ax * G[0] + Ay * G[1] + Az * G[2]) * p;
179 }
180 }
181
182 return clamp (v * 2, -.9999999f, .9999999f);
183 }
184
185 float
186 noise3d::noise (float x, float y, float z, float nx, float ny, float nz)
187 {
188 int ix = floorf (x); float fx = x - ix;
189 int iy = floorf (y); float fy = y - iy;
190 int iz = floorf (z); float fz = z - iz;
191
192 float v = 0;
193
194 for (int j = -1; j <= 2; ++j)
195 for (int i = -1; i <= 2; ++i)
196 for (int k = -1; k <= 2; ++k)
197 {
198 float Dx = fx - i;
199 float Dy = fy - j;
200 float Dz = fz - k;
201
202 float e = Dx * nx + Dy * ny + Dz * nz;
203
204 float o = 1 - abs (e);
205
206 if (o > 0)
207 {
208 float Ax = Dx - e * nx;
209 float Ay = Dy - e * ny;
210 float Az = Dz - e * nz;
211
212 float d = Ax * Ax + Ay * Ay + Az * Az;
213
214 if (d < 4)
215 {
216 int h = rvmap [0](ix + i) ^ rvmap [1](iy + j) ^ rvmap [2](iz + k);
217 float *G = rvec [h & 0xff];
218
219 float t1 = 1 - d / 4;
220 float t2 = t1 * t1;
221 float t4 = t2 * t2;
222
223 float o2 = o * o;
224
225 // (4t⁵ - 3t⁴) * (3o³ - 2o²)
226 float p = (4 * t1 - 3) * t4 * (3 * o2 - 2 * o2 * o);
227 v += (Ax * G[0] + Ay * G[1] + Az * G[2]) * p;
228 }
229 }
230 }
231
232 return clamp (v * 2, -.9999999f, .9999999f);
233 }
234
235 frac_gen::frac_gen (float hurst_expo, float lacunarity)
236 : h (hurst_expo), lac (lacunarity), noise2d (0)
237 {
238 float exsum = 0;
239
240 for (int i = 0; i < MAX_OCTAVES; ++i)
241 {
242 ex [i] = powf (lac, -h * i);
243 exsum += ex [i];
244 fbm_mul [i] = 0.5f / (exsum * 0.75f); // .75f is a heuristic
245 rot [i].set (0.4488f * i);
246 }
247 }
248
249 float
250 frac_gen::fBm (float x, float y, int octaves)
251 {
252 float v = 0.f;
253
254 for (int i = 0; i < octaves; ++i)
255 {
256 rot [i](x, y);
257
258 v += noise (x + i, y) * ex [i];
259
260 x *= lac;
261 y *= lac;
262 }
263
264 return clamp (v * fbm_mul [octaves - 1] + 0.5f, 0.f, .9999999f);
265 }
266
267 float
268 frac_gen::turbulence (float x, float y, int octaves)
269 {
270 float v = 0.f;
271
272 for (int i = 0; i < octaves; ++i)
273 {
274 rot [i](x, y);
275
276 v += fabsf (noise (x + i, y)) * ex [i];
277
278 x *= lac;
279 y *= lac;
280 }
281
282 return clamp (v * fbm_mul [octaves - 1] * 2.f, 0.f, .9999999f);
283 }
284
285 float
286 frac_gen::multifractal (float x, float y, int octaves, float offset)
287 {
288 float v = 1.f;
289
290 for (int i = 0; i < octaves; ++i)
291 {
292 rot [i](x, y);
293
294 v *= noise (x, y) * ex [i] + offset;
295
296 x *= lac;
297 y *= lac;
298 }
299
300 return clamp (v * 0.5f, 0.f, .9999999f);
301 }
302
303 float
304 frac_gen::heterofractal (float x, float y, int octaves, float offset)
305 {
306 float v = noise (x, y) + offset;
307 int i;
308
309 for (i = 1; i < octaves; ++i)
310 {
311 rot [i](x, y);
312
313 x *= lac;
314 y *= lac;
315
316 v += v * (noise (x, y) * ex [i] + offset);
317 }
318
319 return v / powf (2., octaves);
320 }
321
322 float
323 frac_gen::hybridfractal (float x, float y, int octaves, float offset, float gain)
324 {
325 float v = (noise (x, y) + offset) * ex [0];
326 float weight = v;
327 int i;
328
329 for (i = 1; i < octaves; ++i)
330 {
331 rot [i](x, y);
332
333 x *= lac;
334 y *= lac;
335
336 min_it (weight, 1.f);
337
338 float sig = (noise (x, y) + offset) * ex [i];
339 v += weight * sig;
340 weight *= gain * sig;
341 }
342
343 return clamp (v * 0.5f + 0.5f, 0.f, .9999999f);
344 }
345
346 // http://www.gamasutra.com/view/feature/3098/a_realtime_procedural_universe_.php?page=2
347 float
348 frac_gen::terrain (float x, float y, int octaves)
349 {
350 float v = 0.f;
351
352 for (int i = 0; i < octaves; ++i)
353 {
354 rot[i] (x, y);
355
356 v += noise (x + i, y) * ex [i];
357
358 x *= lac;
359 y *= lac;
360 }
361
362 v *= fbm_mul [octaves - 1];
363
364 return v <= 0.f ? - powf (-v, 0.7f) : powf (v, 1. + noise (x, y) * v);
365 }
366
367 float
368 frac_gen::terrain2 (float x, float y, int octaves)
369 {
370 float a = fBm (x, y, octaves);
371 float b = ridgedmultifractal (x, y, octaves, 1, 8);
372 float fade = fBm (x + 10.3, y + 10.3, octaves);
373
374 const float width = 0.05f;
375
376 if (fade > 0.5f + width)
377 return a;
378 else if (fade < 0.5f - width)
379 return b;
380
381 fade = (fade - 0.5f + width) / (width * 2);
382
383 // sigmoidal curve
384 fade = fade * fade * 2 * (1.5f - fade);
385
386 return a * fade + b * (1 - fade);
387 }
388
389 float
390 frac_gen::ridgedmultifractal (float x, float y, int octaves, float offset, float gain)
391 {
392 float sig = offset - fabsf (noise (x, y));
393 sig *= sig;
394 float v = sig;
395
396 for (int i = 1; i < octaves; ++i)
397 {
398 rot [i](x, y);
399
400 x *= lac;
401 y *= lac;
402
403 float w = clamp (sig * gain, 0.f, 1.f);
404
405 sig = offset - fabsf (noise (x, y));
406 sig *= sig;
407 sig *= w;
408
409 v += sig * ex [i];
410 }
411
412 return clamp (v * 0.25f, 0.f, .9999999f);
413 }
414
415 #if 1
416 void hack()
417 {
418 frac_gen gen (0.5, 2);
419 noise3d n(0);
420
421 #if 1
422 int N = 1024;
423
424 printf ("P5 %d %d 255\n", N, N);
425 // pmake&&server/deliantra-server >x&&convert -depth 8 -size 512xx512 gray:x x.ppm&& cv x.ppm
426 for (int y = 0; y < N; ++y)
427 {
428 if (!(y&63))fprintf (stderr, "y %d\n", y);//D
429 for (int x = 0; x < N; ++x)
430 {
431 putc (127 * gen.noise (x * 0.04, y * 0.04) + 128, stdout);
432 //putc (256 * gen.terrain2 (x * 0.004, y * 0.004, 8), stdout);
433 //putc (256 * gen.fBm (x * 0.01, y * 0.01, 7), stdout);
434 //putc (256 * gen.turbulence (x * 0.004 - 1, y * 0.004 - 1, 8), stdout);
435 //putc (256 * gen.heterofractal (x * 0.008, y * 0.008, 8, -1.1, 2.0), stdout);
436 //putc (256 * gen.ridgedmultifractal (x * 0.001, y * 0.001, 32, 1.001, 32), stdout);
437 }
438 }
439 #else
440 int N = 128;
441
442 //printf ("P6 %d %d 255\n", N, N);
443 // pmake&&server/deliantra-server >x&&convert -depth 8 -size 512xx512 gray:x x.ppm&& cv x.ppm
444 for (int z = 0; z < N; ++z)
445 {
446 if (!(z&4))fprintf (stderr, "z %d\n", z);//D
447 for (int y = 0; y < N; ++y)
448 for (int x = 0; x < N; ++x)
449 {
450 float v = n.noise (x * 0.06 + 0.2, y * 0.06 + 0.2, z * 0.06 + 0.2) * 0.5 + 0.5;
451
452 if (z < 64)
453 v = v * (z * z) / (64 * 64);
454
455 if (v <= 0.1)
456 continue;
457
458 float r[4];
459 int i[4];
460
461 r[0] = x;
462 r[1] = y;
463 r[2] = z;
464 r[3] = v;
465
466 memcpy (i, r, 16);
467
468 i[0] = htonl (i[0]);
469 i[1] = htonl (i[1]);
470 i[2] = htonl (i[2]);
471 i[3] = htonl (i[3]);
472
473 fwrite (i, 4*4, 1, stdout);
474 }
475 }
476 #endif
477
478 exit (0);
479 }
480 #endif