载入中...
搜索中...
未找到
NoiseField.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5
6namespace eve::procgen {
7namespace {
8
9float fade(float t) { return t * t * (3.f - 2.f * t); }
10float fade5(float t) { return t * t * t * (t * (t * 6.f - 15.f) + 10.f); }
11
12int wrapIndex(int i, int period) {
13 if (period <= 0) return i;
14 int m = i % period;
15 if (m < 0) m += period;
16 return m;
17}
18
19} // namespace
20
21float NoiseField::hash01(int ix, int iy) const {
22 ix = wrapIndex(ix, periodX);
23 iy = wrapIndex(iy, periodY);
24 uint32_t h = seed;
25 h ^= uint32_t(ix) * 374761393u;
26 h ^= uint32_t(iy) * 668265263u;
27 h = (h ^ (h >> 13)) * 1274126177u;
28 h ^= h >> 16;
29 return float(h & 0x00FFFFFFu) / float(0x00FFFFFFu);
30}
31
32float NoiseField::valueNoise(float x, float y) const {
33 const int x0 = int(std::floor(x));
34 const int y0 = int(std::floor(y));
35 const float fx = fade(x - float(x0));
36 const float fy = fade(y - float(y0));
37 const float n00 = hash01(x0, y0);
38 const float n10 = hash01(x0 + 1, y0);
39 const float n01 = hash01(x0, y0 + 1);
40 const float n11 = hash01(x0 + 1, y0 + 1);
41 const float nx0 = n00 + (n10 - n00) * fx;
42 const float nx1 = n01 + (n11 - n01) * fx;
43 return nx0 + (nx1 - nx0) * fy;
44}
45
46float NoiseField::perlinNoise(float x, float y) const {
47 const int x0 = int(std::floor(x));
48 const int y0 = int(std::floor(y));
49 const float dx = x - float(x0);
50 const float dy = y - float(y0);
51 const float fx = fade5(dx);
52 const float fy = fade5(dy);
53
54 auto grad = [&](int ix, int iy, float px, float py) -> float {
55 // 8 compass gradients (Perlin 2002 style).
56 static const float gx[8] = {1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 0.f, 0.f};
57 static const float gy[8] = {1.f, 1.f, -1.f, -1.f, 0.f, 0.f, 1.f, -1.f};
58 const int h = int(hash01(ix, iy) * 7.999f) & 7;
59 return gx[h] * (px - float(ix)) + gy[h] * (py - float(iy));
60 };
61
62 const float n00 = grad(x0, y0, x, y);
63 const float n10 = grad(x0 + 1, y0, x, y);
64 const float n01 = grad(x0, y0 + 1, x, y);
65 const float n11 = grad(x0 + 1, y0 + 1, x, y);
66 const float nx0 = n00 + (n10 - n00) * fx;
67 const float nx1 = n01 + (n11 - n01) * fx;
68 const float n = nx0 + (nx1 - nx0) * fy;
69 return std::clamp(n * 0.5f + 0.5f, 0.f, 1.f);
70}
71
72float NoiseField::fbm(float x, float y, int octaves, float lacunarity, float gain) const {
73 octaves = std::max(1, octaves);
74 float sum = 0.f, amp = 1.f, norm = 0.f, freq = 1.f;
75 for (int i = 0; i < octaves; ++i) {
76 sum += valueNoise(x * freq, y * freq) * amp;
77 norm += amp;
78 amp *= gain;
79 freq *= lacunarity;
80 }
81 return norm > 0.f ? sum / norm : 0.f;
82}
83
84float NoiseField::fbmPerlin(float x, float y, int octaves, float lacunarity, float gain) const {
85 octaves = std::max(1, octaves);
86 float sum = 0.f, amp = 1.f, norm = 0.f, freq = 1.f;
87 for (int i = 0; i < octaves; ++i) {
88 // Offset each octave so they are uncorrelated (Red Blob Games).
89 const float ox = float(i) * 17.8f;
90 const float oy = float(i) * 23.5f;
91 sum += perlinNoise(x * freq + ox, y * freq + oy) * amp;
92 norm += amp;
93 amp *= gain;
94 freq *= lacunarity;
95 }
96 return norm > 0.f ? sum / norm : 0.f;
97}
98
99float NoiseField::ridged(float x, float y, int octaves, float lacunarity, float gain) const {
100 octaves = std::max(1, octaves);
101 float sum = 0.f, amp = 1.f, norm = 0.f, freq = 1.f;
102 for (int i = 0; i < octaves; ++i) {
103 float n = valueNoise(x * freq, y * freq);
104 n = 1.f - std::fabs(n * 2.f - 1.f);
105 sum += n * n * amp;
106 norm += amp;
107 amp *= gain;
108 freq *= lacunarity;
109 }
110 return norm > 0.f ? sum / norm : 0.f;
111}
112
113float NoiseField::ridgedPerlin(float x, float y, int octaves, float lacunarity, float gain) const {
114 octaves = std::max(1, octaves);
115 float sum = 0.f, amp = 1.f, norm = 0.f, freq = 1.f;
116 for (int i = 0; i < octaves; ++i) {
117 const float ox = float(i) * 11.3f;
118 const float oy = float(i) * 19.7f;
119 float n = perlinNoise(x * freq + ox, y * freq + oy);
120 n = 1.f - std::fabs(n * 2.f - 1.f);
121 sum += n * n * amp;
122 norm += amp;
123 amp *= gain;
124 freq *= lacunarity;
125 }
126 return norm > 0.f ? sum / norm : 0.f;
127}
128
129float NoiseField::warp(float x, float y, float amp, int octaves) const {
130 const float wx = fbm(x + 19.1f, y + 7.3f, octaves) - 0.5f;
131 const float wy = fbm(x + 5.2f, y + 31.7f, octaves) - 0.5f;
132 return fbm(x + wx * amp, y + wy * amp, octaves);
133}
134
135} // namespace eve::procgen
int y
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int h
std::vector< Colorf > px
float m[16]
float fbm(float x, float y, int octaves=4, float lacunarity=2.f, float gain=0.5f) const
float ridged(float x, float y, int octaves=4, float lacunarity=2.f, float gain=0.5f) const
float fbmPerlin(float x, float y, int octaves=4, float lacunarity=2.f, float gain=0.5f) const
float warp(float x, float y, float amp, int octaves=3) const
float hash01(int ix, int iy) const
float perlinNoise(float x, float y) const
Classic 2D Perlin gradient noise, remapped to [0, 1].
float ridgedPerlin(float x, float y, int octaves=4, float lacunarity=2.f, float gain=0.5f) const
float valueNoise(float x, float y) const