@esengine/procgen 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.ts +619 -0
- package/dist/index.js +1792 -0
- package/dist/index.js.map +1 -0
- package/module.json +24 -0
- package/package.json +40 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1792 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
4
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
|
|
6
|
+
// src/noise/PerlinNoise.ts
|
|
7
|
+
var _PerlinNoise = class _PerlinNoise {
|
|
8
|
+
/**
|
|
9
|
+
* @zh 创建 Perlin 噪声生成器
|
|
10
|
+
* @en Create Perlin noise generator
|
|
11
|
+
*
|
|
12
|
+
* @param seed - @zh 随机种子 @en Random seed
|
|
13
|
+
*/
|
|
14
|
+
constructor(seed = 0) {
|
|
15
|
+
__publicField(this, "_perm");
|
|
16
|
+
__publicField(this, "_gradP");
|
|
17
|
+
this._perm = new Uint8Array(512);
|
|
18
|
+
this._gradP = new Float32Array(512 * 3);
|
|
19
|
+
this._seed(seed);
|
|
20
|
+
}
|
|
21
|
+
_seed(seed) {
|
|
22
|
+
const p = new Uint8Array(256);
|
|
23
|
+
for (let i = 0; i < 256; i++) {
|
|
24
|
+
p[i] = i;
|
|
25
|
+
}
|
|
26
|
+
let n = seed;
|
|
27
|
+
for (let i = 255; i > 0; i--) {
|
|
28
|
+
n = n * 16807 % 2147483647;
|
|
29
|
+
const j = n % (i + 1);
|
|
30
|
+
[p[i], p[j]] = [
|
|
31
|
+
p[j],
|
|
32
|
+
p[i]
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
for (let i = 0; i < 512; i++) {
|
|
36
|
+
this._perm[i] = p[i & 255];
|
|
37
|
+
}
|
|
38
|
+
const grad3 = [
|
|
39
|
+
1,
|
|
40
|
+
1,
|
|
41
|
+
0,
|
|
42
|
+
-1,
|
|
43
|
+
1,
|
|
44
|
+
0,
|
|
45
|
+
1,
|
|
46
|
+
-1,
|
|
47
|
+
0,
|
|
48
|
+
-1,
|
|
49
|
+
-1,
|
|
50
|
+
0,
|
|
51
|
+
1,
|
|
52
|
+
0,
|
|
53
|
+
1,
|
|
54
|
+
-1,
|
|
55
|
+
0,
|
|
56
|
+
1,
|
|
57
|
+
1,
|
|
58
|
+
0,
|
|
59
|
+
-1,
|
|
60
|
+
-1,
|
|
61
|
+
0,
|
|
62
|
+
-1,
|
|
63
|
+
0,
|
|
64
|
+
1,
|
|
65
|
+
1,
|
|
66
|
+
0,
|
|
67
|
+
-1,
|
|
68
|
+
1,
|
|
69
|
+
0,
|
|
70
|
+
1,
|
|
71
|
+
-1,
|
|
72
|
+
0,
|
|
73
|
+
-1,
|
|
74
|
+
-1
|
|
75
|
+
];
|
|
76
|
+
for (let i = 0; i < 512; i++) {
|
|
77
|
+
const gi = this._perm[i] % 12 * 3;
|
|
78
|
+
this._gradP[i * 3] = grad3[gi];
|
|
79
|
+
this._gradP[i * 3 + 1] = grad3[gi + 1];
|
|
80
|
+
this._gradP[i * 3 + 2] = grad3[gi + 2];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
_fade(t) {
|
|
84
|
+
return t * t * t * (t * (t * 6 - 15) + 10);
|
|
85
|
+
}
|
|
86
|
+
_lerp(a, b, t) {
|
|
87
|
+
return a + t * (b - a);
|
|
88
|
+
}
|
|
89
|
+
_dot2(gi, x, y) {
|
|
90
|
+
return this._gradP[gi * 3] * x + this._gradP[gi * 3 + 1] * y;
|
|
91
|
+
}
|
|
92
|
+
_dot3(gi, x, y, z) {
|
|
93
|
+
return this._gradP[gi * 3] * x + this._gradP[gi * 3 + 1] * y + this._gradP[gi * 3 + 2] * z;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* @zh 2D Perlin 噪声
|
|
97
|
+
* @en 2D Perlin noise
|
|
98
|
+
*
|
|
99
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
100
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
101
|
+
* @returns @zh 噪声值 [-1, 1] @en Noise value [-1, 1]
|
|
102
|
+
*/
|
|
103
|
+
noise2D(x, y) {
|
|
104
|
+
const X = Math.floor(x) & 255;
|
|
105
|
+
const Y = Math.floor(y) & 255;
|
|
106
|
+
x -= Math.floor(x);
|
|
107
|
+
y -= Math.floor(y);
|
|
108
|
+
const u = this._fade(x);
|
|
109
|
+
const v = this._fade(y);
|
|
110
|
+
const A = this._perm[X] + Y;
|
|
111
|
+
const B = this._perm[X + 1] + Y;
|
|
112
|
+
return this._lerp(this._lerp(this._dot2(this._perm[A], x, y), this._dot2(this._perm[B], x - 1, y), u), this._lerp(this._dot2(this._perm[A + 1], x, y - 1), this._dot2(this._perm[B + 1], x - 1, y - 1), u), v);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @zh 3D Perlin 噪声
|
|
116
|
+
* @en 3D Perlin noise
|
|
117
|
+
*
|
|
118
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
119
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
120
|
+
* @param z - @zh Z 坐标 @en Z coordinate
|
|
121
|
+
* @returns @zh 噪声值 [-1, 1] @en Noise value [-1, 1]
|
|
122
|
+
*/
|
|
123
|
+
noise3D(x, y, z) {
|
|
124
|
+
const X = Math.floor(x) & 255;
|
|
125
|
+
const Y = Math.floor(y) & 255;
|
|
126
|
+
const Z = Math.floor(z) & 255;
|
|
127
|
+
x -= Math.floor(x);
|
|
128
|
+
y -= Math.floor(y);
|
|
129
|
+
z -= Math.floor(z);
|
|
130
|
+
const u = this._fade(x);
|
|
131
|
+
const v = this._fade(y);
|
|
132
|
+
const w = this._fade(z);
|
|
133
|
+
const A = this._perm[X] + Y;
|
|
134
|
+
const AA = this._perm[A] + Z;
|
|
135
|
+
const AB = this._perm[A + 1] + Z;
|
|
136
|
+
const B = this._perm[X + 1] + Y;
|
|
137
|
+
const BA = this._perm[B] + Z;
|
|
138
|
+
const BB = this._perm[B + 1] + Z;
|
|
139
|
+
return this._lerp(this._lerp(this._lerp(this._dot3(this._perm[AA], x, y, z), this._dot3(this._perm[BA], x - 1, y, z), u), this._lerp(this._dot3(this._perm[AB], x, y - 1, z), this._dot3(this._perm[BB], x - 1, y - 1, z), u), v), this._lerp(this._lerp(this._dot3(this._perm[AA + 1], x, y, z - 1), this._dot3(this._perm[BA + 1], x - 1, y, z - 1), u), this._lerp(this._dot3(this._perm[AB + 1], x, y - 1, z - 1), this._dot3(this._perm[BB + 1], x - 1, y - 1, z - 1), u), v), w);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
__name(_PerlinNoise, "PerlinNoise");
|
|
143
|
+
var PerlinNoise = _PerlinNoise;
|
|
144
|
+
function createPerlinNoise(seed = 0) {
|
|
145
|
+
return new PerlinNoise(seed);
|
|
146
|
+
}
|
|
147
|
+
__name(createPerlinNoise, "createPerlinNoise");
|
|
148
|
+
|
|
149
|
+
// src/noise/SimplexNoise.ts
|
|
150
|
+
var F2 = 0.5 * (Math.sqrt(3) - 1);
|
|
151
|
+
var G2 = (3 - Math.sqrt(3)) / 6;
|
|
152
|
+
var F3 = 1 / 3;
|
|
153
|
+
var G3 = 1 / 6;
|
|
154
|
+
var _SimplexNoise = class _SimplexNoise {
|
|
155
|
+
/**
|
|
156
|
+
* @zh 创建 Simplex 噪声生成器
|
|
157
|
+
* @en Create Simplex noise generator
|
|
158
|
+
*
|
|
159
|
+
* @param seed - @zh 随机种子 @en Random seed
|
|
160
|
+
*/
|
|
161
|
+
constructor(seed = 0) {
|
|
162
|
+
__publicField(this, "_perm");
|
|
163
|
+
__publicField(this, "_permMod12");
|
|
164
|
+
this._perm = new Uint8Array(512);
|
|
165
|
+
this._permMod12 = new Uint8Array(512);
|
|
166
|
+
this._seed(seed);
|
|
167
|
+
}
|
|
168
|
+
_seed(seed) {
|
|
169
|
+
const p = new Uint8Array(256);
|
|
170
|
+
for (let i = 0; i < 256; i++) {
|
|
171
|
+
p[i] = i;
|
|
172
|
+
}
|
|
173
|
+
let n = seed;
|
|
174
|
+
for (let i = 255; i > 0; i--) {
|
|
175
|
+
n = n * 16807 % 2147483647;
|
|
176
|
+
const j = n % (i + 1);
|
|
177
|
+
[p[i], p[j]] = [
|
|
178
|
+
p[j],
|
|
179
|
+
p[i]
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
for (let i = 0; i < 512; i++) {
|
|
183
|
+
this._perm[i] = p[i & 255];
|
|
184
|
+
this._permMod12[i] = this._perm[i] % 12;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* @zh 2D Simplex 噪声
|
|
189
|
+
* @en 2D Simplex noise
|
|
190
|
+
*
|
|
191
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
192
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
193
|
+
* @returns @zh 噪声值 [-1, 1] @en Noise value [-1, 1]
|
|
194
|
+
*/
|
|
195
|
+
noise2D(x, y) {
|
|
196
|
+
const grad3 = _SimplexNoise._grad3;
|
|
197
|
+
let n0 = 0, n1 = 0, n2 = 0;
|
|
198
|
+
const s = (x + y) * F2;
|
|
199
|
+
const i = Math.floor(x + s);
|
|
200
|
+
const j = Math.floor(y + s);
|
|
201
|
+
const t = (i + j) * G2;
|
|
202
|
+
const X0 = i - t;
|
|
203
|
+
const Y0 = j - t;
|
|
204
|
+
const x0 = x - X0;
|
|
205
|
+
const y0 = y - Y0;
|
|
206
|
+
let i1, j1;
|
|
207
|
+
if (x0 > y0) {
|
|
208
|
+
i1 = 1;
|
|
209
|
+
j1 = 0;
|
|
210
|
+
} else {
|
|
211
|
+
i1 = 0;
|
|
212
|
+
j1 = 1;
|
|
213
|
+
}
|
|
214
|
+
const x1 = x0 - i1 + G2;
|
|
215
|
+
const y1 = y0 - j1 + G2;
|
|
216
|
+
const x2 = x0 - 1 + 2 * G2;
|
|
217
|
+
const y2 = y0 - 1 + 2 * G2;
|
|
218
|
+
const ii = i & 255;
|
|
219
|
+
const jj = j & 255;
|
|
220
|
+
const gi0 = this._permMod12[ii + this._perm[jj]] * 3;
|
|
221
|
+
const gi1 = this._permMod12[ii + i1 + this._perm[jj + j1]] * 3;
|
|
222
|
+
const gi2 = this._permMod12[ii + 1 + this._perm[jj + 1]] * 3;
|
|
223
|
+
let t0 = 0.5 - x0 * x0 - y0 * y0;
|
|
224
|
+
if (t0 >= 0) {
|
|
225
|
+
t0 *= t0;
|
|
226
|
+
n0 = t0 * t0 * (grad3[gi0] * x0 + grad3[gi0 + 1] * y0);
|
|
227
|
+
}
|
|
228
|
+
let t1 = 0.5 - x1 * x1 - y1 * y1;
|
|
229
|
+
if (t1 >= 0) {
|
|
230
|
+
t1 *= t1;
|
|
231
|
+
n1 = t1 * t1 * (grad3[gi1] * x1 + grad3[gi1 + 1] * y1);
|
|
232
|
+
}
|
|
233
|
+
let t2 = 0.5 - x2 * x2 - y2 * y2;
|
|
234
|
+
if (t2 >= 0) {
|
|
235
|
+
t2 *= t2;
|
|
236
|
+
n2 = t2 * t2 * (grad3[gi2] * x2 + grad3[gi2 + 1] * y2);
|
|
237
|
+
}
|
|
238
|
+
return 70 * (n0 + n1 + n2);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* @zh 3D Simplex 噪声
|
|
242
|
+
* @en 3D Simplex noise
|
|
243
|
+
*
|
|
244
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
245
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
246
|
+
* @param z - @zh Z 坐标 @en Z coordinate
|
|
247
|
+
* @returns @zh 噪声值 [-1, 1] @en Noise value [-1, 1]
|
|
248
|
+
*/
|
|
249
|
+
noise3D(x, y, z) {
|
|
250
|
+
const grad3 = _SimplexNoise._grad3;
|
|
251
|
+
let n0 = 0, n1 = 0, n2 = 0, n3 = 0;
|
|
252
|
+
const s = (x + y + z) * F3;
|
|
253
|
+
const i = Math.floor(x + s);
|
|
254
|
+
const j = Math.floor(y + s);
|
|
255
|
+
const k = Math.floor(z + s);
|
|
256
|
+
const t = (i + j + k) * G3;
|
|
257
|
+
const X0 = i - t;
|
|
258
|
+
const Y0 = j - t;
|
|
259
|
+
const Z0 = k - t;
|
|
260
|
+
const x0 = x - X0;
|
|
261
|
+
const y0 = y - Y0;
|
|
262
|
+
const z0 = z - Z0;
|
|
263
|
+
let i1, j1, k1;
|
|
264
|
+
let i2, j2, k2;
|
|
265
|
+
if (x0 >= y0) {
|
|
266
|
+
if (y0 >= z0) {
|
|
267
|
+
i1 = 1;
|
|
268
|
+
j1 = 0;
|
|
269
|
+
k1 = 0;
|
|
270
|
+
i2 = 1;
|
|
271
|
+
j2 = 1;
|
|
272
|
+
k2 = 0;
|
|
273
|
+
} else if (x0 >= z0) {
|
|
274
|
+
i1 = 1;
|
|
275
|
+
j1 = 0;
|
|
276
|
+
k1 = 0;
|
|
277
|
+
i2 = 1;
|
|
278
|
+
j2 = 0;
|
|
279
|
+
k2 = 1;
|
|
280
|
+
} else {
|
|
281
|
+
i1 = 0;
|
|
282
|
+
j1 = 0;
|
|
283
|
+
k1 = 1;
|
|
284
|
+
i2 = 1;
|
|
285
|
+
j2 = 0;
|
|
286
|
+
k2 = 1;
|
|
287
|
+
}
|
|
288
|
+
} else {
|
|
289
|
+
if (y0 < z0) {
|
|
290
|
+
i1 = 0;
|
|
291
|
+
j1 = 0;
|
|
292
|
+
k1 = 1;
|
|
293
|
+
i2 = 0;
|
|
294
|
+
j2 = 1;
|
|
295
|
+
k2 = 1;
|
|
296
|
+
} else if (x0 < z0) {
|
|
297
|
+
i1 = 0;
|
|
298
|
+
j1 = 1;
|
|
299
|
+
k1 = 0;
|
|
300
|
+
i2 = 0;
|
|
301
|
+
j2 = 1;
|
|
302
|
+
k2 = 1;
|
|
303
|
+
} else {
|
|
304
|
+
i1 = 0;
|
|
305
|
+
j1 = 1;
|
|
306
|
+
k1 = 0;
|
|
307
|
+
i2 = 1;
|
|
308
|
+
j2 = 1;
|
|
309
|
+
k2 = 0;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const x1 = x0 - i1 + G3;
|
|
313
|
+
const y1 = y0 - j1 + G3;
|
|
314
|
+
const z1 = z0 - k1 + G3;
|
|
315
|
+
const x2 = x0 - i2 + 2 * G3;
|
|
316
|
+
const y2 = y0 - j2 + 2 * G3;
|
|
317
|
+
const z2 = z0 - k2 + 2 * G3;
|
|
318
|
+
const x3 = x0 - 1 + 3 * G3;
|
|
319
|
+
const y3 = y0 - 1 + 3 * G3;
|
|
320
|
+
const z3 = z0 - 1 + 3 * G3;
|
|
321
|
+
const ii = i & 255;
|
|
322
|
+
const jj = j & 255;
|
|
323
|
+
const kk = k & 255;
|
|
324
|
+
const gi0 = this._permMod12[ii + this._perm[jj + this._perm[kk]]] * 3;
|
|
325
|
+
const gi1 = this._permMod12[ii + i1 + this._perm[jj + j1 + this._perm[kk + k1]]] * 3;
|
|
326
|
+
const gi2 = this._permMod12[ii + i2 + this._perm[jj + j2 + this._perm[kk + k2]]] * 3;
|
|
327
|
+
const gi3 = this._permMod12[ii + 1 + this._perm[jj + 1 + this._perm[kk + 1]]] * 3;
|
|
328
|
+
let t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0;
|
|
329
|
+
if (t0 >= 0) {
|
|
330
|
+
t0 *= t0;
|
|
331
|
+
n0 = t0 * t0 * (grad3[gi0] * x0 + grad3[gi0 + 1] * y0 + grad3[gi0 + 2] * z0);
|
|
332
|
+
}
|
|
333
|
+
let t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1;
|
|
334
|
+
if (t1 >= 0) {
|
|
335
|
+
t1 *= t1;
|
|
336
|
+
n1 = t1 * t1 * (grad3[gi1] * x1 + grad3[gi1 + 1] * y1 + grad3[gi1 + 2] * z1);
|
|
337
|
+
}
|
|
338
|
+
let t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2;
|
|
339
|
+
if (t2 >= 0) {
|
|
340
|
+
t2 *= t2;
|
|
341
|
+
n2 = t2 * t2 * (grad3[gi2] * x2 + grad3[gi2 + 1] * y2 + grad3[gi2 + 2] * z2);
|
|
342
|
+
}
|
|
343
|
+
let t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3;
|
|
344
|
+
if (t3 >= 0) {
|
|
345
|
+
t3 *= t3;
|
|
346
|
+
n3 = t3 * t3 * (grad3[gi3] * x3 + grad3[gi3 + 1] * y3 + grad3[gi3 + 2] * z3);
|
|
347
|
+
}
|
|
348
|
+
return 32 * (n0 + n1 + n2 + n3);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
__name(_SimplexNoise, "SimplexNoise");
|
|
352
|
+
__publicField(_SimplexNoise, "_grad3", new Float32Array([
|
|
353
|
+
1,
|
|
354
|
+
1,
|
|
355
|
+
0,
|
|
356
|
+
-1,
|
|
357
|
+
1,
|
|
358
|
+
0,
|
|
359
|
+
1,
|
|
360
|
+
-1,
|
|
361
|
+
0,
|
|
362
|
+
-1,
|
|
363
|
+
-1,
|
|
364
|
+
0,
|
|
365
|
+
1,
|
|
366
|
+
0,
|
|
367
|
+
1,
|
|
368
|
+
-1,
|
|
369
|
+
0,
|
|
370
|
+
1,
|
|
371
|
+
1,
|
|
372
|
+
0,
|
|
373
|
+
-1,
|
|
374
|
+
-1,
|
|
375
|
+
0,
|
|
376
|
+
-1,
|
|
377
|
+
0,
|
|
378
|
+
1,
|
|
379
|
+
1,
|
|
380
|
+
0,
|
|
381
|
+
-1,
|
|
382
|
+
1,
|
|
383
|
+
0,
|
|
384
|
+
1,
|
|
385
|
+
-1,
|
|
386
|
+
0,
|
|
387
|
+
-1,
|
|
388
|
+
-1
|
|
389
|
+
]));
|
|
390
|
+
var SimplexNoise = _SimplexNoise;
|
|
391
|
+
function createSimplexNoise(seed = 0) {
|
|
392
|
+
return new SimplexNoise(seed);
|
|
393
|
+
}
|
|
394
|
+
__name(createSimplexNoise, "createSimplexNoise");
|
|
395
|
+
|
|
396
|
+
// src/noise/WorleyNoise.ts
|
|
397
|
+
var _WorleyNoise = class _WorleyNoise {
|
|
398
|
+
/**
|
|
399
|
+
* @zh 创建 Worley 噪声生成器
|
|
400
|
+
* @en Create Worley noise generator
|
|
401
|
+
*
|
|
402
|
+
* @param seed - @zh 随机种子 @en Random seed
|
|
403
|
+
* @param distanceFunc - @zh 距离函数 @en Distance function
|
|
404
|
+
*/
|
|
405
|
+
constructor(seed = 0, distanceFunc = "euclidean") {
|
|
406
|
+
__publicField(this, "_seed");
|
|
407
|
+
__publicField(this, "_distanceFunc");
|
|
408
|
+
this._seed = seed;
|
|
409
|
+
this._distanceFunc = distanceFunc;
|
|
410
|
+
}
|
|
411
|
+
_hash(x, y, z = 0) {
|
|
412
|
+
let h = this._seed;
|
|
413
|
+
h ^= x * 374761393;
|
|
414
|
+
h ^= y * 668265263;
|
|
415
|
+
h ^= z * 1274126177;
|
|
416
|
+
h = Math.imul(h ^ h >>> 13, 1274126177);
|
|
417
|
+
return h;
|
|
418
|
+
}
|
|
419
|
+
_randomPoint(cellX, cellY, index) {
|
|
420
|
+
const h1 = this._hash(cellX, cellY, index);
|
|
421
|
+
const h2 = this._hash(cellX, cellY, index + 1e3);
|
|
422
|
+
return {
|
|
423
|
+
x: cellX + (h1 & 65535) / 65536,
|
|
424
|
+
y: cellY + (h2 & 65535) / 65536
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
_randomPoint3D(cellX, cellY, cellZ, index) {
|
|
428
|
+
const h1 = this._hash(cellX, cellY, cellZ * 1e3 + index);
|
|
429
|
+
const h2 = this._hash(cellX, cellY, cellZ * 1e3 + index + 1e3);
|
|
430
|
+
const h3 = this._hash(cellX, cellY, cellZ * 1e3 + index + 2e3);
|
|
431
|
+
return {
|
|
432
|
+
x: cellX + (h1 & 65535) / 65536,
|
|
433
|
+
y: cellY + (h2 & 65535) / 65536,
|
|
434
|
+
z: cellZ + (h3 & 65535) / 65536
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
_distance2D(x1, y1, x2, y2) {
|
|
438
|
+
const dx = x2 - x1;
|
|
439
|
+
const dy = y2 - y1;
|
|
440
|
+
switch (this._distanceFunc) {
|
|
441
|
+
case "manhattan":
|
|
442
|
+
return Math.abs(dx) + Math.abs(dy);
|
|
443
|
+
case "chebyshev":
|
|
444
|
+
return Math.max(Math.abs(dx), Math.abs(dy));
|
|
445
|
+
case "euclidean":
|
|
446
|
+
default:
|
|
447
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
_distance3D(x1, y1, z1, x2, y2, z2) {
|
|
451
|
+
const dx = x2 - x1;
|
|
452
|
+
const dy = y2 - y1;
|
|
453
|
+
const dz = z2 - z1;
|
|
454
|
+
switch (this._distanceFunc) {
|
|
455
|
+
case "manhattan":
|
|
456
|
+
return Math.abs(dx) + Math.abs(dy) + Math.abs(dz);
|
|
457
|
+
case "chebyshev":
|
|
458
|
+
return Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dz));
|
|
459
|
+
case "euclidean":
|
|
460
|
+
default:
|
|
461
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* @zh 2D Worley 噪声
|
|
466
|
+
* @en 2D Worley noise
|
|
467
|
+
*
|
|
468
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
469
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
470
|
+
* @param pointsPerCell - @zh 每个单元格的点数 @en Points per cell
|
|
471
|
+
* @returns @zh 到最近点的距离 [0, ~1.4] @en Distance to nearest point [0, ~1.4]
|
|
472
|
+
*/
|
|
473
|
+
noise2D(x, y, pointsPerCell = 1) {
|
|
474
|
+
const cellX = Math.floor(x);
|
|
475
|
+
const cellY = Math.floor(y);
|
|
476
|
+
let minDist = Infinity;
|
|
477
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
478
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
479
|
+
const cx = cellX + dx;
|
|
480
|
+
const cy = cellY + dy;
|
|
481
|
+
for (let i = 0; i < pointsPerCell; i++) {
|
|
482
|
+
const point = this._randomPoint(cx, cy, i);
|
|
483
|
+
const dist = this._distance2D(x, y, point.x, point.y);
|
|
484
|
+
minDist = Math.min(minDist, dist);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return minDist;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* @zh 3D Worley 噪声
|
|
492
|
+
* @en 3D Worley noise
|
|
493
|
+
*
|
|
494
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
495
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
496
|
+
* @param z - @zh Z 坐标 @en Z coordinate
|
|
497
|
+
* @param pointsPerCell - @zh 每个单元格的点数 @en Points per cell
|
|
498
|
+
* @returns @zh 到最近点的距离 @en Distance to nearest point
|
|
499
|
+
*/
|
|
500
|
+
noise3D(x, y, z, pointsPerCell = 1) {
|
|
501
|
+
const cellX = Math.floor(x);
|
|
502
|
+
const cellY = Math.floor(y);
|
|
503
|
+
const cellZ = Math.floor(z);
|
|
504
|
+
let minDist = Infinity;
|
|
505
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
506
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
507
|
+
for (let dz = -1; dz <= 1; dz++) {
|
|
508
|
+
const cx = cellX + dx;
|
|
509
|
+
const cy = cellY + dy;
|
|
510
|
+
const cz = cellZ + dz;
|
|
511
|
+
for (let i = 0; i < pointsPerCell; i++) {
|
|
512
|
+
const point = this._randomPoint3D(cx, cy, cz, i);
|
|
513
|
+
const dist = this._distance3D(x, y, z, point.x, point.y, point.z);
|
|
514
|
+
minDist = Math.min(minDist, dist);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return minDist;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* @zh 获取到第 N 近点的距离(用于更复杂的纹理)
|
|
523
|
+
* @en Get distance to Nth nearest point (for more complex textures)
|
|
524
|
+
*
|
|
525
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
526
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
527
|
+
* @param n - @zh 第 N 近 (1 = 最近) @en Nth nearest (1 = nearest)
|
|
528
|
+
* @returns @zh 距离值 @en Distance value
|
|
529
|
+
*/
|
|
530
|
+
nthNearest2D(x, y, n = 1) {
|
|
531
|
+
const cellX = Math.floor(x);
|
|
532
|
+
const cellY = Math.floor(y);
|
|
533
|
+
const distances = [];
|
|
534
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
535
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
536
|
+
const cx = cellX + dx;
|
|
537
|
+
const cy = cellY + dy;
|
|
538
|
+
const point = this._randomPoint(cx, cy, 0);
|
|
539
|
+
distances.push(this._distance2D(x, y, point.x, point.y));
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
distances.sort((a, b) => a - b);
|
|
543
|
+
return distances[Math.min(n - 1, distances.length - 1)];
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
__name(_WorleyNoise, "WorleyNoise");
|
|
547
|
+
var WorleyNoise = _WorleyNoise;
|
|
548
|
+
function createWorleyNoise(seed = 0, distanceFunc = "euclidean") {
|
|
549
|
+
return new WorleyNoise(seed, distanceFunc);
|
|
550
|
+
}
|
|
551
|
+
__name(createWorleyNoise, "createWorleyNoise");
|
|
552
|
+
|
|
553
|
+
// src/noise/FBM.ts
|
|
554
|
+
var DEFAULT_CONFIG = {
|
|
555
|
+
octaves: 6,
|
|
556
|
+
lacunarity: 2,
|
|
557
|
+
persistence: 0.5,
|
|
558
|
+
frequency: 1,
|
|
559
|
+
amplitude: 1
|
|
560
|
+
};
|
|
561
|
+
var _FBM = class _FBM {
|
|
562
|
+
/**
|
|
563
|
+
* @zh 创建 FBM 噪声生成器
|
|
564
|
+
* @en Create FBM noise generator
|
|
565
|
+
*
|
|
566
|
+
* @param noise - @zh 基础噪声函数 @en Base noise function
|
|
567
|
+
* @param config - @zh 配置 @en Configuration
|
|
568
|
+
*/
|
|
569
|
+
constructor(noise, config) {
|
|
570
|
+
__publicField(this, "_noise");
|
|
571
|
+
__publicField(this, "_config");
|
|
572
|
+
this._noise = noise;
|
|
573
|
+
this._config = {
|
|
574
|
+
...DEFAULT_CONFIG,
|
|
575
|
+
...config
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* @zh 2D FBM 噪声
|
|
580
|
+
* @en 2D FBM noise
|
|
581
|
+
*
|
|
582
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
583
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
584
|
+
* @returns @zh 噪声值 @en Noise value
|
|
585
|
+
*/
|
|
586
|
+
noise2D(x, y) {
|
|
587
|
+
let value = 0;
|
|
588
|
+
let frequency = this._config.frequency;
|
|
589
|
+
let amplitude = this._config.amplitude;
|
|
590
|
+
let maxValue = 0;
|
|
591
|
+
for (let i = 0; i < this._config.octaves; i++) {
|
|
592
|
+
value += this._noise.noise2D(x * frequency, y * frequency) * amplitude;
|
|
593
|
+
maxValue += amplitude;
|
|
594
|
+
amplitude *= this._config.persistence;
|
|
595
|
+
frequency *= this._config.lacunarity;
|
|
596
|
+
}
|
|
597
|
+
return value / maxValue;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* @zh 3D FBM 噪声
|
|
601
|
+
* @en 3D FBM noise
|
|
602
|
+
*
|
|
603
|
+
* @param x - @zh X 坐标 @en X coordinate
|
|
604
|
+
* @param y - @zh Y 坐标 @en Y coordinate
|
|
605
|
+
* @param z - @zh Z 坐标 @en Z coordinate
|
|
606
|
+
* @returns @zh 噪声值 @en Noise value
|
|
607
|
+
*/
|
|
608
|
+
noise3D(x, y, z) {
|
|
609
|
+
if (!this._noise.noise3D) {
|
|
610
|
+
throw new Error("Base noise does not support 3D");
|
|
611
|
+
}
|
|
612
|
+
let value = 0;
|
|
613
|
+
let frequency = this._config.frequency;
|
|
614
|
+
let amplitude = this._config.amplitude;
|
|
615
|
+
let maxValue = 0;
|
|
616
|
+
for (let i = 0; i < this._config.octaves; i++) {
|
|
617
|
+
value += this._noise.noise3D(x * frequency, y * frequency, z * frequency) * amplitude;
|
|
618
|
+
maxValue += amplitude;
|
|
619
|
+
amplitude *= this._config.persistence;
|
|
620
|
+
frequency *= this._config.lacunarity;
|
|
621
|
+
}
|
|
622
|
+
return value / maxValue;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* @zh Ridged FBM(脊状,适合山脉)
|
|
626
|
+
* @en Ridged FBM (suitable for mountains)
|
|
627
|
+
*/
|
|
628
|
+
ridged2D(x, y) {
|
|
629
|
+
let value = 0;
|
|
630
|
+
let frequency = this._config.frequency;
|
|
631
|
+
let amplitude = this._config.amplitude;
|
|
632
|
+
let weight = 1;
|
|
633
|
+
for (let i = 0; i < this._config.octaves; i++) {
|
|
634
|
+
let signal = this._noise.noise2D(x * frequency, y * frequency);
|
|
635
|
+
signal = 1 - Math.abs(signal);
|
|
636
|
+
signal *= signal;
|
|
637
|
+
signal *= weight;
|
|
638
|
+
weight = Math.max(0, Math.min(1, signal * 2));
|
|
639
|
+
value += signal * amplitude;
|
|
640
|
+
frequency *= this._config.lacunarity;
|
|
641
|
+
amplitude *= this._config.persistence;
|
|
642
|
+
}
|
|
643
|
+
return value;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* @zh Turbulence(湍流,使用绝对值)
|
|
647
|
+
* @en Turbulence (using absolute value)
|
|
648
|
+
*/
|
|
649
|
+
turbulence2D(x, y) {
|
|
650
|
+
let value = 0;
|
|
651
|
+
let frequency = this._config.frequency;
|
|
652
|
+
let amplitude = this._config.amplitude;
|
|
653
|
+
let maxValue = 0;
|
|
654
|
+
for (let i = 0; i < this._config.octaves; i++) {
|
|
655
|
+
value += Math.abs(this._noise.noise2D(x * frequency, y * frequency)) * amplitude;
|
|
656
|
+
maxValue += amplitude;
|
|
657
|
+
amplitude *= this._config.persistence;
|
|
658
|
+
frequency *= this._config.lacunarity;
|
|
659
|
+
}
|
|
660
|
+
return value / maxValue;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* @zh Billowed(膨胀,适合云朵)
|
|
664
|
+
* @en Billowed (suitable for clouds)
|
|
665
|
+
*/
|
|
666
|
+
billowed2D(x, y) {
|
|
667
|
+
let value = 0;
|
|
668
|
+
let frequency = this._config.frequency;
|
|
669
|
+
let amplitude = this._config.amplitude;
|
|
670
|
+
let maxValue = 0;
|
|
671
|
+
for (let i = 0; i < this._config.octaves; i++) {
|
|
672
|
+
const n = this._noise.noise2D(x * frequency, y * frequency);
|
|
673
|
+
value += (Math.abs(n) * 2 - 1) * amplitude;
|
|
674
|
+
maxValue += amplitude;
|
|
675
|
+
amplitude *= this._config.persistence;
|
|
676
|
+
frequency *= this._config.lacunarity;
|
|
677
|
+
}
|
|
678
|
+
return value / maxValue;
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
__name(_FBM, "FBM");
|
|
682
|
+
var FBM = _FBM;
|
|
683
|
+
function createFBM(noise, config) {
|
|
684
|
+
return new FBM(noise, config);
|
|
685
|
+
}
|
|
686
|
+
__name(createFBM, "createFBM");
|
|
687
|
+
|
|
688
|
+
// src/random/SeededRandom.ts
|
|
689
|
+
var _SeededRandom = class _SeededRandom {
|
|
690
|
+
/**
|
|
691
|
+
* @zh 创建种子随机数生成器
|
|
692
|
+
* @en Create seeded random number generator
|
|
693
|
+
*
|
|
694
|
+
* @param seed - @zh 随机种子 @en Random seed
|
|
695
|
+
*/
|
|
696
|
+
constructor(seed = Date.now()) {
|
|
697
|
+
__publicField(this, "_s0");
|
|
698
|
+
__publicField(this, "_s1");
|
|
699
|
+
__publicField(this, "_initialS0");
|
|
700
|
+
__publicField(this, "_initialS1");
|
|
701
|
+
let h = seed | 0;
|
|
702
|
+
h = Math.imul(h ^ h >>> 16, 2246822507);
|
|
703
|
+
h = Math.imul(h ^ h >>> 13, 3266489909);
|
|
704
|
+
h ^= h >>> 16;
|
|
705
|
+
this._s0 = h >>> 0;
|
|
706
|
+
this._s1 = h * 2654435769 >>> 0;
|
|
707
|
+
if (this._s0 === 0) this._s0 = 1;
|
|
708
|
+
if (this._s1 === 0) this._s1 = 1;
|
|
709
|
+
this._initialS0 = this._s0;
|
|
710
|
+
this._initialS1 = this._s1;
|
|
711
|
+
for (let i = 0; i < 10; i++) {
|
|
712
|
+
this.next();
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* @zh 重置到初始状态
|
|
717
|
+
* @en Reset to initial state
|
|
718
|
+
*/
|
|
719
|
+
reset() {
|
|
720
|
+
this._s0 = this._initialS0;
|
|
721
|
+
this._s1 = this._initialS1;
|
|
722
|
+
for (let i = 0; i < 10; i++) {
|
|
723
|
+
this.next();
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* @zh 生成下一个随机数 [0, 1)
|
|
728
|
+
* @en Generate next random number [0, 1)
|
|
729
|
+
*/
|
|
730
|
+
next() {
|
|
731
|
+
let s1 = this._s0;
|
|
732
|
+
const s0 = this._s1;
|
|
733
|
+
this._s0 = s0;
|
|
734
|
+
s1 ^= s1 << 23;
|
|
735
|
+
s1 ^= s1 >>> 17;
|
|
736
|
+
s1 ^= s0;
|
|
737
|
+
s1 ^= s0 >>> 26;
|
|
738
|
+
this._s1 = s1;
|
|
739
|
+
return (this._s0 + this._s1 >>> 0) / 4294967296;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* @zh 生成整数 [min, max]
|
|
743
|
+
* @en Generate integer [min, max]
|
|
744
|
+
*/
|
|
745
|
+
nextInt(min, max) {
|
|
746
|
+
return Math.floor(this.next() * (max - min + 1)) + min;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* @zh 生成浮点数 [min, max)
|
|
750
|
+
* @en Generate float [min, max)
|
|
751
|
+
*/
|
|
752
|
+
nextFloat(min, max) {
|
|
753
|
+
return this.next() * (max - min) + min;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* @zh 生成布尔值
|
|
757
|
+
* @en Generate boolean
|
|
758
|
+
*
|
|
759
|
+
* @param probability - @zh 为 true 的概率 [0, 1] @en Probability of true [0, 1]
|
|
760
|
+
*/
|
|
761
|
+
nextBool(probability = 0.5) {
|
|
762
|
+
return this.next() < probability;
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* @zh 生成正态分布随机数 (Box-Muller 变换)
|
|
766
|
+
* @en Generate normally distributed random number (Box-Muller transform)
|
|
767
|
+
*
|
|
768
|
+
* @param mean - @zh 均值 @en Mean
|
|
769
|
+
* @param stdDev - @zh 标准差 @en Standard deviation
|
|
770
|
+
*/
|
|
771
|
+
nextGaussian(mean = 0, stdDev = 1) {
|
|
772
|
+
const u1 = this.next();
|
|
773
|
+
const u2 = this.next();
|
|
774
|
+
const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
|
|
775
|
+
return z0 * stdDev + mean;
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* @zh 生成指数分布随机数
|
|
779
|
+
* @en Generate exponentially distributed random number
|
|
780
|
+
*
|
|
781
|
+
* @param lambda - @zh 率参数 @en Rate parameter
|
|
782
|
+
*/
|
|
783
|
+
nextExponential(lambda = 1) {
|
|
784
|
+
return -Math.log(1 - this.next()) / lambda;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* @zh 在圆内生成均匀分布的随机点
|
|
788
|
+
* @en Generate uniformly distributed random point in circle
|
|
789
|
+
*
|
|
790
|
+
* @param radius - @zh 半径 @en Radius
|
|
791
|
+
*/
|
|
792
|
+
nextPointInCircle(radius = 1) {
|
|
793
|
+
const r = Math.sqrt(this.next()) * radius;
|
|
794
|
+
const theta = this.next() * 2 * Math.PI;
|
|
795
|
+
return {
|
|
796
|
+
x: r * Math.cos(theta),
|
|
797
|
+
y: r * Math.sin(theta)
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* @zh 在圆环上生成随机点
|
|
802
|
+
* @en Generate random point on circle
|
|
803
|
+
*
|
|
804
|
+
* @param radius - @zh 半径 @en Radius
|
|
805
|
+
*/
|
|
806
|
+
nextPointOnCircle(radius = 1) {
|
|
807
|
+
const theta = this.next() * 2 * Math.PI;
|
|
808
|
+
return {
|
|
809
|
+
x: radius * Math.cos(theta),
|
|
810
|
+
y: radius * Math.sin(theta)
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* @zh 在球内生成均匀分布的随机点
|
|
815
|
+
* @en Generate uniformly distributed random point in sphere
|
|
816
|
+
*
|
|
817
|
+
* @param radius - @zh 半径 @en Radius
|
|
818
|
+
*/
|
|
819
|
+
nextPointInSphere(radius = 1) {
|
|
820
|
+
const r = Math.cbrt(this.next()) * radius;
|
|
821
|
+
const theta = this.next() * 2 * Math.PI;
|
|
822
|
+
const phi = Math.acos(2 * this.next() - 1);
|
|
823
|
+
return {
|
|
824
|
+
x: r * Math.sin(phi) * Math.cos(theta),
|
|
825
|
+
y: r * Math.sin(phi) * Math.sin(theta),
|
|
826
|
+
z: r * Math.cos(phi)
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* @zh 生成随机方向向量
|
|
831
|
+
* @en Generate random direction vector
|
|
832
|
+
*/
|
|
833
|
+
nextDirection2D() {
|
|
834
|
+
const theta = this.next() * 2 * Math.PI;
|
|
835
|
+
return {
|
|
836
|
+
x: Math.cos(theta),
|
|
837
|
+
y: Math.sin(theta)
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
__name(_SeededRandom, "SeededRandom");
|
|
842
|
+
var SeededRandom = _SeededRandom;
|
|
843
|
+
function createSeededRandom(seed) {
|
|
844
|
+
return new SeededRandom(seed);
|
|
845
|
+
}
|
|
846
|
+
__name(createSeededRandom, "createSeededRandom");
|
|
847
|
+
|
|
848
|
+
// src/random/WeightedRandom.ts
|
|
849
|
+
var _WeightedRandom = class _WeightedRandom {
|
|
850
|
+
/**
|
|
851
|
+
* @zh 创建加权随机选择器
|
|
852
|
+
* @en Create weighted random selector
|
|
853
|
+
*
|
|
854
|
+
* @param items - @zh 加权项数组 @en Array of weighted items
|
|
855
|
+
*/
|
|
856
|
+
constructor(items) {
|
|
857
|
+
__publicField(this, "_items");
|
|
858
|
+
__publicField(this, "_cumulativeWeights");
|
|
859
|
+
__publicField(this, "_totalWeight");
|
|
860
|
+
if (items.length === 0) {
|
|
861
|
+
throw new Error("Items array cannot be empty");
|
|
862
|
+
}
|
|
863
|
+
this._items = [
|
|
864
|
+
...items
|
|
865
|
+
];
|
|
866
|
+
this._cumulativeWeights = [];
|
|
867
|
+
let total = 0;
|
|
868
|
+
for (const item of this._items) {
|
|
869
|
+
if (item.weight <= 0) {
|
|
870
|
+
throw new Error("Weights must be positive");
|
|
871
|
+
}
|
|
872
|
+
total += item.weight;
|
|
873
|
+
this._cumulativeWeights.push(total);
|
|
874
|
+
}
|
|
875
|
+
this._totalWeight = total;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* @zh 随机选择一个项目
|
|
879
|
+
* @en Randomly select an item
|
|
880
|
+
*
|
|
881
|
+
* @param rng - @zh 随机数生成器 @en Random number generator
|
|
882
|
+
*/
|
|
883
|
+
pick(rng) {
|
|
884
|
+
const r = rng.next() * this._totalWeight;
|
|
885
|
+
let left = 0;
|
|
886
|
+
let right = this._cumulativeWeights.length - 1;
|
|
887
|
+
while (left < right) {
|
|
888
|
+
const mid = left + right >>> 1;
|
|
889
|
+
if (this._cumulativeWeights[mid] < r) {
|
|
890
|
+
left = mid + 1;
|
|
891
|
+
} else {
|
|
892
|
+
right = mid;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
return this._items[left].value;
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* @zh 使用 Math.random 选择
|
|
899
|
+
* @en Pick using Math.random
|
|
900
|
+
*/
|
|
901
|
+
pickRandom() {
|
|
902
|
+
return this.pick({
|
|
903
|
+
next: /* @__PURE__ */ __name(() => Math.random(), "next")
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* @zh 获取项目的选中概率
|
|
908
|
+
* @en Get selection probability of an item
|
|
909
|
+
*/
|
|
910
|
+
getProbability(index) {
|
|
911
|
+
if (index < 0 || index >= this._items.length) {
|
|
912
|
+
throw new Error("Index out of bounds");
|
|
913
|
+
}
|
|
914
|
+
return this._items[index].weight / this._totalWeight;
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* @zh 获取所有项目数量
|
|
918
|
+
* @en Get total item count
|
|
919
|
+
*/
|
|
920
|
+
get size() {
|
|
921
|
+
return this._items.length;
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* @zh 获取总权重
|
|
925
|
+
* @en Get total weight
|
|
926
|
+
*/
|
|
927
|
+
get totalWeight() {
|
|
928
|
+
return this._totalWeight;
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
__name(_WeightedRandom, "WeightedRandom");
|
|
932
|
+
var WeightedRandom = _WeightedRandom;
|
|
933
|
+
function weightedPick(items, rng) {
|
|
934
|
+
if (items.length === 0) {
|
|
935
|
+
throw new Error("Items array cannot be empty");
|
|
936
|
+
}
|
|
937
|
+
let totalWeight = 0;
|
|
938
|
+
for (const item of items) {
|
|
939
|
+
totalWeight += item.weight;
|
|
940
|
+
}
|
|
941
|
+
let r = rng.next() * totalWeight;
|
|
942
|
+
for (const item of items) {
|
|
943
|
+
r -= item.weight;
|
|
944
|
+
if (r <= 0) {
|
|
945
|
+
return item.value;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return items[items.length - 1].value;
|
|
949
|
+
}
|
|
950
|
+
__name(weightedPick, "weightedPick");
|
|
951
|
+
function weightedPickFromMap(weights, rng) {
|
|
952
|
+
const items = [];
|
|
953
|
+
for (const key in weights) {
|
|
954
|
+
items.push({
|
|
955
|
+
value: key,
|
|
956
|
+
weight: weights[key]
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
return weightedPick(items, rng);
|
|
960
|
+
}
|
|
961
|
+
__name(weightedPickFromMap, "weightedPickFromMap");
|
|
962
|
+
function createWeightedRandom(items) {
|
|
963
|
+
return new WeightedRandom(items);
|
|
964
|
+
}
|
|
965
|
+
__name(createWeightedRandom, "createWeightedRandom");
|
|
966
|
+
|
|
967
|
+
// src/random/Shuffle.ts
|
|
968
|
+
function shuffle(array, rng) {
|
|
969
|
+
for (let i = array.length - 1; i > 0; i--) {
|
|
970
|
+
const j = Math.floor(rng.next() * (i + 1));
|
|
971
|
+
[array[i], array[j]] = [
|
|
972
|
+
array[j],
|
|
973
|
+
array[i]
|
|
974
|
+
];
|
|
975
|
+
}
|
|
976
|
+
return array;
|
|
977
|
+
}
|
|
978
|
+
__name(shuffle, "shuffle");
|
|
979
|
+
function shuffleCopy(array, rng) {
|
|
980
|
+
return shuffle([
|
|
981
|
+
...array
|
|
982
|
+
], rng);
|
|
983
|
+
}
|
|
984
|
+
__name(shuffleCopy, "shuffleCopy");
|
|
985
|
+
function pickOne(array, rng) {
|
|
986
|
+
if (array.length === 0) {
|
|
987
|
+
throw new Error("Cannot pick from empty array");
|
|
988
|
+
}
|
|
989
|
+
return array[Math.floor(rng.next() * array.length)];
|
|
990
|
+
}
|
|
991
|
+
__name(pickOne, "pickOne");
|
|
992
|
+
function sample(array, count, rng) {
|
|
993
|
+
if (count > array.length) {
|
|
994
|
+
throw new Error("Sample count exceeds array length");
|
|
995
|
+
}
|
|
996
|
+
if (count === array.length) {
|
|
997
|
+
return shuffleCopy(array, rng);
|
|
998
|
+
}
|
|
999
|
+
if (count < array.length / 2) {
|
|
1000
|
+
const result = [];
|
|
1001
|
+
const indices = /* @__PURE__ */ new Set();
|
|
1002
|
+
while (result.length < count) {
|
|
1003
|
+
const index = Math.floor(rng.next() * array.length);
|
|
1004
|
+
if (!indices.has(index)) {
|
|
1005
|
+
indices.add(index);
|
|
1006
|
+
result.push(array[index]);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return result;
|
|
1010
|
+
}
|
|
1011
|
+
return shuffleCopy(array, rng).slice(0, count);
|
|
1012
|
+
}
|
|
1013
|
+
__name(sample, "sample");
|
|
1014
|
+
function sampleWithReplacement(array, count, rng) {
|
|
1015
|
+
if (array.length === 0) {
|
|
1016
|
+
throw new Error("Cannot sample from empty array");
|
|
1017
|
+
}
|
|
1018
|
+
const result = [];
|
|
1019
|
+
for (let i = 0; i < count; i++) {
|
|
1020
|
+
result.push(pickOne(array, rng));
|
|
1021
|
+
}
|
|
1022
|
+
return result;
|
|
1023
|
+
}
|
|
1024
|
+
__name(sampleWithReplacement, "sampleWithReplacement");
|
|
1025
|
+
function randomIntegers(min, max, count, rng) {
|
|
1026
|
+
const range = max - min + 1;
|
|
1027
|
+
if (count > range) {
|
|
1028
|
+
throw new Error("Count exceeds range");
|
|
1029
|
+
}
|
|
1030
|
+
const numbers = [];
|
|
1031
|
+
for (let i = min; i <= max; i++) {
|
|
1032
|
+
numbers.push(i);
|
|
1033
|
+
}
|
|
1034
|
+
return sample(numbers, count, rng);
|
|
1035
|
+
}
|
|
1036
|
+
__name(randomIntegers, "randomIntegers");
|
|
1037
|
+
function weightedSample(items, weights, count, rng) {
|
|
1038
|
+
if (items.length !== weights.length) {
|
|
1039
|
+
throw new Error("Items and weights must have same length");
|
|
1040
|
+
}
|
|
1041
|
+
if (count > items.length) {
|
|
1042
|
+
throw new Error("Sample count exceeds array length");
|
|
1043
|
+
}
|
|
1044
|
+
const result = [];
|
|
1045
|
+
const remaining = [
|
|
1046
|
+
...items
|
|
1047
|
+
];
|
|
1048
|
+
const remainingWeights = [
|
|
1049
|
+
...weights
|
|
1050
|
+
];
|
|
1051
|
+
for (let i = 0; i < count; i++) {
|
|
1052
|
+
let totalWeight = 0;
|
|
1053
|
+
for (const w of remainingWeights) {
|
|
1054
|
+
totalWeight += w;
|
|
1055
|
+
}
|
|
1056
|
+
let r = rng.next() * totalWeight;
|
|
1057
|
+
let selectedIndex = 0;
|
|
1058
|
+
for (let j = 0; j < remainingWeights.length; j++) {
|
|
1059
|
+
r -= remainingWeights[j];
|
|
1060
|
+
if (r <= 0) {
|
|
1061
|
+
selectedIndex = j;
|
|
1062
|
+
break;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
result.push(remaining[selectedIndex]);
|
|
1066
|
+
remaining.splice(selectedIndex, 1);
|
|
1067
|
+
remainingWeights.splice(selectedIndex, 1);
|
|
1068
|
+
}
|
|
1069
|
+
return result;
|
|
1070
|
+
}
|
|
1071
|
+
__name(weightedSample, "weightedSample");
|
|
1072
|
+
|
|
1073
|
+
// src/nodes/ProcGenNodes.ts
|
|
1074
|
+
var noiseCache = /* @__PURE__ */ new Map();
|
|
1075
|
+
function getPerlinNoise(seed) {
|
|
1076
|
+
const key = `perlin_${seed}`;
|
|
1077
|
+
if (!noiseCache.has(key)) {
|
|
1078
|
+
noiseCache.set(key, new PerlinNoise(seed));
|
|
1079
|
+
}
|
|
1080
|
+
return noiseCache.get(key);
|
|
1081
|
+
}
|
|
1082
|
+
__name(getPerlinNoise, "getPerlinNoise");
|
|
1083
|
+
function getSimplexNoise(seed) {
|
|
1084
|
+
const key = `simplex_${seed}`;
|
|
1085
|
+
if (!noiseCache.has(key)) {
|
|
1086
|
+
noiseCache.set(key, new SimplexNoise(seed));
|
|
1087
|
+
}
|
|
1088
|
+
return noiseCache.get(key);
|
|
1089
|
+
}
|
|
1090
|
+
__name(getSimplexNoise, "getSimplexNoise");
|
|
1091
|
+
function getWorleyNoise(seed) {
|
|
1092
|
+
const key = `worley_${seed}`;
|
|
1093
|
+
if (!noiseCache.has(key)) {
|
|
1094
|
+
noiseCache.set(key, new WorleyNoise(seed));
|
|
1095
|
+
}
|
|
1096
|
+
return noiseCache.get(key);
|
|
1097
|
+
}
|
|
1098
|
+
__name(getWorleyNoise, "getWorleyNoise");
|
|
1099
|
+
var SampleNoise2DTemplate = {
|
|
1100
|
+
type: "SampleNoise2D",
|
|
1101
|
+
title: "Sample Noise 2D",
|
|
1102
|
+
category: "math",
|
|
1103
|
+
description: "Sample 2D noise at coordinates / \u5728\u5750\u6807\u5904\u91C7\u6837 2D \u566A\u58F0",
|
|
1104
|
+
keywords: [
|
|
1105
|
+
"noise",
|
|
1106
|
+
"perlin",
|
|
1107
|
+
"simplex",
|
|
1108
|
+
"random",
|
|
1109
|
+
"procedural"
|
|
1110
|
+
],
|
|
1111
|
+
menuPath: [
|
|
1112
|
+
"Procedural",
|
|
1113
|
+
"Noise",
|
|
1114
|
+
"Sample Noise 2D"
|
|
1115
|
+
],
|
|
1116
|
+
isPure: true,
|
|
1117
|
+
inputs: [
|
|
1118
|
+
{
|
|
1119
|
+
name: "x",
|
|
1120
|
+
displayName: "X",
|
|
1121
|
+
type: "float"
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
name: "y",
|
|
1125
|
+
displayName: "Y",
|
|
1126
|
+
type: "float"
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
name: "seed",
|
|
1130
|
+
displayName: "Seed",
|
|
1131
|
+
type: "int"
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
name: "noiseType",
|
|
1135
|
+
displayName: "Type",
|
|
1136
|
+
type: "string"
|
|
1137
|
+
}
|
|
1138
|
+
],
|
|
1139
|
+
outputs: [
|
|
1140
|
+
{
|
|
1141
|
+
name: "value",
|
|
1142
|
+
displayName: "Value",
|
|
1143
|
+
type: "float"
|
|
1144
|
+
}
|
|
1145
|
+
],
|
|
1146
|
+
color: "#9c27b0"
|
|
1147
|
+
};
|
|
1148
|
+
var _SampleNoise2DExecutor = class _SampleNoise2DExecutor {
|
|
1149
|
+
execute(node, context) {
|
|
1150
|
+
const ctx = context;
|
|
1151
|
+
const x = ctx.evaluateInput(node.id, "x", 0);
|
|
1152
|
+
const y = ctx.evaluateInput(node.id, "y", 0);
|
|
1153
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1154
|
+
const noiseType = ctx.evaluateInput(node.id, "noiseType", "perlin");
|
|
1155
|
+
let value = 0;
|
|
1156
|
+
switch (noiseType.toLowerCase()) {
|
|
1157
|
+
case "simplex":
|
|
1158
|
+
value = getSimplexNoise(seed).noise2D(x, y);
|
|
1159
|
+
break;
|
|
1160
|
+
case "worley":
|
|
1161
|
+
value = getWorleyNoise(seed).noise2D(x, y);
|
|
1162
|
+
break;
|
|
1163
|
+
case "perlin":
|
|
1164
|
+
default:
|
|
1165
|
+
value = getPerlinNoise(seed).noise2D(x, y);
|
|
1166
|
+
break;
|
|
1167
|
+
}
|
|
1168
|
+
return {
|
|
1169
|
+
outputs: {
|
|
1170
|
+
value
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
__name(_SampleNoise2DExecutor, "SampleNoise2DExecutor");
|
|
1176
|
+
var SampleNoise2DExecutor = _SampleNoise2DExecutor;
|
|
1177
|
+
var SampleFBMTemplate = {
|
|
1178
|
+
type: "SampleFBM",
|
|
1179
|
+
title: "Sample FBM",
|
|
1180
|
+
category: "math",
|
|
1181
|
+
description: "Sample Fractal Brownian Motion noise / \u91C7\u6837\u5206\u5F62\u5E03\u6717\u8FD0\u52A8\u566A\u58F0",
|
|
1182
|
+
keywords: [
|
|
1183
|
+
"noise",
|
|
1184
|
+
"fbm",
|
|
1185
|
+
"fractal",
|
|
1186
|
+
"octave",
|
|
1187
|
+
"terrain"
|
|
1188
|
+
],
|
|
1189
|
+
menuPath: [
|
|
1190
|
+
"Procedural",
|
|
1191
|
+
"Noise",
|
|
1192
|
+
"Sample FBM"
|
|
1193
|
+
],
|
|
1194
|
+
isPure: true,
|
|
1195
|
+
inputs: [
|
|
1196
|
+
{
|
|
1197
|
+
name: "x",
|
|
1198
|
+
displayName: "X",
|
|
1199
|
+
type: "float"
|
|
1200
|
+
},
|
|
1201
|
+
{
|
|
1202
|
+
name: "y",
|
|
1203
|
+
displayName: "Y",
|
|
1204
|
+
type: "float"
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
name: "seed",
|
|
1208
|
+
displayName: "Seed",
|
|
1209
|
+
type: "int"
|
|
1210
|
+
},
|
|
1211
|
+
{
|
|
1212
|
+
name: "octaves",
|
|
1213
|
+
displayName: "Octaves",
|
|
1214
|
+
type: "int"
|
|
1215
|
+
},
|
|
1216
|
+
{
|
|
1217
|
+
name: "frequency",
|
|
1218
|
+
displayName: "Frequency",
|
|
1219
|
+
type: "float"
|
|
1220
|
+
},
|
|
1221
|
+
{
|
|
1222
|
+
name: "persistence",
|
|
1223
|
+
displayName: "Persistence",
|
|
1224
|
+
type: "float"
|
|
1225
|
+
}
|
|
1226
|
+
],
|
|
1227
|
+
outputs: [
|
|
1228
|
+
{
|
|
1229
|
+
name: "value",
|
|
1230
|
+
displayName: "Value",
|
|
1231
|
+
type: "float"
|
|
1232
|
+
}
|
|
1233
|
+
],
|
|
1234
|
+
color: "#9c27b0"
|
|
1235
|
+
};
|
|
1236
|
+
var _SampleFBMExecutor = class _SampleFBMExecutor {
|
|
1237
|
+
execute(node, context) {
|
|
1238
|
+
const ctx = context;
|
|
1239
|
+
const x = ctx.evaluateInput(node.id, "x", 0);
|
|
1240
|
+
const y = ctx.evaluateInput(node.id, "y", 0);
|
|
1241
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1242
|
+
const octaves = ctx.evaluateInput(node.id, "octaves", 6);
|
|
1243
|
+
const frequency = ctx.evaluateInput(node.id, "frequency", 1);
|
|
1244
|
+
const persistence = ctx.evaluateInput(node.id, "persistence", 0.5);
|
|
1245
|
+
const noise = getPerlinNoise(seed);
|
|
1246
|
+
const fbm = new FBM(noise, {
|
|
1247
|
+
octaves,
|
|
1248
|
+
frequency,
|
|
1249
|
+
persistence
|
|
1250
|
+
});
|
|
1251
|
+
const value = fbm.noise2D(x, y);
|
|
1252
|
+
return {
|
|
1253
|
+
outputs: {
|
|
1254
|
+
value
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
__name(_SampleFBMExecutor, "SampleFBMExecutor");
|
|
1260
|
+
var SampleFBMExecutor = _SampleFBMExecutor;
|
|
1261
|
+
var SeededRandomTemplate = {
|
|
1262
|
+
type: "SeededRandom",
|
|
1263
|
+
title: "Seeded Random",
|
|
1264
|
+
category: "math",
|
|
1265
|
+
description: "Generate deterministic random number / \u751F\u6210\u786E\u5B9A\u6027\u968F\u673A\u6570",
|
|
1266
|
+
keywords: [
|
|
1267
|
+
"random",
|
|
1268
|
+
"seed",
|
|
1269
|
+
"deterministic",
|
|
1270
|
+
"procedural"
|
|
1271
|
+
],
|
|
1272
|
+
menuPath: [
|
|
1273
|
+
"Procedural",
|
|
1274
|
+
"Random",
|
|
1275
|
+
"Seeded Random"
|
|
1276
|
+
],
|
|
1277
|
+
isPure: true,
|
|
1278
|
+
inputs: [
|
|
1279
|
+
{
|
|
1280
|
+
name: "seed",
|
|
1281
|
+
displayName: "Seed",
|
|
1282
|
+
type: "int"
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
name: "index",
|
|
1286
|
+
displayName: "Index",
|
|
1287
|
+
type: "int"
|
|
1288
|
+
}
|
|
1289
|
+
],
|
|
1290
|
+
outputs: [
|
|
1291
|
+
{
|
|
1292
|
+
name: "value",
|
|
1293
|
+
displayName: "Value",
|
|
1294
|
+
type: "float"
|
|
1295
|
+
}
|
|
1296
|
+
],
|
|
1297
|
+
color: "#9c27b0"
|
|
1298
|
+
};
|
|
1299
|
+
var _SeededRandomExecutor = class _SeededRandomExecutor {
|
|
1300
|
+
execute(node, context) {
|
|
1301
|
+
const ctx = context;
|
|
1302
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1303
|
+
const index = ctx.evaluateInput(node.id, "index", 0);
|
|
1304
|
+
const rng = new SeededRandom(seed + index * 12345);
|
|
1305
|
+
const value = rng.next();
|
|
1306
|
+
return {
|
|
1307
|
+
outputs: {
|
|
1308
|
+
value
|
|
1309
|
+
}
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
};
|
|
1313
|
+
__name(_SeededRandomExecutor, "SeededRandomExecutor");
|
|
1314
|
+
var SeededRandomExecutor = _SeededRandomExecutor;
|
|
1315
|
+
var SeededRandomIntTemplate = {
|
|
1316
|
+
type: "SeededRandomInt",
|
|
1317
|
+
title: "Seeded Random Int",
|
|
1318
|
+
category: "math",
|
|
1319
|
+
description: "Generate deterministic random integer / \u751F\u6210\u786E\u5B9A\u6027\u968F\u673A\u6574\u6570",
|
|
1320
|
+
keywords: [
|
|
1321
|
+
"random",
|
|
1322
|
+
"seed",
|
|
1323
|
+
"integer",
|
|
1324
|
+
"deterministic"
|
|
1325
|
+
],
|
|
1326
|
+
menuPath: [
|
|
1327
|
+
"Procedural",
|
|
1328
|
+
"Random",
|
|
1329
|
+
"Seeded Random Int"
|
|
1330
|
+
],
|
|
1331
|
+
isPure: true,
|
|
1332
|
+
inputs: [
|
|
1333
|
+
{
|
|
1334
|
+
name: "seed",
|
|
1335
|
+
displayName: "Seed",
|
|
1336
|
+
type: "int"
|
|
1337
|
+
},
|
|
1338
|
+
{
|
|
1339
|
+
name: "index",
|
|
1340
|
+
displayName: "Index",
|
|
1341
|
+
type: "int"
|
|
1342
|
+
},
|
|
1343
|
+
{
|
|
1344
|
+
name: "min",
|
|
1345
|
+
displayName: "Min",
|
|
1346
|
+
type: "int"
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
name: "max",
|
|
1350
|
+
displayName: "Max",
|
|
1351
|
+
type: "int"
|
|
1352
|
+
}
|
|
1353
|
+
],
|
|
1354
|
+
outputs: [
|
|
1355
|
+
{
|
|
1356
|
+
name: "value",
|
|
1357
|
+
displayName: "Value",
|
|
1358
|
+
type: "int"
|
|
1359
|
+
}
|
|
1360
|
+
],
|
|
1361
|
+
color: "#9c27b0"
|
|
1362
|
+
};
|
|
1363
|
+
var _SeededRandomIntExecutor = class _SeededRandomIntExecutor {
|
|
1364
|
+
execute(node, context) {
|
|
1365
|
+
const ctx = context;
|
|
1366
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1367
|
+
const index = ctx.evaluateInput(node.id, "index", 0);
|
|
1368
|
+
const min = ctx.evaluateInput(node.id, "min", 0);
|
|
1369
|
+
const max = ctx.evaluateInput(node.id, "max", 100);
|
|
1370
|
+
const rng = new SeededRandom(seed + index * 12345);
|
|
1371
|
+
const value = rng.nextInt(min, max);
|
|
1372
|
+
return {
|
|
1373
|
+
outputs: {
|
|
1374
|
+
value
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
__name(_SeededRandomIntExecutor, "SeededRandomIntExecutor");
|
|
1380
|
+
var SeededRandomIntExecutor = _SeededRandomIntExecutor;
|
|
1381
|
+
var WeightedPickTemplate = {
|
|
1382
|
+
type: "WeightedPick",
|
|
1383
|
+
title: "Weighted Pick",
|
|
1384
|
+
category: "math",
|
|
1385
|
+
description: "Pick from weighted options / \u4ECE\u52A0\u6743\u9009\u9879\u4E2D\u9009\u62E9",
|
|
1386
|
+
keywords: [
|
|
1387
|
+
"random",
|
|
1388
|
+
"weight",
|
|
1389
|
+
"pick",
|
|
1390
|
+
"select",
|
|
1391
|
+
"loot"
|
|
1392
|
+
],
|
|
1393
|
+
menuPath: [
|
|
1394
|
+
"Procedural",
|
|
1395
|
+
"Random",
|
|
1396
|
+
"Weighted Pick"
|
|
1397
|
+
],
|
|
1398
|
+
isPure: true,
|
|
1399
|
+
inputs: [
|
|
1400
|
+
{
|
|
1401
|
+
name: "seed",
|
|
1402
|
+
displayName: "Seed",
|
|
1403
|
+
type: "int"
|
|
1404
|
+
},
|
|
1405
|
+
{
|
|
1406
|
+
name: "index",
|
|
1407
|
+
displayName: "Index",
|
|
1408
|
+
type: "int"
|
|
1409
|
+
},
|
|
1410
|
+
{
|
|
1411
|
+
name: "items",
|
|
1412
|
+
displayName: "Items",
|
|
1413
|
+
type: "array"
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
name: "weights",
|
|
1417
|
+
displayName: "Weights",
|
|
1418
|
+
type: "array"
|
|
1419
|
+
}
|
|
1420
|
+
],
|
|
1421
|
+
outputs: [
|
|
1422
|
+
{
|
|
1423
|
+
name: "value",
|
|
1424
|
+
displayName: "Value",
|
|
1425
|
+
type: "any"
|
|
1426
|
+
},
|
|
1427
|
+
{
|
|
1428
|
+
name: "selectedIndex",
|
|
1429
|
+
displayName: "Index",
|
|
1430
|
+
type: "int"
|
|
1431
|
+
}
|
|
1432
|
+
],
|
|
1433
|
+
color: "#9c27b0"
|
|
1434
|
+
};
|
|
1435
|
+
var _WeightedPickExecutor = class _WeightedPickExecutor {
|
|
1436
|
+
execute(node, context) {
|
|
1437
|
+
const ctx = context;
|
|
1438
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1439
|
+
const index = ctx.evaluateInput(node.id, "index", 0);
|
|
1440
|
+
const items = ctx.evaluateInput(node.id, "items", []);
|
|
1441
|
+
const weights = ctx.evaluateInput(node.id, "weights", []);
|
|
1442
|
+
if (items.length === 0) {
|
|
1443
|
+
return {
|
|
1444
|
+
outputs: {
|
|
1445
|
+
value: null,
|
|
1446
|
+
selectedIndex: -1
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
const rng = new SeededRandom(seed + index * 12345);
|
|
1451
|
+
const weightedItems = items.map((item, i) => ({
|
|
1452
|
+
value: {
|
|
1453
|
+
value: item,
|
|
1454
|
+
index: i
|
|
1455
|
+
},
|
|
1456
|
+
weight: weights[i] ?? 1
|
|
1457
|
+
}));
|
|
1458
|
+
const result = weightedPick(weightedItems, rng);
|
|
1459
|
+
return {
|
|
1460
|
+
outputs: {
|
|
1461
|
+
value: result.value,
|
|
1462
|
+
selectedIndex: result.index
|
|
1463
|
+
}
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
};
|
|
1467
|
+
__name(_WeightedPickExecutor, "WeightedPickExecutor");
|
|
1468
|
+
var WeightedPickExecutor = _WeightedPickExecutor;
|
|
1469
|
+
var ShuffleArrayTemplate = {
|
|
1470
|
+
type: "ShuffleArray",
|
|
1471
|
+
title: "Shuffle Array",
|
|
1472
|
+
category: "math",
|
|
1473
|
+
description: "Shuffle array with seed / \u4F7F\u7528\u79CD\u5B50\u6D17\u724C\u6570\u7EC4",
|
|
1474
|
+
keywords: [
|
|
1475
|
+
"random",
|
|
1476
|
+
"shuffle",
|
|
1477
|
+
"array",
|
|
1478
|
+
"order"
|
|
1479
|
+
],
|
|
1480
|
+
menuPath: [
|
|
1481
|
+
"Procedural",
|
|
1482
|
+
"Random",
|
|
1483
|
+
"Shuffle Array"
|
|
1484
|
+
],
|
|
1485
|
+
isPure: true,
|
|
1486
|
+
inputs: [
|
|
1487
|
+
{
|
|
1488
|
+
name: "seed",
|
|
1489
|
+
displayName: "Seed",
|
|
1490
|
+
type: "int"
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
name: "array",
|
|
1494
|
+
displayName: "Array",
|
|
1495
|
+
type: "array"
|
|
1496
|
+
}
|
|
1497
|
+
],
|
|
1498
|
+
outputs: [
|
|
1499
|
+
{
|
|
1500
|
+
name: "result",
|
|
1501
|
+
displayName: "Result",
|
|
1502
|
+
type: "array"
|
|
1503
|
+
}
|
|
1504
|
+
],
|
|
1505
|
+
color: "#9c27b0"
|
|
1506
|
+
};
|
|
1507
|
+
var _ShuffleArrayExecutor = class _ShuffleArrayExecutor {
|
|
1508
|
+
execute(node, context) {
|
|
1509
|
+
const ctx = context;
|
|
1510
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1511
|
+
const array = ctx.evaluateInput(node.id, "array", []);
|
|
1512
|
+
const rng = new SeededRandom(seed);
|
|
1513
|
+
const result = shuffle([
|
|
1514
|
+
...array
|
|
1515
|
+
], rng);
|
|
1516
|
+
return {
|
|
1517
|
+
outputs: {
|
|
1518
|
+
result
|
|
1519
|
+
}
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
__name(_ShuffleArrayExecutor, "ShuffleArrayExecutor");
|
|
1524
|
+
var ShuffleArrayExecutor = _ShuffleArrayExecutor;
|
|
1525
|
+
var PickRandomTemplate = {
|
|
1526
|
+
type: "PickRandom",
|
|
1527
|
+
title: "Pick Random",
|
|
1528
|
+
category: "math",
|
|
1529
|
+
description: "Pick random element from array / \u4ECE\u6570\u7EC4\u4E2D\u968F\u673A\u9009\u62E9\u5143\u7D20",
|
|
1530
|
+
keywords: [
|
|
1531
|
+
"random",
|
|
1532
|
+
"pick",
|
|
1533
|
+
"array",
|
|
1534
|
+
"select"
|
|
1535
|
+
],
|
|
1536
|
+
menuPath: [
|
|
1537
|
+
"Procedural",
|
|
1538
|
+
"Random",
|
|
1539
|
+
"Pick Random"
|
|
1540
|
+
],
|
|
1541
|
+
isPure: true,
|
|
1542
|
+
inputs: [
|
|
1543
|
+
{
|
|
1544
|
+
name: "seed",
|
|
1545
|
+
displayName: "Seed",
|
|
1546
|
+
type: "int"
|
|
1547
|
+
},
|
|
1548
|
+
{
|
|
1549
|
+
name: "index",
|
|
1550
|
+
displayName: "Index",
|
|
1551
|
+
type: "int"
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
name: "array",
|
|
1555
|
+
displayName: "Array",
|
|
1556
|
+
type: "array"
|
|
1557
|
+
}
|
|
1558
|
+
],
|
|
1559
|
+
outputs: [
|
|
1560
|
+
{
|
|
1561
|
+
name: "value",
|
|
1562
|
+
displayName: "Value",
|
|
1563
|
+
type: "any"
|
|
1564
|
+
}
|
|
1565
|
+
],
|
|
1566
|
+
color: "#9c27b0"
|
|
1567
|
+
};
|
|
1568
|
+
var _PickRandomExecutor = class _PickRandomExecutor {
|
|
1569
|
+
execute(node, context) {
|
|
1570
|
+
const ctx = context;
|
|
1571
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1572
|
+
const index = ctx.evaluateInput(node.id, "index", 0);
|
|
1573
|
+
const array = ctx.evaluateInput(node.id, "array", []);
|
|
1574
|
+
if (array.length === 0) {
|
|
1575
|
+
return {
|
|
1576
|
+
outputs: {
|
|
1577
|
+
value: null
|
|
1578
|
+
}
|
|
1579
|
+
};
|
|
1580
|
+
}
|
|
1581
|
+
const rng = new SeededRandom(seed + index * 12345);
|
|
1582
|
+
const value = pickOne(array, rng);
|
|
1583
|
+
return {
|
|
1584
|
+
outputs: {
|
|
1585
|
+
value
|
|
1586
|
+
}
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
};
|
|
1590
|
+
__name(_PickRandomExecutor, "PickRandomExecutor");
|
|
1591
|
+
var PickRandomExecutor = _PickRandomExecutor;
|
|
1592
|
+
var SampleArrayTemplate = {
|
|
1593
|
+
type: "SampleArray",
|
|
1594
|
+
title: "Sample Array",
|
|
1595
|
+
category: "math",
|
|
1596
|
+
description: "Sample N unique elements from array / \u4ECE\u6570\u7EC4\u4E2D\u91C7\u6837 N \u4E2A\u4E0D\u91CD\u590D\u5143\u7D20",
|
|
1597
|
+
keywords: [
|
|
1598
|
+
"random",
|
|
1599
|
+
"sample",
|
|
1600
|
+
"array",
|
|
1601
|
+
"unique"
|
|
1602
|
+
],
|
|
1603
|
+
menuPath: [
|
|
1604
|
+
"Procedural",
|
|
1605
|
+
"Random",
|
|
1606
|
+
"Sample Array"
|
|
1607
|
+
],
|
|
1608
|
+
isPure: true,
|
|
1609
|
+
inputs: [
|
|
1610
|
+
{
|
|
1611
|
+
name: "seed",
|
|
1612
|
+
displayName: "Seed",
|
|
1613
|
+
type: "int"
|
|
1614
|
+
},
|
|
1615
|
+
{
|
|
1616
|
+
name: "array",
|
|
1617
|
+
displayName: "Array",
|
|
1618
|
+
type: "array"
|
|
1619
|
+
},
|
|
1620
|
+
{
|
|
1621
|
+
name: "count",
|
|
1622
|
+
displayName: "Count",
|
|
1623
|
+
type: "int"
|
|
1624
|
+
}
|
|
1625
|
+
],
|
|
1626
|
+
outputs: [
|
|
1627
|
+
{
|
|
1628
|
+
name: "result",
|
|
1629
|
+
displayName: "Result",
|
|
1630
|
+
type: "array"
|
|
1631
|
+
}
|
|
1632
|
+
],
|
|
1633
|
+
color: "#9c27b0"
|
|
1634
|
+
};
|
|
1635
|
+
var _SampleArrayExecutor = class _SampleArrayExecutor {
|
|
1636
|
+
execute(node, context) {
|
|
1637
|
+
const ctx = context;
|
|
1638
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1639
|
+
const array = ctx.evaluateInput(node.id, "array", []);
|
|
1640
|
+
const count = ctx.evaluateInput(node.id, "count", 1);
|
|
1641
|
+
if (array.length === 0 || count <= 0) {
|
|
1642
|
+
return {
|
|
1643
|
+
outputs: {
|
|
1644
|
+
result: []
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1648
|
+
const rng = new SeededRandom(seed);
|
|
1649
|
+
const actualCount = Math.min(count, array.length);
|
|
1650
|
+
const result = sample(array, actualCount, rng);
|
|
1651
|
+
return {
|
|
1652
|
+
outputs: {
|
|
1653
|
+
result
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
__name(_SampleArrayExecutor, "SampleArrayExecutor");
|
|
1659
|
+
var SampleArrayExecutor = _SampleArrayExecutor;
|
|
1660
|
+
var RandomPointInCircleTemplate = {
|
|
1661
|
+
type: "RandomPointInCircle",
|
|
1662
|
+
title: "Random Point In Circle",
|
|
1663
|
+
category: "math",
|
|
1664
|
+
description: "Generate random point inside circle / \u5728\u5706\u5185\u751F\u6210\u968F\u673A\u70B9",
|
|
1665
|
+
keywords: [
|
|
1666
|
+
"random",
|
|
1667
|
+
"point",
|
|
1668
|
+
"circle",
|
|
1669
|
+
"position"
|
|
1670
|
+
],
|
|
1671
|
+
menuPath: [
|
|
1672
|
+
"Procedural",
|
|
1673
|
+
"Random",
|
|
1674
|
+
"Random Point In Circle"
|
|
1675
|
+
],
|
|
1676
|
+
isPure: true,
|
|
1677
|
+
inputs: [
|
|
1678
|
+
{
|
|
1679
|
+
name: "seed",
|
|
1680
|
+
displayName: "Seed",
|
|
1681
|
+
type: "int"
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
name: "index",
|
|
1685
|
+
displayName: "Index",
|
|
1686
|
+
type: "int"
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
name: "centerX",
|
|
1690
|
+
displayName: "Center X",
|
|
1691
|
+
type: "float"
|
|
1692
|
+
},
|
|
1693
|
+
{
|
|
1694
|
+
name: "centerY",
|
|
1695
|
+
displayName: "Center Y",
|
|
1696
|
+
type: "float"
|
|
1697
|
+
},
|
|
1698
|
+
{
|
|
1699
|
+
name: "radius",
|
|
1700
|
+
displayName: "Radius",
|
|
1701
|
+
type: "float"
|
|
1702
|
+
}
|
|
1703
|
+
],
|
|
1704
|
+
outputs: [
|
|
1705
|
+
{
|
|
1706
|
+
name: "x",
|
|
1707
|
+
displayName: "X",
|
|
1708
|
+
type: "float"
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
name: "y",
|
|
1712
|
+
displayName: "Y",
|
|
1713
|
+
type: "float"
|
|
1714
|
+
}
|
|
1715
|
+
],
|
|
1716
|
+
color: "#9c27b0"
|
|
1717
|
+
};
|
|
1718
|
+
var _RandomPointInCircleExecutor = class _RandomPointInCircleExecutor {
|
|
1719
|
+
execute(node, context) {
|
|
1720
|
+
const ctx = context;
|
|
1721
|
+
const seed = ctx.evaluateInput(node.id, "seed", 0);
|
|
1722
|
+
const index = ctx.evaluateInput(node.id, "index", 0);
|
|
1723
|
+
const centerX = ctx.evaluateInput(node.id, "centerX", 0);
|
|
1724
|
+
const centerY = ctx.evaluateInput(node.id, "centerY", 0);
|
|
1725
|
+
const radius = ctx.evaluateInput(node.id, "radius", 1);
|
|
1726
|
+
const rng = new SeededRandom(seed + index * 12345);
|
|
1727
|
+
const point = rng.nextPointInCircle(radius);
|
|
1728
|
+
return {
|
|
1729
|
+
outputs: {
|
|
1730
|
+
x: centerX + point.x,
|
|
1731
|
+
y: centerY + point.y
|
|
1732
|
+
}
|
|
1733
|
+
};
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
__name(_RandomPointInCircleExecutor, "RandomPointInCircleExecutor");
|
|
1737
|
+
var RandomPointInCircleExecutor = _RandomPointInCircleExecutor;
|
|
1738
|
+
var ProcGenNodeDefinitions = {
|
|
1739
|
+
templates: [
|
|
1740
|
+
SampleNoise2DTemplate,
|
|
1741
|
+
SampleFBMTemplate,
|
|
1742
|
+
SeededRandomTemplate,
|
|
1743
|
+
SeededRandomIntTemplate,
|
|
1744
|
+
WeightedPickTemplate,
|
|
1745
|
+
ShuffleArrayTemplate,
|
|
1746
|
+
PickRandomTemplate,
|
|
1747
|
+
SampleArrayTemplate,
|
|
1748
|
+
RandomPointInCircleTemplate
|
|
1749
|
+
],
|
|
1750
|
+
executors: /* @__PURE__ */ new Map([
|
|
1751
|
+
[
|
|
1752
|
+
"SampleNoise2D",
|
|
1753
|
+
new SampleNoise2DExecutor()
|
|
1754
|
+
],
|
|
1755
|
+
[
|
|
1756
|
+
"SampleFBM",
|
|
1757
|
+
new SampleFBMExecutor()
|
|
1758
|
+
],
|
|
1759
|
+
[
|
|
1760
|
+
"SeededRandom",
|
|
1761
|
+
new SeededRandomExecutor()
|
|
1762
|
+
],
|
|
1763
|
+
[
|
|
1764
|
+
"SeededRandomInt",
|
|
1765
|
+
new SeededRandomIntExecutor()
|
|
1766
|
+
],
|
|
1767
|
+
[
|
|
1768
|
+
"WeightedPick",
|
|
1769
|
+
new WeightedPickExecutor()
|
|
1770
|
+
],
|
|
1771
|
+
[
|
|
1772
|
+
"ShuffleArray",
|
|
1773
|
+
new ShuffleArrayExecutor()
|
|
1774
|
+
],
|
|
1775
|
+
[
|
|
1776
|
+
"PickRandom",
|
|
1777
|
+
new PickRandomExecutor()
|
|
1778
|
+
],
|
|
1779
|
+
[
|
|
1780
|
+
"SampleArray",
|
|
1781
|
+
new SampleArrayExecutor()
|
|
1782
|
+
],
|
|
1783
|
+
[
|
|
1784
|
+
"RandomPointInCircle",
|
|
1785
|
+
new RandomPointInCircleExecutor()
|
|
1786
|
+
]
|
|
1787
|
+
])
|
|
1788
|
+
};
|
|
1789
|
+
|
|
1790
|
+
export { FBM, PerlinNoise, PickRandomExecutor, PickRandomTemplate, ProcGenNodeDefinitions, RandomPointInCircleExecutor, RandomPointInCircleTemplate, SampleArrayExecutor, SampleArrayTemplate, SampleFBMExecutor, SampleFBMTemplate, SampleNoise2DExecutor, SampleNoise2DTemplate, SeededRandom, SeededRandomExecutor, SeededRandomIntExecutor, SeededRandomIntTemplate, SeededRandomTemplate, ShuffleArrayExecutor, ShuffleArrayTemplate, SimplexNoise, WeightedPickExecutor, WeightedPickTemplate, WeightedRandom, WorleyNoise, createFBM, createPerlinNoise, createSeededRandom, createSimplexNoise, createWeightedRandom, createWorleyNoise, pickOne, randomIntegers, sample, sampleWithReplacement, shuffle, shuffleCopy, weightedPick, weightedPickFromMap, weightedSample };
|
|
1791
|
+
//# sourceMappingURL=index.js.map
|
|
1792
|
+
//# sourceMappingURL=index.js.map
|