@mml-io/3d-web-client-core 0.1.0 → 0.3.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 +19 -0
- package/build/camera/CameraManager.d.ts +21 -7
- package/build/character/Character.d.ts +1 -0
- package/build/character/CharacterManager.d.ts +4 -2
- package/build/character/CharacterMaterial.d.ts +1 -0
- package/build/character/LocalController.d.ts +21 -7
- package/build/character/ModelLoader.d.ts +8 -3
- package/build/character/RemoteController.d.ts +2 -4
- package/build/collisions/CollisionsManager.d.ts +10 -2
- package/build/helpers/math-helpers.d.ts +2 -0
- package/build/index.js +1311 -243
- package/build/index.js.map +4 -4
- package/build/input/KeyInputManager.d.ts +9 -2
- package/build/rendering/composer.d.ts +16 -1
- package/build/rendering/post-effects/bright-contrast-sat.d.ts +2 -0
- package/build/time/TimeManager.d.ts +2 -0
- package/build/tweakpane/TweakPane.d.ts +30 -0
- package/build/tweakpane/characterSettings.d.ts +89 -0
- package/build/tweakpane/composerSettings.d.ts +234 -0
- package/build/tweakpane/tweakPaneActivity.d.ts +2 -0
- package/package.json +6 -3
package/build/index.js
CHANGED
@@ -6,7 +6,7 @@ var __publicField = (obj, key, value) => {
|
|
6
6
|
};
|
7
7
|
|
8
8
|
// src/camera/CameraManager.ts
|
9
|
-
import { PerspectiveCamera, Vector3 as Vector32 } from "three";
|
9
|
+
import { PerspectiveCamera, Raycaster, Vector3 as Vector32 } from "three";
|
10
10
|
|
11
11
|
// src/helpers/math-helpers.ts
|
12
12
|
import { Vector3 } from "three";
|
@@ -27,25 +27,51 @@ var round = (n, digits) => {
|
|
27
27
|
var ease = (target, n, factor) => {
|
28
28
|
return round((target - n) * factor, 5);
|
29
29
|
};
|
30
|
+
function clamp(value, min, max) {
|
31
|
+
return Math.min(Math.max(value, min), max);
|
32
|
+
}
|
33
|
+
var remap = (value, minValue, maxValue, minScaledValue, maxScaledValue) => {
|
34
|
+
return minScaledValue + (maxScaledValue - minScaledValue) * (value - minValue) / (maxValue - minValue);
|
35
|
+
};
|
36
|
+
|
37
|
+
// src/tweakpane/tweakPaneActivity.ts
|
38
|
+
var isTweakpaneActive = false;
|
39
|
+
function setTweakpaneActive(status) {
|
40
|
+
isTweakpaneActive = status;
|
41
|
+
}
|
42
|
+
function getTweakpaneActive() {
|
43
|
+
return isTweakpaneActive;
|
44
|
+
}
|
30
45
|
|
31
46
|
// src/camera/CameraManager.ts
|
32
47
|
var CameraManager = class {
|
33
|
-
constructor() {
|
48
|
+
constructor(collisionsManager) {
|
49
|
+
this.collisionsManager = collisionsManager;
|
34
50
|
__publicField(this, "camera");
|
35
|
-
__publicField(this, "
|
36
|
-
__publicField(this, "
|
37
|
-
__publicField(this, "
|
38
|
-
__publicField(this, "
|
39
|
-
__publicField(this, "
|
51
|
+
__publicField(this, "initialDistance", 2.5);
|
52
|
+
__publicField(this, "minDistance", 0.1);
|
53
|
+
__publicField(this, "maxDistance", 6);
|
54
|
+
__publicField(this, "initialFOV", 80);
|
55
|
+
__publicField(this, "fov", this.initialFOV);
|
56
|
+
__publicField(this, "minFOV", 63);
|
57
|
+
__publicField(this, "maxFOV", 85);
|
58
|
+
__publicField(this, "targetFOV", this.initialFOV);
|
59
|
+
__publicField(this, "minPolarAngle", Math.PI * 0.25);
|
60
|
+
__publicField(this, "maxPolarAngle", Math.PI * 0.95);
|
61
|
+
__publicField(this, "dampingFactor", 0.091);
|
62
|
+
__publicField(this, "targetDistance", this.initialDistance);
|
63
|
+
__publicField(this, "distance", this.initialDistance);
|
40
64
|
__publicField(this, "targetPhi", Math.PI / 2);
|
41
65
|
__publicField(this, "phi", Math.PI / 2);
|
42
66
|
__publicField(this, "targetTheta", -Math.PI / 2);
|
43
67
|
__publicField(this, "theta", -Math.PI / 2);
|
68
|
+
__publicField(this, "dragging", false);
|
69
|
+
__publicField(this, "target", new Vector32(0, 1.55, 0));
|
44
70
|
__publicField(this, "hadTarget", false);
|
45
|
-
this
|
46
|
-
this.camera.
|
47
|
-
this.
|
48
|
-
this.
|
71
|
+
__publicField(this, "rayCaster");
|
72
|
+
this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
|
73
|
+
this.camera.position.set(0, 1.4, -this.initialDistance);
|
74
|
+
this.rayCaster = new Raycaster();
|
49
75
|
document.addEventListener("mousedown", this.onMouseDown.bind(this));
|
50
76
|
document.addEventListener("mouseup", this.onMouseUp.bind(this));
|
51
77
|
document.addEventListener("mousemove", this.onMouseMove.bind(this));
|
@@ -65,22 +91,21 @@ var CameraManager = class {
|
|
65
91
|
this.dragging = false;
|
66
92
|
}
|
67
93
|
onMouseMove(event) {
|
68
|
-
if (!this.dragging)
|
94
|
+
if (!this.dragging || getTweakpaneActive() === true)
|
69
95
|
return;
|
70
|
-
|
71
|
-
if (this.targetTheta === null || this.targetPhi === null) {
|
96
|
+
if (this.targetTheta === null || this.targetPhi === null)
|
72
97
|
return;
|
73
|
-
}
|
74
98
|
this.targetTheta += event.movementX * 0.01;
|
75
99
|
this.targetPhi -= event.movementY * 0.01;
|
76
|
-
this.targetPhi = Math.max(
|
77
|
-
this.targetPhi = Math.min(Math.PI * 0.7, this.targetPhi);
|
100
|
+
this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
|
78
101
|
}
|
79
102
|
onMouseWheel(event) {
|
80
|
-
const scrollAmount = event.deltaY *
|
103
|
+
const scrollAmount = event.deltaY * 1e-3;
|
81
104
|
this.targetDistance += scrollAmount;
|
82
|
-
this.targetDistance = Math.max(
|
83
|
-
|
105
|
+
this.targetDistance = Math.max(
|
106
|
+
this.minDistance,
|
107
|
+
Math.min(this.maxDistance, this.targetDistance)
|
108
|
+
);
|
84
109
|
}
|
85
110
|
setTarget(target) {
|
86
111
|
this.target.copy(target);
|
@@ -102,19 +127,41 @@ var CameraManager = class {
|
|
102
127
|
this.theta = this.targetTheta;
|
103
128
|
this.distance = this.targetDistance;
|
104
129
|
}
|
130
|
+
adjustCameraPosition() {
|
131
|
+
this.rayCaster.set(
|
132
|
+
this.camera.position,
|
133
|
+
this.target.clone().sub(this.camera.position).normalize()
|
134
|
+
);
|
135
|
+
const minimumDistance = this.collisionsManager.raycastFirstDistance(this.rayCaster.ray);
|
136
|
+
const cameraToPlayerDistance = this.camera.position.distanceTo(this.target);
|
137
|
+
if (minimumDistance !== null && minimumDistance <= cameraToPlayerDistance) {
|
138
|
+
this.targetDistance = cameraToPlayerDistance - minimumDistance;
|
139
|
+
this.distance = this.targetDistance;
|
140
|
+
}
|
141
|
+
}
|
105
142
|
update() {
|
106
|
-
if (this.target === null)
|
143
|
+
if (this.target === null)
|
107
144
|
return;
|
108
|
-
}
|
109
145
|
if (this.phi !== null && this.targetPhi !== null && this.theta !== null && this.targetTheta !== null) {
|
110
|
-
this.distance +=
|
111
|
-
this.
|
112
|
-
this.
|
113
|
-
this.theta += ease(this.targetTheta, this.theta, 0.07);
|
146
|
+
this.distance += (this.targetDistance - this.distance) * this.dampingFactor * 0.21;
|
147
|
+
this.phi += (this.targetPhi - this.phi) * this.dampingFactor;
|
148
|
+
this.theta += (this.targetTheta - this.theta) * this.dampingFactor;
|
114
149
|
const x = this.target.x + this.distance * Math.sin(this.phi) * Math.cos(this.theta);
|
115
150
|
const y = this.target.y + this.distance * Math.cos(this.phi);
|
116
151
|
const z = this.target.z + this.distance * Math.sin(this.phi) * Math.sin(this.theta);
|
117
|
-
this.
|
152
|
+
this.targetFOV = remap(
|
153
|
+
this.targetDistance,
|
154
|
+
this.minDistance,
|
155
|
+
this.maxDistance,
|
156
|
+
this.minFOV,
|
157
|
+
this.maxFOV
|
158
|
+
);
|
159
|
+
this.fov += ease(this.targetFOV, this.fov, 0.07);
|
160
|
+
this.camera.fov = this.fov;
|
161
|
+
this.camera.updateProjectionMatrix();
|
162
|
+
this.camera.updateMatrixWorld();
|
163
|
+
this.camera.position.set(x, clamp(y, 0.1, Infinity), z);
|
164
|
+
this.adjustCameraPosition();
|
118
165
|
this.camera.lookAt(this.target);
|
119
166
|
}
|
120
167
|
}
|
@@ -225,6 +272,41 @@ ${before}
|
|
225
272
|
);
|
226
273
|
}
|
227
274
|
|
275
|
+
// src/tweakpane/characterSettings.ts
|
276
|
+
var characterValues = {
|
277
|
+
material: {
|
278
|
+
transmission: 1,
|
279
|
+
metalness: 0.8,
|
280
|
+
roughness: 0.12,
|
281
|
+
ior: 1.5,
|
282
|
+
thickness: 0.1,
|
283
|
+
specularColor: { r: 1, g: 1, b: 1 },
|
284
|
+
specularIntensity: 0.1,
|
285
|
+
emissive: { r: 1, g: 1, b: 1 },
|
286
|
+
emissiveIntensity: 0.1,
|
287
|
+
envMapIntensity: 1,
|
288
|
+
sheenColor: { r: 1, g: 1, b: 1 },
|
289
|
+
sheen: 0.5,
|
290
|
+
clearcoat: 0,
|
291
|
+
clearcoatRoughness: 0
|
292
|
+
}
|
293
|
+
};
|
294
|
+
var characterOptions = {
|
295
|
+
material: {
|
296
|
+
transmission: { min: 0.01, max: 3, step: 0.01 },
|
297
|
+
metalness: { min: 0, max: 1, step: 0.01 },
|
298
|
+
roughness: { min: 0, max: 1, step: 0.01 },
|
299
|
+
ior: { min: 0, max: 5, step: 0.01 },
|
300
|
+
thickness: { min: 0, max: 1, step: 0.01 },
|
301
|
+
specularIntensity: { min: 0, max: 1, step: 0.01 },
|
302
|
+
emissiveIntensity: { min: 0, max: 1, step: 0.01 },
|
303
|
+
envMapIntensity: { min: 0, max: 1, step: 0.01 },
|
304
|
+
sheen: { min: 0, max: 1, step: 0.01 },
|
305
|
+
clearcoat: { min: 0, max: 1, step: 0.01 },
|
306
|
+
clearcoatRoughness: { min: 0, max: 1, step: 0.01 }
|
307
|
+
}
|
308
|
+
};
|
309
|
+
|
228
310
|
// src/character/CharacterMaterial.ts
|
229
311
|
var CharacterMaterial = class extends MeshPhysicalMaterial {
|
230
312
|
constructor() {
|
@@ -232,16 +314,32 @@ var CharacterMaterial = class extends MeshPhysicalMaterial {
|
|
232
314
|
__publicField(this, "uniforms", {});
|
233
315
|
__publicField(this, "colorsCube216", []);
|
234
316
|
this.color = new Color(16777215);
|
235
|
-
this.transmission =
|
236
|
-
this.metalness =
|
237
|
-
this.roughness =
|
238
|
-
this.ior =
|
239
|
-
this.thickness =
|
240
|
-
this.specularColor = new Color(
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
317
|
+
this.transmission = characterValues.material.transmission;
|
318
|
+
this.metalness = characterValues.material.metalness;
|
319
|
+
this.roughness = characterValues.material.roughness;
|
320
|
+
this.ior = characterValues.material.ior;
|
321
|
+
this.thickness = characterValues.material.thickness;
|
322
|
+
this.specularColor = new Color().setRGB(
|
323
|
+
characterValues.material.specularColor.r,
|
324
|
+
characterValues.material.specularColor.g,
|
325
|
+
characterValues.material.specularColor.b
|
326
|
+
);
|
327
|
+
this.specularIntensity = characterValues.material.specularIntensity;
|
328
|
+
this.emissive = new Color().setRGB(
|
329
|
+
characterValues.material.emissive.r,
|
330
|
+
characterValues.material.emissive.g,
|
331
|
+
characterValues.material.emissive.b
|
332
|
+
);
|
333
|
+
this.emissiveIntensity = characterValues.material.emissiveIntensity;
|
334
|
+
this.envMapIntensity = characterValues.material.envMapIntensity;
|
335
|
+
this.sheenColor = new Color().setRGB(
|
336
|
+
characterValues.material.sheenColor.r,
|
337
|
+
characterValues.material.sheenColor.g,
|
338
|
+
characterValues.material.sheenColor.b
|
339
|
+
);
|
340
|
+
this.sheen = characterValues.material.sheen;
|
341
|
+
this.clearcoat = characterValues.material.clearcoat;
|
342
|
+
this.clearcoatRoughness = characterValues.material.clearcoatRoughness;
|
245
343
|
this.onBeforeCompile = (shader) => {
|
246
344
|
this.uniforms = UniformsUtils.clone(shader.uniforms);
|
247
345
|
this.uniforms.nearClip = { value: 0.01 };
|
@@ -257,6 +355,7 @@ var CharacterMaterial = class extends MeshPhysicalMaterial {
|
|
257
355
|
shader.fragmentShader,
|
258
356
|
/* glsl */
|
259
357
|
`
|
358
|
+
//#define showPattern
|
260
359
|
varying vec2 vUv;
|
261
360
|
uniform float nearClip;
|
262
361
|
uniform float farClip;
|
@@ -265,6 +364,25 @@ var CharacterMaterial = class extends MeshPhysicalMaterial {
|
|
265
364
|
uniform float time;
|
266
365
|
uniform vec3 diffuseRandomColor;
|
267
366
|
${bayerDither}
|
367
|
+
|
368
|
+
#ifdef showPattern
|
369
|
+
vec2 rand2(vec2 p) {
|
370
|
+
return fract(vec2(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077)));
|
371
|
+
}
|
372
|
+
float voronoi(in vec2 x) {
|
373
|
+
vec2 p = floor(x);
|
374
|
+
vec2 f = fract(x);
|
375
|
+
float minDistance = 1.0;
|
376
|
+
for(int j = -1; j <= 1; j ++)
|
377
|
+
for(int i = -1; i <= 1; i ++) {
|
378
|
+
vec2 b = vec2(i, j);
|
379
|
+
vec2 rand = 0.5 + 0.5 * sin(time * 1.5 + 12.0 * rand2(p + b));
|
380
|
+
vec2 r = vec2(b) - f + rand;
|
381
|
+
minDistance = min(minDistance, length(r));
|
382
|
+
}
|
383
|
+
return minDistance;
|
384
|
+
}
|
385
|
+
#endif
|
268
386
|
`
|
269
387
|
);
|
270
388
|
shader.fragmentShader = injectBefore(
|
@@ -286,10 +404,22 @@ var CharacterMaterial = class extends MeshPhysicalMaterial {
|
|
286
404
|
d = bayerDither(bayerbr, p - ivec2(4, 4));
|
287
405
|
}
|
288
406
|
if (distance <= ditheringNear + d * ditheringRange) discard;
|
289
|
-
|
290
|
-
|
407
|
+
|
408
|
+
vec2 uv = vUv;
|
409
|
+
float s = clamp(0.35 + 0.35 * sin(5.0 * -time + vUv.y * 600.0), 0.0, 1.0);
|
291
410
|
float scanLines = pow(s, 1.33);
|
411
|
+
|
292
412
|
outgoingLight *= diffuseRandomColor;
|
413
|
+
|
414
|
+
#ifdef showPattern
|
415
|
+
float val = pow(voronoi(uv * 8.0) * 1.2, 0.5);
|
416
|
+
float thickness = 1.0 / 500.0;
|
417
|
+
vec2 g = step(mod(uv, 0.015), vec2(thickness));
|
418
|
+
float a = 1.0 - clamp(val * (g.x + g.y), 0.0, 1.0);
|
419
|
+
vec3 grid = vec3(smoothstep(0.01, 0.0, a) * 1.15) * diffuseRandomColor;
|
420
|
+
outgoingLight += grid;
|
421
|
+
#endif
|
422
|
+
|
293
423
|
outgoingLight += smoothstep(0.1, 0.0, scanLines) * 0.1;
|
294
424
|
`
|
295
425
|
);
|
@@ -297,8 +427,8 @@ var CharacterMaterial = class extends MeshPhysicalMaterial {
|
|
297
427
|
this.generateColorCube();
|
298
428
|
}
|
299
429
|
generateColorCube() {
|
300
|
-
const saturation = 0.
|
301
|
-
const lightness = 0.
|
430
|
+
const saturation = 0.4;
|
431
|
+
const lightness = 0.7;
|
302
432
|
const goldenRatioConjugate = 0.618033988749895;
|
303
433
|
let hue = 0;
|
304
434
|
for (let i = 0; i < 216; i++) {
|
@@ -308,6 +438,34 @@ var CharacterMaterial = class extends MeshPhysicalMaterial {
|
|
308
438
|
hue = (hue + goldenRatioConjugate) % 1;
|
309
439
|
}
|
310
440
|
}
|
441
|
+
update() {
|
442
|
+
this.transmission = characterValues.material.transmission;
|
443
|
+
this.metalness = characterValues.material.metalness;
|
444
|
+
this.roughness = characterValues.material.roughness;
|
445
|
+
this.ior = characterValues.material.ior;
|
446
|
+
this.thickness = characterValues.material.thickness;
|
447
|
+
this.specularColor = new Color().setRGB(
|
448
|
+
characterValues.material.specularColor.r,
|
449
|
+
characterValues.material.specularColor.g,
|
450
|
+
characterValues.material.specularColor.b
|
451
|
+
);
|
452
|
+
this.specularIntensity = characterValues.material.specularIntensity;
|
453
|
+
this.emissive = new Color().setRGB(
|
454
|
+
characterValues.material.emissive.r,
|
455
|
+
characterValues.material.emissive.g,
|
456
|
+
characterValues.material.emissive.b
|
457
|
+
);
|
458
|
+
this.emissiveIntensity = characterValues.material.emissiveIntensity;
|
459
|
+
this.envMapIntensity = characterValues.material.envMapIntensity;
|
460
|
+
this.sheenColor = new Color().setRGB(
|
461
|
+
characterValues.material.sheenColor.r,
|
462
|
+
characterValues.material.sheenColor.g,
|
463
|
+
characterValues.material.sheenColor.b
|
464
|
+
);
|
465
|
+
this.sheen = characterValues.material.sheen;
|
466
|
+
this.clearcoat = characterValues.material.clearcoat;
|
467
|
+
this.clearcoatRoughness = characterValues.material.clearcoatRoughness;
|
468
|
+
}
|
311
469
|
};
|
312
470
|
|
313
471
|
// src/character/CharacterState.ts
|
@@ -323,73 +481,130 @@ var AnimationState = /* @__PURE__ */ ((AnimationState2) => {
|
|
323
481
|
|
324
482
|
// src/character/ModelLoader.ts
|
325
483
|
import { LoadingManager } from "three";
|
326
|
-
import {
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
__publicField(this, "
|
484
|
+
import { GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
485
|
+
var CachedGLTFLoader = class extends ThreeGLTFLoader {
|
486
|
+
constructor(manager) {
|
487
|
+
super(manager);
|
488
|
+
__publicField(this, "blobCache");
|
489
|
+
this.blobCache = /* @__PURE__ */ new Map();
|
490
|
+
}
|
491
|
+
setBlobUrl(originalUrl, blobUrl) {
|
492
|
+
this.blobCache.set(originalUrl, blobUrl);
|
493
|
+
}
|
494
|
+
getBlobUrl(originalUrl) {
|
495
|
+
return this.blobCache.get(originalUrl);
|
496
|
+
}
|
497
|
+
load(url, onLoad, onProgress, onError) {
|
498
|
+
const blobUrl = this.getBlobUrl(url);
|
499
|
+
if (blobUrl) {
|
500
|
+
console.log(`Loading cached ${url.split("/").pop()}`);
|
501
|
+
super.load(blobUrl, onLoad, onProgress, onError);
|
502
|
+
} else {
|
503
|
+
super.load(url, onLoad, onProgress, onError);
|
504
|
+
}
|
505
|
+
}
|
506
|
+
};
|
507
|
+
var LRUCache = class {
|
508
|
+
constructor(maxSize = 100) {
|
509
|
+
__publicField(this, "maxSize");
|
510
|
+
__publicField(this, "cache");
|
511
|
+
this.maxSize = maxSize;
|
512
|
+
this.cache = /* @__PURE__ */ new Map();
|
513
|
+
}
|
514
|
+
get(key) {
|
515
|
+
const item = this.cache.get(key);
|
516
|
+
if (item) {
|
517
|
+
this.cache.delete(key);
|
518
|
+
this.cache.set(key, item);
|
519
|
+
}
|
520
|
+
return item;
|
521
|
+
}
|
522
|
+
set(key, value) {
|
523
|
+
if (this.cache.size >= this.maxSize) {
|
524
|
+
const oldestKey = this.cache.keys().next().value;
|
525
|
+
this.cache.delete(oldestKey);
|
526
|
+
}
|
527
|
+
this.cache.set(key, value);
|
528
|
+
}
|
529
|
+
};
|
530
|
+
var _ModelLoader = class {
|
531
|
+
constructor(maxCacheSize = 100) {
|
331
532
|
__publicField(this, "loadingManager");
|
332
|
-
__publicField(this, "fbxLoader");
|
333
533
|
__publicField(this, "gltfLoader");
|
534
|
+
__publicField(this, "modelCache");
|
535
|
+
__publicField(this, "ongoingLoads", /* @__PURE__ */ new Map());
|
334
536
|
this.loadingManager = new LoadingManager();
|
335
|
-
this.
|
336
|
-
this.
|
537
|
+
this.gltfLoader = new CachedGLTFLoader(this.loadingManager);
|
538
|
+
this.modelCache = new LRUCache(maxCacheSize);
|
337
539
|
}
|
338
|
-
|
339
|
-
|
340
|
-
if (
|
341
|
-
|
342
|
-
return;
|
540
|
+
/* TODO: decide between below lazy initialization or eager on this file's bottom export */
|
541
|
+
static getInstance() {
|
542
|
+
if (!_ModelLoader.instance) {
|
543
|
+
_ModelLoader.instance = new _ModelLoader();
|
343
544
|
}
|
344
|
-
|
345
|
-
|
346
|
-
|
545
|
+
return _ModelLoader.instance;
|
546
|
+
}
|
547
|
+
async load(fileUrl, fileType) {
|
548
|
+
const cachedModel = this.modelCache.get(fileUrl);
|
549
|
+
if (cachedModel) {
|
550
|
+
const blobURL = URL.createObjectURL(cachedModel.blob);
|
551
|
+
this.gltfLoader.setBlobUrl(fileUrl, blobURL);
|
552
|
+
return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension);
|
553
|
+
} else {
|
554
|
+
console.log(`Loading ${fileUrl} from server`);
|
555
|
+
const ongoingLoad = this.ongoingLoads.get(fileUrl);
|
556
|
+
if (ongoingLoad)
|
557
|
+
return ongoingLoad;
|
558
|
+
const loadPromise = fetch(fileUrl).then((response) => response.blob()).then((blob) => {
|
559
|
+
const originalExtension = fileUrl.split(".").pop() || "";
|
560
|
+
this.modelCache.set(fileUrl, { blob, originalExtension });
|
561
|
+
const blobURL = URL.createObjectURL(blob);
|
562
|
+
this.ongoingLoads.delete(fileUrl);
|
563
|
+
return this.loadFromUrl(blobURL, fileType, originalExtension);
|
564
|
+
});
|
565
|
+
this.ongoingLoads.set(fileUrl, loadPromise);
|
566
|
+
return loadPromise;
|
347
567
|
}
|
568
|
+
}
|
569
|
+
async loadFromUrl(url, fileType, extension) {
|
348
570
|
if (["gltf", "glb"].includes(extension)) {
|
349
571
|
return new Promise((resolve, reject) => {
|
350
572
|
this.gltfLoader.load(
|
351
|
-
|
573
|
+
url,
|
352
574
|
(object) => {
|
353
575
|
if (fileType === "model") {
|
354
576
|
resolve(object.scene);
|
355
577
|
} else if (fileType === "animation") {
|
356
578
|
resolve(object.animations[0]);
|
357
579
|
} else {
|
358
|
-
const error = `Trying to load unknown ${fileType} type of element from file ${
|
580
|
+
const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
|
359
581
|
console.error(error);
|
360
582
|
reject(error);
|
361
583
|
}
|
362
584
|
},
|
363
585
|
void 0,
|
364
586
|
(error) => {
|
365
|
-
console.error(`Error loading GL(B|TF) from ${
|
366
|
-
reject(error);
|
367
|
-
}
|
368
|
-
);
|
369
|
-
});
|
370
|
-
} else if (extension === "fbx") {
|
371
|
-
return new Promise((resolve, reject) => {
|
372
|
-
this.fbxLoader.load(
|
373
|
-
fileUrl,
|
374
|
-
(object) => {
|
375
|
-
resolve(object);
|
376
|
-
},
|
377
|
-
void 0,
|
378
|
-
(error) => {
|
379
|
-
console.error(`Error loading FBX from ${fileUrl}: ${error}`);
|
587
|
+
console.error(`Error loading GL(B|TF) from ${url}: ${error}`);
|
380
588
|
reject(error);
|
381
589
|
}
|
382
590
|
);
|
383
591
|
});
|
592
|
+
} else {
|
593
|
+
console.error(`Error: can't recognize ${url} extension: ${extension}`);
|
384
594
|
}
|
385
595
|
}
|
386
596
|
};
|
597
|
+
var ModelLoader = _ModelLoader;
|
598
|
+
__publicField(ModelLoader, "instance", null);
|
599
|
+
var MODEL_LOADER = ModelLoader.getInstance();
|
600
|
+
var ModelLoader_default = MODEL_LOADER;
|
387
601
|
|
388
602
|
// src/character/CharacterModel.ts
|
389
603
|
var CharacterModel = class {
|
390
604
|
constructor(characterDescription) {
|
391
605
|
this.characterDescription = characterDescription;
|
392
|
-
|
606
|
+
/* TODO: pick between below eager instantiation or ModelLoader.getInstance() lazy one */
|
607
|
+
__publicField(this, "modelLoader", ModelLoader_default);
|
393
608
|
__publicField(this, "mesh", null);
|
394
609
|
__publicField(this, "material", new CharacterMaterial());
|
395
610
|
__publicField(this, "animations", {});
|
@@ -410,6 +625,10 @@ var CharacterModel = class {
|
|
410
625
|
this.characterDescription.sprintAnimationFileUrl,
|
411
626
|
2 /* running */
|
412
627
|
);
|
628
|
+
await this.setAnimationFromFile(
|
629
|
+
this.characterDescription.airAnimationFileUrl,
|
630
|
+
4 /* air */
|
631
|
+
);
|
413
632
|
this.applyMaterialToAllSkinnedMeshes(this.material);
|
414
633
|
}
|
415
634
|
updateAnimation(targetAnimation, deltaTime) {
|
@@ -462,7 +681,7 @@ var CharacterModel = class {
|
|
462
681
|
if (typeof mainMesh !== "undefined") {
|
463
682
|
this.mesh = new Object3D2();
|
464
683
|
const model = mainMesh;
|
465
|
-
model.position.set(0, -0.
|
684
|
+
model.position.set(0, -0.4, 0);
|
466
685
|
this.mesh.add(model);
|
467
686
|
this.mesh.name = name;
|
468
687
|
this.mesh.scale.set(scale, scale, scale);
|
@@ -485,7 +704,7 @@ var CharacterModel = class {
|
|
485
704
|
}
|
486
705
|
});
|
487
706
|
}
|
488
|
-
transitionToAnimation(targetAnimation, transitionDuration = 0.
|
707
|
+
transitionToAnimation(targetAnimation, transitionDuration = 0.15) {
|
489
708
|
if (!this.mesh || this.currentAnimation === null)
|
490
709
|
return;
|
491
710
|
const currentAction = this.animations[this.currentAnimation];
|
@@ -506,7 +725,7 @@ var CharacterModel = class {
|
|
506
725
|
};
|
507
726
|
|
508
727
|
// src/character/LocalController.ts
|
509
|
-
import { Box3, Line3, Matrix4, Quaternion, Vector3 as Vector33 } from "three";
|
728
|
+
import { Box3, Line3, Matrix4, Quaternion, Raycaster as Raycaster2, Vector3 as Vector33 } from "three";
|
510
729
|
var LocalController = class {
|
511
730
|
constructor(model, id, collisionsManager, keyInputManager, cameraManager, timeManager) {
|
512
731
|
this.model = model;
|
@@ -520,10 +739,20 @@ var LocalController = class {
|
|
520
739
|
radius: 0.4,
|
521
740
|
segment: new Line3(new Vector33(), new Vector33(0, 1.05, 0))
|
522
741
|
});
|
742
|
+
__publicField(this, "maxWalkSpeed", 6);
|
743
|
+
__publicField(this, "maxRunSpeed", 8.5);
|
744
|
+
__publicField(this, "gravity", -42);
|
745
|
+
__publicField(this, "jumpForce", 16);
|
746
|
+
__publicField(this, "coyoteTimeThreshold", 290);
|
747
|
+
__publicField(this, "coyoteTime", false);
|
748
|
+
__publicField(this, "canJump", true);
|
523
749
|
__publicField(this, "characterOnGround", false);
|
750
|
+
__publicField(this, "characterWasOnGround", false);
|
751
|
+
__publicField(this, "characterAirborneSince", 0);
|
752
|
+
__publicField(this, "currentHeight", 0);
|
524
753
|
__publicField(this, "characterVelocity", new Vector33());
|
525
|
-
__publicField(this, "
|
526
|
-
__publicField(this, "
|
754
|
+
__publicField(this, "vectorUp", new Vector33(0, 1, 0));
|
755
|
+
__publicField(this, "vectorDown", new Vector33(0, -1, 0));
|
527
756
|
__publicField(this, "rotationOffset", 0);
|
528
757
|
__publicField(this, "azimuthalAngle", 0);
|
529
758
|
__publicField(this, "tempBox", new Box3());
|
@@ -531,16 +760,15 @@ var LocalController = class {
|
|
531
760
|
__publicField(this, "tempSegment", new Line3());
|
532
761
|
__publicField(this, "tempVector", new Vector33());
|
533
762
|
__publicField(this, "tempVector2", new Vector33());
|
534
|
-
__publicField(this, "
|
535
|
-
__publicField(this, "
|
536
|
-
__publicField(this, "
|
537
|
-
__publicField(this, "
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
__publicField(this, "runInput", false);
|
763
|
+
__publicField(this, "rayCaster", new Raycaster2());
|
764
|
+
__publicField(this, "forward");
|
765
|
+
__publicField(this, "backward");
|
766
|
+
__publicField(this, "left");
|
767
|
+
__publicField(this, "right");
|
768
|
+
__publicField(this, "run");
|
769
|
+
__publicField(this, "jump");
|
770
|
+
__publicField(this, "anyDirection");
|
771
|
+
__publicField(this, "conflictingDirections");
|
544
772
|
__publicField(this, "thirdPersonCamera", null);
|
545
773
|
__publicField(this, "speed", 0);
|
546
774
|
__publicField(this, "targetSpeed", 0);
|
@@ -550,75 +778,90 @@ var LocalController = class {
|
|
550
778
|
rotation: { quaternionY: 0, quaternionW: 0 },
|
551
779
|
state: 0 /* idle */
|
552
780
|
});
|
781
|
+
setInterval(() => this.update.bind(this), 3e3);
|
553
782
|
}
|
554
783
|
update() {
|
555
784
|
if (!this.model?.mesh || !this.model?.animationMixer)
|
556
785
|
return;
|
557
786
|
if (!this.thirdPersonCamera)
|
558
787
|
this.thirdPersonCamera = this.cameraManager.camera;
|
559
|
-
const
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
this.
|
565
|
-
this.
|
566
|
-
this.
|
567
|
-
|
788
|
+
const { forward, backward, left, right, run, jump, anyDirection, conflictingDirection } = this.keyInputManager;
|
789
|
+
this.forward = forward;
|
790
|
+
this.backward = backward;
|
791
|
+
this.left = left;
|
792
|
+
this.right = right;
|
793
|
+
this.run = run;
|
794
|
+
this.jump = jump;
|
795
|
+
this.anyDirection = anyDirection;
|
796
|
+
this.conflictingDirections = conflictingDirection;
|
797
|
+
this.targetSpeed = this.run ? this.maxRunSpeed : this.maxWalkSpeed;
|
798
|
+
this.speed += ease(this.targetSpeed, this.speed, 0.07);
|
799
|
+
this.rayCaster.set(this.model.mesh.position, this.vectorDown);
|
800
|
+
const minimumDistance = this.collisionsManager.raycastFirstDistance(this.rayCaster.ray);
|
801
|
+
if (minimumDistance !== null) {
|
802
|
+
this.currentHeight = minimumDistance;
|
803
|
+
}
|
804
|
+
if (anyDirection || !this.characterOnGround) {
|
568
805
|
const targetAnimation = this.getTargetAnimation();
|
569
806
|
this.model.updateAnimation(targetAnimation, this.timeManager.deltaTime);
|
570
807
|
} else {
|
571
808
|
this.model.updateAnimation(0 /* idle */, this.timeManager.deltaTime);
|
572
809
|
}
|
573
|
-
if (
|
810
|
+
if (this.anyDirection)
|
574
811
|
this.updateRotation();
|
575
|
-
}
|
576
812
|
for (let i = 0; i < this.collisionDetectionSteps; i++) {
|
577
813
|
this.updatePosition(this.timeManager.deltaTime / this.collisionDetectionSteps, i);
|
578
814
|
}
|
579
|
-
if (this.model.mesh.position.y < 0)
|
815
|
+
if (this.model.mesh.position.y < 0)
|
580
816
|
this.resetPosition();
|
581
|
-
}
|
582
817
|
this.updateNetworkState();
|
583
818
|
}
|
584
819
|
getTargetAnimation() {
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
const conflictingDirections = forward && backward || left && right;
|
589
|
-
if (conflictingDirections)
|
820
|
+
if (!this.model.mesh)
|
821
|
+
return 0 /* idle */;
|
822
|
+
if (this.conflictingDirections)
|
590
823
|
return 0 /* idle */;
|
591
|
-
|
824
|
+
const jumpHeight = this.characterVelocity.y > 0 ? 0.2 : 1.8;
|
825
|
+
if (this.currentHeight > jumpHeight && !this.characterOnGround) {
|
826
|
+
return 4 /* air */;
|
827
|
+
}
|
828
|
+
return this.run && this.anyDirection ? 2 /* running */ : this.anyDirection ? 1 /* walking */ : 0 /* idle */;
|
592
829
|
}
|
593
830
|
updateRotationOffset() {
|
594
|
-
|
595
|
-
if (left && right || forward && backward)
|
831
|
+
if (this.conflictingDirections)
|
596
832
|
return;
|
597
|
-
if (forward) {
|
833
|
+
if (this.forward) {
|
598
834
|
this.rotationOffset = Math.PI;
|
599
|
-
if (left)
|
835
|
+
if (this.left)
|
600
836
|
this.rotationOffset = Math.PI + Math.PI / 4;
|
601
|
-
if (right)
|
837
|
+
if (this.right)
|
602
838
|
this.rotationOffset = Math.PI - Math.PI / 4;
|
603
|
-
} else if (backward) {
|
839
|
+
} else if (this.backward) {
|
604
840
|
this.rotationOffset = Math.PI * 2;
|
605
|
-
if (left)
|
841
|
+
if (this.left)
|
606
842
|
this.rotationOffset = -Math.PI * 2 - Math.PI / 4;
|
607
|
-
if (right)
|
843
|
+
if (this.right)
|
608
844
|
this.rotationOffset = Math.PI * 2 + Math.PI / 4;
|
609
|
-
} else if (left) {
|
845
|
+
} else if (this.left) {
|
610
846
|
this.rotationOffset = Math.PI * -0.5;
|
611
|
-
} else if (right) {
|
847
|
+
} else if (this.right) {
|
612
848
|
this.rotationOffset = Math.PI * 0.5;
|
613
849
|
}
|
614
850
|
}
|
615
851
|
updateAzimuthalAngle() {
|
616
852
|
if (!this.thirdPersonCamera || !this.model?.mesh)
|
617
853
|
return;
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
854
|
+
const camToModelDistance = this.thirdPersonCamera.position.distanceTo(this.model.mesh.position);
|
855
|
+
const isCameraFirstPerson = camToModelDistance < 2;
|
856
|
+
if (isCameraFirstPerson) {
|
857
|
+
const cameraForward = new Vector33(0, 0, 1).applyQuaternion(this.thirdPersonCamera.quaternion);
|
858
|
+
this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z);
|
859
|
+
} else {
|
860
|
+
this.azimuthalAngle = Math.atan2(
|
861
|
+
this.thirdPersonCamera.position.x - this.model.mesh.position.x,
|
862
|
+
this.thirdPersonCamera.position.z - this.model.mesh.position.z
|
863
|
+
);
|
864
|
+
}
|
622
865
|
}
|
623
866
|
updateRotation() {
|
624
867
|
if (!this.thirdPersonCamera || !this.model?.mesh)
|
@@ -626,7 +869,7 @@ var LocalController = class {
|
|
626
869
|
this.updateRotationOffset();
|
627
870
|
this.updateAzimuthalAngle();
|
628
871
|
const rotationQuaternion = new Quaternion();
|
629
|
-
rotationQuaternion.setFromAxisAngle(this.
|
872
|
+
rotationQuaternion.setFromAxisAngle(this.vectorUp, this.azimuthalAngle + this.rotationOffset);
|
630
873
|
this.model.mesh.quaternion.rotateTowards(rotationQuaternion, 0.07);
|
631
874
|
}
|
632
875
|
addScaledVectorToCharacter(deltaTime) {
|
@@ -637,36 +880,43 @@ var LocalController = class {
|
|
637
880
|
updatePosition(deltaTime, _iter) {
|
638
881
|
if (!this.model?.mesh)
|
639
882
|
return;
|
640
|
-
const { forward, backward, left, right } = this.inputDirections;
|
641
|
-
this.targetSpeed = this.runInput ? 14 : 8;
|
642
|
-
this.speed += ease(this.targetSpeed, this.speed, 0.07);
|
643
883
|
if (this.characterOnGround) {
|
644
|
-
this.
|
645
|
-
|
884
|
+
if (!this.jump)
|
885
|
+
this.canJump = true;
|
886
|
+
if (this.jump && this.canJump) {
|
646
887
|
this.characterVelocity.y += this.jumpForce;
|
647
888
|
this.canJump = false;
|
648
889
|
} else {
|
649
890
|
this.characterVelocity.y = deltaTime * this.gravity;
|
650
891
|
}
|
892
|
+
} else if (this.jump && this.coyoteTime) {
|
893
|
+
console.log("coyoteJump");
|
894
|
+
this.characterVelocity.y = this.jumpForce;
|
895
|
+
this.canJump = false;
|
651
896
|
} else {
|
652
897
|
this.characterVelocity.y += deltaTime * this.gravity;
|
653
898
|
this.canJump = false;
|
654
899
|
}
|
655
900
|
this.model.mesh.position.addScaledVector(this.characterVelocity, deltaTime);
|
656
|
-
|
657
|
-
|
658
|
-
this.
|
901
|
+
this.tempVector.set(0, 0, 0);
|
902
|
+
if (this.forward) {
|
903
|
+
const forward = new Vector33(0, 0, -1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
904
|
+
this.tempVector.add(forward);
|
659
905
|
}
|
660
|
-
if (backward) {
|
661
|
-
|
662
|
-
this.
|
906
|
+
if (this.backward) {
|
907
|
+
const backward = new Vector33(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
908
|
+
this.tempVector.add(backward);
|
663
909
|
}
|
664
|
-
if (left) {
|
665
|
-
|
666
|
-
this.
|
910
|
+
if (this.left) {
|
911
|
+
const left = new Vector33(-1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
912
|
+
this.tempVector.add(left);
|
913
|
+
}
|
914
|
+
if (this.right) {
|
915
|
+
const right = new Vector33(1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
|
916
|
+
this.tempVector.add(right);
|
667
917
|
}
|
668
|
-
if (
|
669
|
-
this.tempVector.
|
918
|
+
if (this.tempVector.length() > 0) {
|
919
|
+
this.tempVector.normalize();
|
670
920
|
this.addScaledVectorToCharacter(deltaTime);
|
671
921
|
}
|
672
922
|
this.model.mesh.updateMatrixWorld();
|
@@ -687,6 +937,11 @@ var LocalController = class {
|
|
687
937
|
deltaVector.normalize().multiplyScalar(offset);
|
688
938
|
this.model.mesh.position.add(deltaVector);
|
689
939
|
this.characterOnGround = deltaVector.y > Math.abs(deltaTime * this.characterVelocity.y * 0.25);
|
940
|
+
if (this.characterWasOnGround && !this.characterOnGround) {
|
941
|
+
this.characterAirborneSince = Date.now();
|
942
|
+
}
|
943
|
+
this.coyoteTime = this.characterVelocity.y < 0 && this.characterOnGround === false && Date.now() - this.characterAirborneSince < this.coyoteTimeThreshold;
|
944
|
+
this.characterWasOnGround = this.characterOnGround;
|
690
945
|
if (this.characterOnGround) {
|
691
946
|
this.characterVelocity.set(0, 0, 0);
|
692
947
|
} else {
|
@@ -714,7 +969,7 @@ var LocalController = class {
|
|
714
969
|
if (!this.model?.mesh)
|
715
970
|
return;
|
716
971
|
this.characterVelocity.y = 0;
|
717
|
-
this.model.mesh.position.y =
|
972
|
+
this.model.mesh.position.y = 3;
|
718
973
|
this.characterOnGround = false;
|
719
974
|
}
|
720
975
|
};
|
@@ -760,6 +1015,7 @@ var Character = class {
|
|
760
1015
|
if (typeof this.model.material.uniforms.time !== "undefined") {
|
761
1016
|
this.model.material.uniforms.time.value = time;
|
762
1017
|
this.model.material.uniforms.diffuseRandomColor.value = this.color;
|
1018
|
+
this.model.material.update();
|
763
1019
|
}
|
764
1020
|
}
|
765
1021
|
};
|
@@ -770,24 +1026,19 @@ import { Group, Vector3 as Vector36 } from "three";
|
|
770
1026
|
// src/character/RemoteController.ts
|
771
1027
|
import {
|
772
1028
|
AnimationMixer as AnimationMixer2,
|
773
|
-
LoadingManager as LoadingManager2,
|
774
1029
|
Object3D as Object3D3,
|
775
1030
|
Quaternion as Quaternion2,
|
776
1031
|
Vector3 as Vector35
|
777
1032
|
} from "three";
|
778
|
-
import { FBXLoader as FBXLoader2 } from "three/examples/jsm/loaders/FBXLoader.js";
|
779
|
-
import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
|
780
1033
|
var RemoteController = class {
|
781
1034
|
constructor(character, id) {
|
782
1035
|
this.character = character;
|
783
1036
|
this.id = id;
|
1037
|
+
__publicField(this, "modelLoader", ModelLoader_default);
|
784
1038
|
__publicField(this, "characterModel", null);
|
785
|
-
__publicField(this, "loadManager", new LoadingManager2());
|
786
1039
|
__publicField(this, "animationMixer", new AnimationMixer2(new Object3D3()));
|
787
1040
|
__publicField(this, "animations", /* @__PURE__ */ new Map());
|
788
1041
|
__publicField(this, "currentAnimation", 0 /* idle */);
|
789
|
-
__publicField(this, "fbxLoader", new FBXLoader2(this.loadManager));
|
790
|
-
__publicField(this, "gltfLoader", new GLTFLoader2(this.loadManager));
|
791
1042
|
__publicField(this, "networkState", {
|
792
1043
|
id: 0,
|
793
1044
|
position: { x: 0, y: 0, z: 0 },
|
@@ -795,6 +1046,7 @@ var RemoteController = class {
|
|
795
1046
|
state: this.currentAnimation
|
796
1047
|
});
|
797
1048
|
this.characterModel = this.character.model.mesh;
|
1049
|
+
this.characterModel.updateMatrixWorld();
|
798
1050
|
this.animationMixer = new AnimationMixer2(this.characterModel);
|
799
1051
|
}
|
800
1052
|
update(clientUpdate, time, deltaTime) {
|
@@ -804,44 +1056,15 @@ var RemoteController = class {
|
|
804
1056
|
this.updateFromNetwork(clientUpdate);
|
805
1057
|
this.animationMixer.update(deltaTime);
|
806
1058
|
}
|
807
|
-
setAnimationFromFile(animationType, fileName) {
|
808
|
-
const
|
809
|
-
const
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
}
|
814
|
-
if (["gltf", "glb"].includes(extension)) {
|
815
|
-
this.gltfLoader.load(
|
816
|
-
animationFile,
|
817
|
-
(anim) => {
|
818
|
-
const animation = anim.animations[0];
|
819
|
-
const animationAction = this.animationMixer.clipAction(animation);
|
820
|
-
this.animations.set(animationType, animationAction);
|
821
|
-
if (animationType === 0 /* idle */) {
|
822
|
-
animationAction.play();
|
823
|
-
}
|
824
|
-
},
|
825
|
-
void 0,
|
826
|
-
(error) => console.error(`Error loading ${animationFile}: ${error}`)
|
827
|
-
);
|
828
|
-
} else if (["fbx"].includes(extension)) {
|
829
|
-
this.fbxLoader.load(
|
830
|
-
animationFile,
|
831
|
-
(anim) => {
|
832
|
-
const animation = anim.animations[0];
|
833
|
-
const animationAction = this.animationMixer.clipAction(animation);
|
834
|
-
this.animations.set(animationType, animationAction);
|
835
|
-
if (animationType === 0 /* idle */) {
|
836
|
-
animationAction.play();
|
837
|
-
}
|
838
|
-
},
|
839
|
-
void 0,
|
840
|
-
(error) => console.error(`Error loading ${animationFile}: ${error}`)
|
841
|
-
);
|
1059
|
+
async setAnimationFromFile(animationType, fileName) {
|
1060
|
+
const animation = await this.modelLoader.load(fileName, "animation");
|
1061
|
+
const animationAction = this.animationMixer.clipAction(animation);
|
1062
|
+
this.animations.set(animationType, animationAction);
|
1063
|
+
if (animationType === 0 /* idle */) {
|
1064
|
+
animationAction.play();
|
842
1065
|
}
|
843
1066
|
}
|
844
|
-
transitionToAnimation(targetAnimation, transitionDuration = 0.
|
1067
|
+
transitionToAnimation(targetAnimation, transitionDuration = 0.15) {
|
845
1068
|
if (this.currentAnimation === targetAnimation)
|
846
1069
|
return;
|
847
1070
|
const currentAction = this.animations.get(this.currentAnimation);
|
@@ -861,9 +1084,9 @@ var RemoteController = class {
|
|
861
1084
|
if (!this.characterModel)
|
862
1085
|
return;
|
863
1086
|
const { position, rotation, state } = clientUpdate;
|
864
|
-
this.characterModel.position.lerp(new Vector35(position.x, position.y, position.z), 0.
|
1087
|
+
this.characterModel.position.lerp(new Vector35(position.x, position.y, position.z), 0.15);
|
865
1088
|
const rotationQuaternion = new Quaternion2(0, rotation.quaternionY, 0, rotation.quaternionW);
|
866
|
-
this.characterModel.quaternion.slerp(rotationQuaternion, 0.
|
1089
|
+
this.characterModel.quaternion.slerp(rotationQuaternion, 0.6);
|
867
1090
|
if (state !== this.currentAnimation) {
|
868
1091
|
this.transitionToAnimation(state);
|
869
1092
|
}
|
@@ -905,10 +1128,19 @@ var CharacterManager = class {
|
|
905
1128
|
__publicField(this, "remoteCharacterControllers", /* @__PURE__ */ new Map());
|
906
1129
|
__publicField(this, "characterDescription", null);
|
907
1130
|
__publicField(this, "character", null);
|
1131
|
+
__publicField(this, "cameraOffsetTarget", 0);
|
1132
|
+
__publicField(this, "cameraOffset", 0);
|
908
1133
|
__publicField(this, "group");
|
909
1134
|
this.group = new Group();
|
910
|
-
|
911
|
-
|
1135
|
+
setInterval(() => this.update.bind(this), 3e3);
|
1136
|
+
}
|
1137
|
+
/* TODO:
|
1138
|
+
1) Separate this method into spawnLocalCharacter and spawnRemoteCharacter
|
1139
|
+
2) Make this synchronous to avoid having loadingCharacters and instead manage
|
1140
|
+
the mesh loading async (would allow us to show a nameplate where a remote
|
1141
|
+
user is before the asset loads).
|
1142
|
+
*/
|
1143
|
+
spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector36()) {
|
912
1144
|
this.characterDescription = characterDescription;
|
913
1145
|
const characterLoadingPromise = new Promise((resolve) => {
|
914
1146
|
const character = new Character(
|
@@ -923,15 +1155,26 @@ var CharacterManager = class {
|
|
923
1155
|
this.cameraManager.camera
|
924
1156
|
);
|
925
1157
|
} else {
|
926
|
-
|
1158
|
+
spawnPosition = getSpawnPositionInsideCircle(3, 30, id, 0.4);
|
927
1159
|
character.model.mesh.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
1160
|
+
character.model.mesh.updateMatrixWorld();
|
1161
|
+
this.sendUpdate({
|
1162
|
+
id,
|
1163
|
+
position: {
|
1164
|
+
x: spawnPosition.x,
|
1165
|
+
y: spawnPosition.y,
|
1166
|
+
z: spawnPosition.z
|
1167
|
+
},
|
1168
|
+
rotation: { quaternionY: 0, quaternionW: 0 },
|
1169
|
+
state: 0 /* idle */
|
1170
|
+
});
|
1171
|
+
}
|
1172
|
+
character.model.hideMaterialByMeshName("SK_Mannequin_2");
|
1173
|
+
if (!isLocal) {
|
1174
|
+
character.model?.mesh?.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
1175
|
+
character.model?.mesh?.updateMatrixWorld();
|
1176
|
+
character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
|
933
1177
|
}
|
934
|
-
character.model.hideMaterialByMeshName("SK_UE5Mannequin_1");
|
935
1178
|
this.group.add(character.model.mesh);
|
936
1179
|
if (isLocal) {
|
937
1180
|
this.character = character;
|
@@ -950,6 +1193,15 @@ var CharacterManager = class {
|
|
950
1193
|
2 /* running */,
|
951
1194
|
characterDescription.sprintAnimationFileUrl
|
952
1195
|
);
|
1196
|
+
remoteController.setAnimationFromFile(
|
1197
|
+
4 /* air */,
|
1198
|
+
characterDescription.airAnimationFileUrl
|
1199
|
+
);
|
1200
|
+
remoteController.characterModel?.position.set(
|
1201
|
+
spawnPosition.x,
|
1202
|
+
spawnPosition.y,
|
1203
|
+
spawnPosition.z
|
1204
|
+
);
|
953
1205
|
this.remoteCharacterControllers.set(id, remoteController);
|
954
1206
|
}
|
955
1207
|
resolve(character);
|
@@ -990,7 +1242,13 @@ var CharacterManager = class {
|
|
990
1242
|
update() {
|
991
1243
|
if (this.character) {
|
992
1244
|
this.character.update(this.timeManager.time);
|
993
|
-
|
1245
|
+
if (this.character.model?.mesh) {
|
1246
|
+
this.cameraOffsetTarget = this.cameraManager.targetDistance <= 0.4 ? 0.6 : 0;
|
1247
|
+
this.cameraOffset += ease(this.cameraOffsetTarget, this.cameraOffset, 0.1);
|
1248
|
+
const targetOffset = new Vector36(0, 1.3, this.cameraOffset);
|
1249
|
+
targetOffset.applyQuaternion(this.character.model.mesh.quaternion);
|
1250
|
+
this.cameraManager.setTarget(this.character.position.add(targetOffset));
|
1251
|
+
}
|
994
1252
|
if (this.character.controller) {
|
995
1253
|
this.character.controller.update();
|
996
1254
|
if (this.timeManager.frame % 2 === 0) {
|
@@ -998,8 +1256,14 @@ var CharacterManager = class {
|
|
998
1256
|
}
|
999
1257
|
}
|
1000
1258
|
for (const [id, update] of this.clientStates) {
|
1259
|
+
const { position } = update;
|
1001
1260
|
if (!this.remoteCharacters.has(id) && !this.loadingCharacters.has(id)) {
|
1002
|
-
this.spawnCharacter(
|
1261
|
+
this.spawnCharacter(
|
1262
|
+
this.characterDescription,
|
1263
|
+
id,
|
1264
|
+
false,
|
1265
|
+
new Vector36(position.x, position.y, position.z)
|
1266
|
+
).then((_character) => {
|
1003
1267
|
this.loadingCharacters.delete(id);
|
1004
1268
|
});
|
1005
1269
|
}
|
@@ -1031,6 +1295,10 @@ var KeyInputManager = class {
|
|
1031
1295
|
__publicField(this, "keys", /* @__PURE__ */ new Map());
|
1032
1296
|
document.addEventListener("keydown", this.onKeyDown.bind(this));
|
1033
1297
|
document.addEventListener("keyup", this.onKeyUp.bind(this));
|
1298
|
+
window.addEventListener("blur", this.handleUnfocus.bind(this));
|
1299
|
+
}
|
1300
|
+
handleUnfocus(_event) {
|
1301
|
+
this.keys.clear();
|
1034
1302
|
}
|
1035
1303
|
onKeyDown(event) {
|
1036
1304
|
this.keys.set(event.key.toLowerCase(), true);
|
@@ -1044,15 +1312,34 @@ var KeyInputManager = class {
|
|
1044
1312
|
isMovementKeyPressed() {
|
1045
1313
|
return ["w", "a", "s", "d"].some((key) => this.isKeyPressed(key));
|
1046
1314
|
}
|
1047
|
-
|
1315
|
+
get forward() {
|
1316
|
+
return this.isKeyPressed("w");
|
1317
|
+
}
|
1318
|
+
get backward() {
|
1319
|
+
return this.isKeyPressed("s");
|
1320
|
+
}
|
1321
|
+
get left() {
|
1322
|
+
return this.isKeyPressed("a");
|
1323
|
+
}
|
1324
|
+
get right() {
|
1325
|
+
return this.isKeyPressed("d");
|
1326
|
+
}
|
1327
|
+
get run() {
|
1048
1328
|
return this.isKeyPressed("shift");
|
1049
1329
|
}
|
1050
|
-
|
1330
|
+
get jump() {
|
1051
1331
|
return this.isKeyPressed(" ");
|
1052
1332
|
}
|
1333
|
+
get anyDirection() {
|
1334
|
+
return this.isMovementKeyPressed();
|
1335
|
+
}
|
1336
|
+
get conflictingDirection() {
|
1337
|
+
return this.isKeyPressed("w") && this.isKeyPressed("s") || this.isKeyPressed("a") && this.isKeyPressed("d");
|
1338
|
+
}
|
1053
1339
|
dispose() {
|
1054
1340
|
document.removeEventListener("keydown", this.onKeyDown.bind(this));
|
1055
1341
|
document.removeEventListener("keyup", this.onKeyDown.bind(this));
|
1342
|
+
window.removeEventListener("blur", this.handleUnfocus.bind(this));
|
1056
1343
|
}
|
1057
1344
|
};
|
1058
1345
|
|
@@ -1128,22 +1415,606 @@ var MMLCompositionScene = class {
|
|
1128
1415
|
|
1129
1416
|
// src/rendering/composer.ts
|
1130
1417
|
import {
|
1131
|
-
EffectComposer,
|
1418
|
+
EffectComposer as EffectComposer2,
|
1132
1419
|
RenderPass,
|
1133
|
-
EffectPass,
|
1420
|
+
EffectPass as EffectPass2,
|
1134
1421
|
FXAAEffect,
|
1135
1422
|
ShaderPass,
|
1136
|
-
BloomEffect
|
1423
|
+
BloomEffect as BloomEffect2,
|
1424
|
+
SSAOEffect as SSAOEffect2,
|
1425
|
+
BlendFunction as BlendFunction3,
|
1426
|
+
TextureEffect,
|
1427
|
+
ToneMappingEffect as ToneMappingEffect2,
|
1428
|
+
SMAAEffect,
|
1429
|
+
SMAAPreset,
|
1430
|
+
EdgeDetectionMode,
|
1431
|
+
PredicationMode,
|
1432
|
+
NormalPass
|
1137
1433
|
} from "postprocessing";
|
1138
1434
|
import {
|
1139
|
-
|
1140
|
-
|
1435
|
+
Color as Color4,
|
1436
|
+
HalfFloatType,
|
1437
|
+
LinearSRGBColorSpace,
|
1438
|
+
LoadingManager as LoadingManager2,
|
1439
|
+
PMREMGenerator,
|
1141
1440
|
Vector2 as Vector22,
|
1142
|
-
WebGLRenderer as
|
1441
|
+
WebGLRenderer as WebGLRenderer3
|
1143
1442
|
} from "three";
|
1443
|
+
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
|
1144
1444
|
|
1145
|
-
// src/
|
1146
|
-
import {
|
1445
|
+
// src/tweakpane/composerSettings.ts
|
1446
|
+
import { BlendFunction } from "postprocessing";
|
1447
|
+
var composerValues = {
|
1448
|
+
renderer: {
|
1449
|
+
shadowMap: 2,
|
1450
|
+
toneMapping: 4,
|
1451
|
+
exposure: 1,
|
1452
|
+
bgIntensity: 0.6,
|
1453
|
+
bgBlurriness: 0
|
1454
|
+
},
|
1455
|
+
ssao: {
|
1456
|
+
blendFunction: BlendFunction.MULTIPLY,
|
1457
|
+
distanceScaling: true,
|
1458
|
+
depthAwareUpsampling: true,
|
1459
|
+
samples: 17,
|
1460
|
+
rings: 7,
|
1461
|
+
luminanceInfluence: 0.7,
|
1462
|
+
radius: 0.03,
|
1463
|
+
intensity: 2.5,
|
1464
|
+
bias: 0.05,
|
1465
|
+
fade: 0.03,
|
1466
|
+
resolutionScale: 0.75,
|
1467
|
+
color: { r: 0, g: 0, b: 0 },
|
1468
|
+
worldDistanceThreshold: 30,
|
1469
|
+
worldDistanceFalloff: 7,
|
1470
|
+
worldProximityThreshold: 0.5,
|
1471
|
+
worldProximityFalloff: 0.3
|
1472
|
+
},
|
1473
|
+
toneMapping: {
|
1474
|
+
mode: 2,
|
1475
|
+
resolution: 512,
|
1476
|
+
whitePoint: 32,
|
1477
|
+
middleGrey: 21,
|
1478
|
+
minLuminance: 0.01,
|
1479
|
+
averageLuminance: 0.01,
|
1480
|
+
adaptationRate: 2
|
1481
|
+
},
|
1482
|
+
brightness: -0.03,
|
1483
|
+
contrast: 1.3,
|
1484
|
+
saturation: 0.95,
|
1485
|
+
grain: 0.055,
|
1486
|
+
bloom: 0.4
|
1487
|
+
};
|
1488
|
+
var composerOptions = {
|
1489
|
+
renderer: {
|
1490
|
+
shadowMap: { min: 0, max: 2, step: 1 },
|
1491
|
+
toneMapping: { min: 0, max: 5, step: 1 },
|
1492
|
+
exposure: { min: 0, max: 3, step: 0.01 },
|
1493
|
+
bgIntensity: { min: 0, max: 1, step: 0.01 },
|
1494
|
+
bgBlurriness: { min: 0, max: 0.1, step: 1e-3 }
|
1495
|
+
},
|
1496
|
+
ssao: {
|
1497
|
+
samples: { min: 1, max: 50, step: 1 },
|
1498
|
+
rings: { min: 1, max: 50, step: 1 },
|
1499
|
+
luminanceInfluence: { min: 0, max: 1, step: 0.01 },
|
1500
|
+
radius: { min: 0, max: 0.1, step: 1e-3 },
|
1501
|
+
intensity: { min: 0, max: 5, step: 0.1 },
|
1502
|
+
bias: { min: 0, max: 0.1, step: 1e-3 },
|
1503
|
+
fade: { min: 0, max: 0.1, step: 1e-3 },
|
1504
|
+
resolutionScale: { min: 0.25, max: 2, step: 0.25 },
|
1505
|
+
worldDistanceThreshold: { min: 0, max: 200, step: 1 },
|
1506
|
+
worldDistanceFalloff: { min: 0, max: 200, step: 1 },
|
1507
|
+
worldProximityThreshold: { min: 0, max: 2, step: 0.01 },
|
1508
|
+
worldProximityFalloff: { min: 0, max: 2, step: 0.01 }
|
1509
|
+
},
|
1510
|
+
toneMapping: {
|
1511
|
+
mode: { min: 0, max: 4, step: 1 },
|
1512
|
+
resolution: { min: 64, max: 512, step: 64 },
|
1513
|
+
whitePoint: { min: 0, max: 32, step: 0.01 },
|
1514
|
+
middleGrey: { min: 0, max: 32, step: 0.01 },
|
1515
|
+
minLuminance: { min: 0, max: 32, step: 1e-3 },
|
1516
|
+
averageLuminance: { min: 1e-3, max: 0.2, step: 1e-3 },
|
1517
|
+
adaptationRate: { min: 0.1, max: 2, step: 0.1 }
|
1518
|
+
},
|
1519
|
+
brightness: {
|
1520
|
+
amount: { min: -1, max: 1, step: 0.01 }
|
1521
|
+
},
|
1522
|
+
contrast: {
|
1523
|
+
amount: { min: 0, max: 2, step: 0.01 }
|
1524
|
+
},
|
1525
|
+
saturation: {
|
1526
|
+
amount: { min: 0, max: 2, step: 0.01 }
|
1527
|
+
},
|
1528
|
+
grain: {
|
1529
|
+
amount: { min: 0, max: 0.2, step: 2e-3 }
|
1530
|
+
},
|
1531
|
+
bloom: {
|
1532
|
+
amount: { min: 0, max: 4, step: 0.1 }
|
1533
|
+
}
|
1534
|
+
};
|
1535
|
+
var shadowMapTypes = {
|
1536
|
+
0: "BasicShadowMap",
|
1537
|
+
1: "PCFShadowMap",
|
1538
|
+
2: "PCFSoftShadowMap"
|
1539
|
+
};
|
1540
|
+
var rendererToneMappingTypes = {
|
1541
|
+
0: "NoToneMapping",
|
1542
|
+
1: "LinearToneMapping",
|
1543
|
+
2: "ReinhardToneMapping",
|
1544
|
+
3: "CineonToneMapping",
|
1545
|
+
4: "ACESFilmicToneMapping",
|
1546
|
+
5: "CustomToneMapping"
|
1547
|
+
};
|
1548
|
+
var customToneMappingTypes = {
|
1549
|
+
0: "REINHARD",
|
1550
|
+
1: "REINHARD2",
|
1551
|
+
2: "REINHARD2_ADAPTIVE",
|
1552
|
+
3: "OPTIMIZED_CINEON",
|
1553
|
+
4: "ACES_FILMIC"
|
1554
|
+
};
|
1555
|
+
var rendererBlades = {
|
1556
|
+
shadowMapType: shadowMapTypes[composerValues.renderer.shadowMap],
|
1557
|
+
toneMappingType: rendererToneMappingTypes[composerValues.renderer.toneMapping]
|
1558
|
+
};
|
1559
|
+
var setShadowMapType = (value) => {
|
1560
|
+
rendererBlades.shadowMapType = shadowMapTypes[value];
|
1561
|
+
};
|
1562
|
+
var setToneMappingType = (value) => {
|
1563
|
+
rendererBlades.toneMappingType = rendererToneMappingTypes[value];
|
1564
|
+
};
|
1565
|
+
var customToneMappingBlade = {
|
1566
|
+
customToneMappingType: customToneMappingTypes[composerValues.toneMapping.mode]
|
1567
|
+
};
|
1568
|
+
var setCustomToneMappingType = (value) => {
|
1569
|
+
customToneMappingBlade.customToneMappingType = customToneMappingTypes[value];
|
1570
|
+
};
|
1571
|
+
var ssaoMaterialParams = [
|
1572
|
+
"fade",
|
1573
|
+
"bias",
|
1574
|
+
"minRadiusScale",
|
1575
|
+
"worldDistanceThreshold",
|
1576
|
+
"worldDistanceFalloff",
|
1577
|
+
"worldProximityThreshold",
|
1578
|
+
"worldProximityFalloff"
|
1579
|
+
];
|
1580
|
+
var statsData = {
|
1581
|
+
triangles: "0",
|
1582
|
+
geometries: "0",
|
1583
|
+
textures: "0",
|
1584
|
+
shaders: "0",
|
1585
|
+
postPasses: "0",
|
1586
|
+
drawCalls: "0",
|
1587
|
+
rawDeltaTime: "0",
|
1588
|
+
deltaTime: "0",
|
1589
|
+
FPS: "0"
|
1590
|
+
};
|
1591
|
+
|
1592
|
+
// src/tweakpane/TweakPane.ts
|
1593
|
+
import {
|
1594
|
+
BlendFunction as BlendFunction2
|
1595
|
+
} from "postprocessing";
|
1596
|
+
import { Color as Color3 } from "three";
|
1597
|
+
import { Pane } from "tweakpane";
|
1598
|
+
var TweakPane = class {
|
1599
|
+
constructor(renderer, scene, composer) {
|
1600
|
+
__publicField(this, "renderer");
|
1601
|
+
__publicField(this, "scene");
|
1602
|
+
__publicField(this, "composer");
|
1603
|
+
__publicField(this, "gui", new Pane());
|
1604
|
+
__publicField(this, "render");
|
1605
|
+
__publicField(this, "stats");
|
1606
|
+
__publicField(this, "renderOptions");
|
1607
|
+
__publicField(this, "ssao");
|
1608
|
+
__publicField(this, "toneMapping");
|
1609
|
+
__publicField(this, "post");
|
1610
|
+
__publicField(this, "export");
|
1611
|
+
__publicField(this, "characterMaterial");
|
1612
|
+
__publicField(this, "saveVisibilityInLocalStorage", true);
|
1613
|
+
__publicField(this, "guiVisible", false);
|
1614
|
+
if (this.saveVisibilityInLocalStorage) {
|
1615
|
+
const localStorageGuiVisible = localStorage.getItem("guiVisible");
|
1616
|
+
if (localStorageGuiVisible !== null) {
|
1617
|
+
if (localStorageGuiVisible === "true") {
|
1618
|
+
this.guiVisible = true;
|
1619
|
+
} else if (localStorageGuiVisible === "false") {
|
1620
|
+
this.guiVisible = false;
|
1621
|
+
}
|
1622
|
+
}
|
1623
|
+
}
|
1624
|
+
this.renderer = renderer;
|
1625
|
+
this.scene = scene;
|
1626
|
+
this.composer = composer;
|
1627
|
+
this.render = this.gui.addFolder({ title: "rendering", expanded: true });
|
1628
|
+
this.stats = this.render.addFolder({ title: "stats", expanded: true });
|
1629
|
+
this.renderOptions = this.render.addFolder({ title: "renderOptions", expanded: false });
|
1630
|
+
this.toneMapping = this.render.addFolder({ title: "customToneMapping", expanded: false });
|
1631
|
+
this.ssao = this.render.addFolder({ title: "ambientOcclusion", expanded: false });
|
1632
|
+
this.post = this.render.addFolder({ title: "post", expanded: false });
|
1633
|
+
this.toneMapping.hidden = composerValues.renderer.toneMapping === 5 ? false : true;
|
1634
|
+
this.characterMaterial = this.gui.addFolder({ title: "characterMaterial", expanded: false });
|
1635
|
+
this.characterMaterial.addInput(
|
1636
|
+
characterValues.material,
|
1637
|
+
"transmission",
|
1638
|
+
characterOptions.material.transmission
|
1639
|
+
);
|
1640
|
+
this.characterMaterial.addInput(
|
1641
|
+
characterValues.material,
|
1642
|
+
"metalness",
|
1643
|
+
characterOptions.material.metalness
|
1644
|
+
);
|
1645
|
+
this.characterMaterial.addInput(
|
1646
|
+
characterValues.material,
|
1647
|
+
"roughness",
|
1648
|
+
characterOptions.material.roughness
|
1649
|
+
);
|
1650
|
+
this.characterMaterial.addInput(characterValues.material, "ior", characterOptions.material.ior);
|
1651
|
+
this.characterMaterial.addInput(
|
1652
|
+
characterValues.material,
|
1653
|
+
"thickness",
|
1654
|
+
characterOptions.material.thickness
|
1655
|
+
);
|
1656
|
+
this.characterMaterial.addInput(characterValues.material, "specularColor", {
|
1657
|
+
color: { type: "float" }
|
1658
|
+
});
|
1659
|
+
this.characterMaterial.addInput(
|
1660
|
+
characterValues.material,
|
1661
|
+
"specularIntensity",
|
1662
|
+
characterOptions.material.specularIntensity
|
1663
|
+
);
|
1664
|
+
this.characterMaterial.addInput(characterValues.material, "emissive", {
|
1665
|
+
color: { type: "float" }
|
1666
|
+
});
|
1667
|
+
this.characterMaterial.addInput(
|
1668
|
+
characterValues.material,
|
1669
|
+
"emissiveIntensity",
|
1670
|
+
characterOptions.material.emissiveIntensity
|
1671
|
+
);
|
1672
|
+
this.characterMaterial.addInput(
|
1673
|
+
characterValues.material,
|
1674
|
+
"envMapIntensity",
|
1675
|
+
characterOptions.material.envMapIntensity
|
1676
|
+
);
|
1677
|
+
this.characterMaterial.addInput(characterValues.material, "sheenColor", {
|
1678
|
+
color: { type: "float" }
|
1679
|
+
});
|
1680
|
+
this.characterMaterial.addInput(
|
1681
|
+
characterValues.material,
|
1682
|
+
"sheen",
|
1683
|
+
characterOptions.material.sheen
|
1684
|
+
);
|
1685
|
+
this.characterMaterial.addInput(
|
1686
|
+
characterValues.material,
|
1687
|
+
"clearcoat",
|
1688
|
+
characterOptions.material.clearcoat
|
1689
|
+
);
|
1690
|
+
this.characterMaterial.addInput(
|
1691
|
+
characterValues.material,
|
1692
|
+
"clearcoatRoughness",
|
1693
|
+
characterOptions.material.clearcoatRoughness
|
1694
|
+
);
|
1695
|
+
this.characterMaterial.on("change", (e) => {
|
1696
|
+
if (!e.presetKey) {
|
1697
|
+
return;
|
1698
|
+
}
|
1699
|
+
if (e.presetKey === "specularColor") {
|
1700
|
+
characterValues.material.specularColor = {
|
1701
|
+
r: e.value.r,
|
1702
|
+
g: e.value.g,
|
1703
|
+
b: e.value.b
|
1704
|
+
};
|
1705
|
+
return;
|
1706
|
+
}
|
1707
|
+
if (e.presetKey === "emissive") {
|
1708
|
+
characterValues.material.emissive = {
|
1709
|
+
r: e.value.r,
|
1710
|
+
g: e.value.g,
|
1711
|
+
b: e.value.b
|
1712
|
+
};
|
1713
|
+
return;
|
1714
|
+
}
|
1715
|
+
if (e.presetKey === "sheenColor") {
|
1716
|
+
characterValues.material.sheenColor = {
|
1717
|
+
r: e.value.r,
|
1718
|
+
g: e.value.g,
|
1719
|
+
b: e.value.b
|
1720
|
+
};
|
1721
|
+
return;
|
1722
|
+
}
|
1723
|
+
});
|
1724
|
+
this.export = this.gui.addFolder({ title: "import/export", expanded: false });
|
1725
|
+
window.addEventListener("keydown", this.processKey.bind(this));
|
1726
|
+
this.setupGUIListeners.bind(this)();
|
1727
|
+
this.setupRenderPane = this.setupRenderPane.bind(this);
|
1728
|
+
}
|
1729
|
+
processKey(e) {
|
1730
|
+
if (e.key === "p")
|
1731
|
+
this.toggleGUI();
|
1732
|
+
}
|
1733
|
+
setupGUIListeners() {
|
1734
|
+
const gui = this.gui;
|
1735
|
+
const paneElement = gui.containerElem_;
|
1736
|
+
paneElement.style.display = this.guiVisible ? "unset" : "none";
|
1737
|
+
this.gui.element.addEventListener("mousedown", () => setTweakpaneActive(true));
|
1738
|
+
this.gui.element.addEventListener("mouseup", () => setTweakpaneActive(false));
|
1739
|
+
this.gui.element.addEventListener("mouseleave", () => setTweakpaneActive(false));
|
1740
|
+
}
|
1741
|
+
setupRenderPane(ssaoEffect, toneMappingEffect, toneMappingPass, brightnessContrastSaturation, bloomEffect, gaussGrainEffect) {
|
1742
|
+
this.stats.addMonitor(statsData, "triangles");
|
1743
|
+
this.stats.addMonitor(statsData, "geometries");
|
1744
|
+
this.stats.addMonitor(statsData, "textures");
|
1745
|
+
this.stats.addMonitor(statsData, "shaders");
|
1746
|
+
this.stats.addMonitor(statsData, "postPasses");
|
1747
|
+
this.stats.addMonitor(statsData, "drawCalls");
|
1748
|
+
this.stats.addMonitor(statsData, "rawDeltaTime");
|
1749
|
+
this.stats.addMonitor(statsData, "deltaTime");
|
1750
|
+
this.stats.addMonitor(statsData, "FPS");
|
1751
|
+
this.renderOptions.addInput(
|
1752
|
+
composerValues.renderer,
|
1753
|
+
"shadowMap",
|
1754
|
+
composerOptions.renderer.shadowMap
|
1755
|
+
);
|
1756
|
+
this.renderOptions.addMonitor(rendererBlades, "shadowMapType");
|
1757
|
+
this.renderOptions.addInput(
|
1758
|
+
composerValues.renderer,
|
1759
|
+
"toneMapping",
|
1760
|
+
composerOptions.renderer.toneMapping
|
1761
|
+
);
|
1762
|
+
this.renderOptions.addMonitor(rendererBlades, "toneMappingType");
|
1763
|
+
this.renderOptions.addInput(
|
1764
|
+
composerValues.renderer,
|
1765
|
+
"exposure",
|
1766
|
+
composerOptions.renderer.exposure
|
1767
|
+
);
|
1768
|
+
this.renderOptions.addInput(
|
1769
|
+
composerValues.renderer,
|
1770
|
+
"bgIntensity",
|
1771
|
+
composerOptions.renderer.bgIntensity
|
1772
|
+
);
|
1773
|
+
this.renderOptions.addInput(
|
1774
|
+
composerValues.renderer,
|
1775
|
+
"bgBlurriness",
|
1776
|
+
composerOptions.renderer.bgBlurriness
|
1777
|
+
);
|
1778
|
+
this.renderOptions.on("change", (e) => {
|
1779
|
+
const target = e.target;
|
1780
|
+
switch (target.label) {
|
1781
|
+
case "shadowMap":
|
1782
|
+
this.renderer.shadowMap.type = e.value;
|
1783
|
+
setShadowMapType(e.value);
|
1784
|
+
break;
|
1785
|
+
case "toneMapping":
|
1786
|
+
this.renderer.toneMapping = e.value;
|
1787
|
+
if (e.value !== 5 && e.value !== 0) {
|
1788
|
+
this.toneMapping.hidden = true;
|
1789
|
+
} else {
|
1790
|
+
this.toneMapping.hidden = false;
|
1791
|
+
}
|
1792
|
+
toneMappingPass.enabled = e.value === 5 || e.value === 0 ? true : false;
|
1793
|
+
setToneMappingType(e.value);
|
1794
|
+
break;
|
1795
|
+
case "exposure":
|
1796
|
+
this.renderer.toneMappingExposure = e.value;
|
1797
|
+
break;
|
1798
|
+
case "bgIntensity":
|
1799
|
+
this.scene.backgroundIntensity = e.value;
|
1800
|
+
break;
|
1801
|
+
case "bgBlurriness":
|
1802
|
+
this.scene.backgroundBlurriness = e.value;
|
1803
|
+
break;
|
1804
|
+
default:
|
1805
|
+
break;
|
1806
|
+
}
|
1807
|
+
});
|
1808
|
+
this.ssao.addInput({ showEffectOnly: false }, "showEffectOnly");
|
1809
|
+
this.ssao.addInput(composerValues.ssao, "samples", composerOptions.ssao.samples);
|
1810
|
+
this.ssao.addInput(composerValues.ssao, "rings", composerOptions.ssao.rings);
|
1811
|
+
this.ssao.addInput(
|
1812
|
+
composerValues.ssao,
|
1813
|
+
"luminanceInfluence",
|
1814
|
+
composerOptions.ssao.luminanceInfluence
|
1815
|
+
);
|
1816
|
+
this.ssao.addInput(composerValues.ssao, "radius", composerOptions.ssao.radius);
|
1817
|
+
this.ssao.addInput(composerValues.ssao, "intensity", composerOptions.ssao.intensity);
|
1818
|
+
this.ssao.addInput(composerValues.ssao, "bias", composerOptions.ssao.bias);
|
1819
|
+
this.ssao.addInput(composerValues.ssao, "fade", composerOptions.ssao.fade);
|
1820
|
+
this.ssao.addInput(
|
1821
|
+
composerValues.ssao,
|
1822
|
+
"resolutionScale",
|
1823
|
+
composerOptions.ssao.resolutionScale
|
1824
|
+
);
|
1825
|
+
this.ssao.addInput(
|
1826
|
+
composerValues.ssao,
|
1827
|
+
"worldDistanceThreshold",
|
1828
|
+
composerOptions.ssao.worldDistanceThreshold
|
1829
|
+
);
|
1830
|
+
this.ssao.addInput(
|
1831
|
+
composerValues.ssao,
|
1832
|
+
"worldDistanceFalloff",
|
1833
|
+
composerOptions.ssao.worldDistanceFalloff
|
1834
|
+
);
|
1835
|
+
this.ssao.addInput(
|
1836
|
+
composerValues.ssao,
|
1837
|
+
"worldProximityThreshold",
|
1838
|
+
composerOptions.ssao.worldProximityThreshold
|
1839
|
+
);
|
1840
|
+
this.ssao.addInput(
|
1841
|
+
composerValues.ssao,
|
1842
|
+
"worldProximityFalloff",
|
1843
|
+
composerOptions.ssao.worldProximityFalloff
|
1844
|
+
);
|
1845
|
+
this.ssao.addInput(composerValues.ssao, "color", {
|
1846
|
+
color: { alpha: false, type: "float" }
|
1847
|
+
});
|
1848
|
+
this.ssao.on("change", (e) => {
|
1849
|
+
if (!e.presetKey) {
|
1850
|
+
return;
|
1851
|
+
}
|
1852
|
+
const preset = e.presetKey;
|
1853
|
+
if (preset === "showEffectOnly") {
|
1854
|
+
ssaoEffect.blendMode.blendFunction = e.value === true ? BlendFunction2.NORMAL : BlendFunction2.MULTIPLY;
|
1855
|
+
return;
|
1856
|
+
}
|
1857
|
+
if (preset === "resolutionScale") {
|
1858
|
+
ssaoEffect.resolution.scale = e.value;
|
1859
|
+
return;
|
1860
|
+
}
|
1861
|
+
if (ssaoMaterialParams.includes(e.presetKey)) {
|
1862
|
+
ssaoEffect.ssaoMaterial[preset] = e.value;
|
1863
|
+
return;
|
1864
|
+
}
|
1865
|
+
if (e.presetKey === "color") {
|
1866
|
+
ssaoEffect.color = new Color3().setRGB(e.value.r, e.value.g, e.value.b);
|
1867
|
+
return;
|
1868
|
+
}
|
1869
|
+
ssaoEffect[preset] = e.value;
|
1870
|
+
});
|
1871
|
+
this.toneMapping.addInput(composerValues.toneMapping, "mode", composerOptions.toneMapping.mode);
|
1872
|
+
this.toneMapping.addMonitor(customToneMappingBlade, "customToneMappingType");
|
1873
|
+
this.toneMapping.addInput(
|
1874
|
+
composerValues.toneMapping,
|
1875
|
+
"whitePoint",
|
1876
|
+
composerOptions.toneMapping.whitePoint
|
1877
|
+
);
|
1878
|
+
this.toneMapping.addInput(
|
1879
|
+
composerValues.toneMapping,
|
1880
|
+
"middleGrey",
|
1881
|
+
composerOptions.toneMapping.middleGrey
|
1882
|
+
);
|
1883
|
+
const minLuminance = this.toneMapping.addInput(
|
1884
|
+
composerValues.toneMapping,
|
1885
|
+
"minLuminance",
|
1886
|
+
composerOptions.toneMapping.minLuminance
|
1887
|
+
);
|
1888
|
+
minLuminance.hidden = composerValues.toneMapping.mode === 2 ? true : false;
|
1889
|
+
const averageLuminance = this.toneMapping.addInput(
|
1890
|
+
composerValues.toneMapping,
|
1891
|
+
"averageLuminance",
|
1892
|
+
composerOptions.toneMapping.averageLuminance
|
1893
|
+
);
|
1894
|
+
averageLuminance.hidden = composerValues.toneMapping.mode === 2 ? true : false;
|
1895
|
+
this.toneMapping.addInput(
|
1896
|
+
composerValues.toneMapping,
|
1897
|
+
"adaptationRate",
|
1898
|
+
composerOptions.toneMapping.adaptationRate
|
1899
|
+
);
|
1900
|
+
this.toneMapping.on("change", (e) => {
|
1901
|
+
if (!e.presetKey) {
|
1902
|
+
return;
|
1903
|
+
}
|
1904
|
+
const preset = e.presetKey;
|
1905
|
+
if (preset === "mode") {
|
1906
|
+
minLuminance.hidden = composerValues.toneMapping.mode === 2 ? true : false;
|
1907
|
+
averageLuminance.hidden = composerValues.toneMapping.mode === 2 ? true : false;
|
1908
|
+
setCustomToneMappingType(e.value);
|
1909
|
+
}
|
1910
|
+
toneMappingEffect[preset] = e.value;
|
1911
|
+
return;
|
1912
|
+
});
|
1913
|
+
this.post.addInput(composerValues, "brightness", composerOptions.brightness.amount);
|
1914
|
+
this.post.addInput(composerValues, "contrast", composerOptions.contrast.amount);
|
1915
|
+
this.post.addInput(composerValues, "saturation", composerOptions.saturation.amount);
|
1916
|
+
this.post.addInput(composerValues, "bloom", composerOptions.bloom.amount);
|
1917
|
+
this.post.addInput(composerValues, "grain", composerOptions.grain.amount);
|
1918
|
+
this.post.on("change", (e) => {
|
1919
|
+
const target = e.presetKey;
|
1920
|
+
switch (target) {
|
1921
|
+
case "brightness":
|
1922
|
+
brightnessContrastSaturation.uniforms.brightness.value = e.value;
|
1923
|
+
break;
|
1924
|
+
case "contrast":
|
1925
|
+
brightnessContrastSaturation.uniforms.contrast.value = e.value;
|
1926
|
+
break;
|
1927
|
+
case "saturation":
|
1928
|
+
brightnessContrastSaturation.uniforms.saturation.value = e.value;
|
1929
|
+
break;
|
1930
|
+
case "bloom":
|
1931
|
+
bloomEffect.intensity = e.value;
|
1932
|
+
break;
|
1933
|
+
case "grain":
|
1934
|
+
gaussGrainEffect.uniforms.amount.value = e.value;
|
1935
|
+
break;
|
1936
|
+
default:
|
1937
|
+
break;
|
1938
|
+
}
|
1939
|
+
});
|
1940
|
+
const exportButton = this.export.addButton({ title: "export" });
|
1941
|
+
exportButton.on("click", () => {
|
1942
|
+
this.downloadSettingsAsJSON(this.gui.exportPreset());
|
1943
|
+
});
|
1944
|
+
const importButton = this.export.addButton({ title: "import" });
|
1945
|
+
importButton.on("click", () => {
|
1946
|
+
this.importSettingsFromJSON((settings) => {
|
1947
|
+
this.gui.importPreset(settings);
|
1948
|
+
});
|
1949
|
+
});
|
1950
|
+
}
|
1951
|
+
formatDateForFilename() {
|
1952
|
+
const date = /* @__PURE__ */ new Date();
|
1953
|
+
const year = date.getFullYear();
|
1954
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
1955
|
+
const day = String(date.getDate()).padStart(2, "0");
|
1956
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
1957
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
1958
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
1959
|
+
return `${year}-${month}-${day} ${hours}-${minutes}-${seconds}`;
|
1960
|
+
}
|
1961
|
+
downloadSettingsAsJSON(settings) {
|
1962
|
+
const jsonString = JSON.stringify(settings, null, 2);
|
1963
|
+
const blob = new Blob([jsonString], { type: "application/json" });
|
1964
|
+
const url = URL.createObjectURL(blob);
|
1965
|
+
const a = document.createElement("a");
|
1966
|
+
a.download = `settings ${this.formatDateForFilename()}.json`;
|
1967
|
+
a.href = url;
|
1968
|
+
a.click();
|
1969
|
+
URL.revokeObjectURL(url);
|
1970
|
+
}
|
1971
|
+
importSettingsFromJSON(callback) {
|
1972
|
+
const input = document.createElement("input");
|
1973
|
+
input.type = "file";
|
1974
|
+
input.accept = ".json";
|
1975
|
+
input.addEventListener("change", (event) => {
|
1976
|
+
const file = event.target.files?.[0];
|
1977
|
+
if (file) {
|
1978
|
+
const reader = new FileReader();
|
1979
|
+
reader.onload = (loadEvent) => {
|
1980
|
+
try {
|
1981
|
+
const settings = JSON.parse(loadEvent.target?.result);
|
1982
|
+
callback(settings);
|
1983
|
+
} catch (err) {
|
1984
|
+
console.error("Error parsing JSON:", err);
|
1985
|
+
}
|
1986
|
+
};
|
1987
|
+
reader.readAsText(file);
|
1988
|
+
}
|
1989
|
+
});
|
1990
|
+
input.click();
|
1991
|
+
}
|
1992
|
+
updateStats(timeManager) {
|
1993
|
+
const { geometries, textures } = this.renderer.info.memory;
|
1994
|
+
const { triangles, calls } = this.renderer.info.render;
|
1995
|
+
statsData.triangles = triangles.toString();
|
1996
|
+
statsData.geometries = geometries.toString();
|
1997
|
+
statsData.textures = textures.toString();
|
1998
|
+
statsData.shaders = this.renderer.info.programs.length.toString();
|
1999
|
+
statsData.postPasses = this.composer.passes.length.toString();
|
2000
|
+
statsData.drawCalls = calls.toString();
|
2001
|
+
statsData.rawDeltaTime = (Math.round(timeManager.rawDeltaTime * 1e5) / 1e5).toString();
|
2002
|
+
statsData.deltaTime = (Math.round(timeManager.deltaTime * 1e5) / 1e5).toString();
|
2003
|
+
statsData.FPS = timeManager.fps.toString();
|
2004
|
+
}
|
2005
|
+
toggleGUI() {
|
2006
|
+
const gui = this.gui;
|
2007
|
+
const paneElement = gui.containerElem_;
|
2008
|
+
paneElement.style.display = this.guiVisible ? "none" : "unset";
|
2009
|
+
this.guiVisible = !this.guiVisible;
|
2010
|
+
if (this.saveVisibilityInLocalStorage) {
|
2011
|
+
localStorage.setItem("guiVisible", this.guiVisible === true ? "true" : "false");
|
2012
|
+
}
|
2013
|
+
}
|
2014
|
+
};
|
2015
|
+
|
2016
|
+
// src/rendering/post-effects/bright-contrast-sat.ts
|
2017
|
+
import { ShaderMaterial, Uniform } from "three";
|
1147
2018
|
|
1148
2019
|
// src/rendering/shaders/vertex-shader.ts
|
1149
2020
|
var vertexShader = (
|
@@ -1159,14 +2030,86 @@ var vertexShader = (
|
|
1159
2030
|
`
|
1160
2031
|
);
|
1161
2032
|
|
1162
|
-
// src/rendering/post-effects/
|
1163
|
-
var
|
2033
|
+
// src/rendering/post-effects/bright-contrast-sat.ts
|
2034
|
+
var BrightnessContrastSaturation = new ShaderMaterial({
|
1164
2035
|
uniforms: {
|
1165
2036
|
tDiffuse: new Uniform(null),
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
2037
|
+
brightness: new Uniform(0),
|
2038
|
+
contrast: new Uniform(1),
|
2039
|
+
saturation: new Uniform(1)
|
2040
|
+
},
|
2041
|
+
vertexShader,
|
2042
|
+
fragmentShader: (
|
2043
|
+
/* glsl */
|
2044
|
+
`
|
2045
|
+
precision highp float;
|
2046
|
+
in vec2 vUv;
|
2047
|
+
|
2048
|
+
uniform sampler2D tDiffuse;
|
2049
|
+
uniform float brightness;
|
2050
|
+
uniform float contrast;
|
2051
|
+
uniform float saturation;
|
2052
|
+
|
2053
|
+
mat4 brightnessMatrix(float brightness) {
|
2054
|
+
return mat4(
|
2055
|
+
1, 0, 0, 0,
|
2056
|
+
0, 1, 0, 0,
|
2057
|
+
0, 0, 1, 0,
|
2058
|
+
brightness, brightness, brightness, 1
|
2059
|
+
);
|
2060
|
+
}
|
2061
|
+
|
2062
|
+
mat4 contrastMatrix(float contrast) {
|
2063
|
+
float t = (1.0 - contrast) / 2.0;
|
2064
|
+
|
2065
|
+
return mat4(
|
2066
|
+
contrast, 0, 0, 0,
|
2067
|
+
0, contrast, 0, 0,
|
2068
|
+
0, 0, contrast, 0,
|
2069
|
+
t, t, t, 1
|
2070
|
+
);
|
2071
|
+
}
|
2072
|
+
|
2073
|
+
mat4 saturationMatrix(float saturation) {
|
2074
|
+
vec3 luminance = vec3(0.3086, 0.6094, 0.0820);
|
2075
|
+
float oneMinusSat = 1.0 - saturation;
|
2076
|
+
vec3 red = vec3(luminance.x * oneMinusSat);
|
2077
|
+
red += vec3(saturation, 0, 0);
|
2078
|
+
vec3 green = vec3(luminance.y * oneMinusSat);
|
2079
|
+
green += vec3(0, saturation, 0);
|
2080
|
+
vec3 blue = vec3(luminance.z * oneMinusSat);
|
2081
|
+
blue += vec3(0, 0, saturation);
|
2082
|
+
return mat4(
|
2083
|
+
red, 0,
|
2084
|
+
green, 0,
|
2085
|
+
blue, 0,
|
2086
|
+
0, 0, 0, 1
|
2087
|
+
);
|
2088
|
+
}
|
2089
|
+
|
2090
|
+
void main(void) {
|
2091
|
+
vec4 color = texture(tDiffuse, vUv);
|
2092
|
+
gl_FragColor = (
|
2093
|
+
brightnessMatrix(brightness) *
|
2094
|
+
contrastMatrix(contrast) *
|
2095
|
+
saturationMatrix(saturation) *
|
2096
|
+
color
|
2097
|
+
);
|
2098
|
+
}
|
2099
|
+
`
|
2100
|
+
),
|
2101
|
+
dithering: true
|
2102
|
+
});
|
2103
|
+
|
2104
|
+
// src/rendering/post-effects/gauss-grain.ts
|
2105
|
+
import { ShaderMaterial as ShaderMaterial2, Uniform as Uniform2, Vector2 } from "three";
|
2106
|
+
var GaussGrainEffect = new ShaderMaterial2({
|
2107
|
+
uniforms: {
|
2108
|
+
tDiffuse: new Uniform2(null),
|
2109
|
+
resolution: new Uniform2(new Vector2()),
|
2110
|
+
time: new Uniform2(0),
|
2111
|
+
amount: new Uniform2(0),
|
2112
|
+
alpha: new Uniform2(0)
|
1170
2113
|
},
|
1171
2114
|
vertexShader,
|
1172
2115
|
fragmentShader: (
|
@@ -1193,7 +2136,7 @@ var GaussGrainEffect = new ShaderMaterial({
|
|
1193
2136
|
}
|
1194
2137
|
|
1195
2138
|
vec3 gaussgrain() {
|
1196
|
-
vec2 ps = vec2(1.
|
2139
|
+
vec2 ps = vec2(1.0) / resolution.xy;
|
1197
2140
|
vec2 uv = gl_FragCoord.xy * ps;
|
1198
2141
|
float t = time;
|
1199
2142
|
float seed = dot(uv, vec2(12.9898, 78.233));
|
@@ -1210,7 +2153,8 @@ var GaussGrainEffect = new ShaderMaterial({
|
|
1210
2153
|
gl_FragColor = vec4(clamp(col, 0.0, 1.0), alpha);
|
1211
2154
|
}
|
1212
2155
|
`
|
1213
|
-
)
|
2156
|
+
),
|
2157
|
+
dithering: true
|
1214
2158
|
});
|
1215
2159
|
|
1216
2160
|
// src/rendering/composer.ts
|
@@ -1219,6 +2163,7 @@ var Composer = class {
|
|
1219
2163
|
__publicField(this, "width", window.innerWidth);
|
1220
2164
|
__publicField(this, "height", window.innerHeight);
|
1221
2165
|
__publicField(this, "resolution", new Vector22(this.width, this.height));
|
2166
|
+
__publicField(this, "isEnvHDRI", false);
|
1222
2167
|
__publicField(this, "scene");
|
1223
2168
|
__publicField(this, "camera");
|
1224
2169
|
__publicField(this, "renderer");
|
@@ -1228,57 +2173,165 @@ var Composer = class {
|
|
1228
2173
|
__publicField(this, "fxaaPass");
|
1229
2174
|
__publicField(this, "bloomEffect");
|
1230
2175
|
__publicField(this, "bloomPass");
|
2176
|
+
__publicField(this, "toneMappingEffect");
|
2177
|
+
__publicField(this, "smaaEffect");
|
2178
|
+
__publicField(this, "normalPass");
|
2179
|
+
__publicField(this, "normalTextureEffect");
|
2180
|
+
__publicField(this, "ssaoEffect");
|
2181
|
+
__publicField(this, "ssaoPass");
|
2182
|
+
__publicField(this, "toneMappingPass");
|
2183
|
+
__publicField(this, "smaaPass");
|
2184
|
+
__publicField(this, "bcs", BrightnessContrastSaturation);
|
2185
|
+
__publicField(this, "bcsPass");
|
1231
2186
|
__publicField(this, "gaussGrainEffect", GaussGrainEffect);
|
1232
2187
|
__publicField(this, "gaussGrainPass");
|
2188
|
+
__publicField(this, "tweakPane");
|
1233
2189
|
this.scene = scene;
|
1234
2190
|
this.camera = camera;
|
1235
|
-
this.renderer = new
|
2191
|
+
this.renderer = new WebGLRenderer3({
|
1236
2192
|
powerPreference: "high-performance",
|
1237
2193
|
antialias: false,
|
1238
2194
|
stencil: false,
|
1239
2195
|
depth: false
|
1240
2196
|
});
|
2197
|
+
this.renderer.info.autoReset = false;
|
1241
2198
|
this.renderer.setSize(this.width, this.height);
|
1242
2199
|
this.renderer.shadowMap.enabled = true;
|
1243
|
-
this.renderer.shadowMap.type =
|
1244
|
-
this.renderer.toneMapping =
|
1245
|
-
this.renderer.toneMappingExposure =
|
2200
|
+
this.renderer.shadowMap.type = composerValues.renderer.shadowMap;
|
2201
|
+
this.renderer.toneMapping = composerValues.renderer.toneMapping;
|
2202
|
+
this.renderer.toneMappingExposure = composerValues.renderer.exposure;
|
1246
2203
|
document.body.appendChild(this.renderer.domElement);
|
1247
|
-
this.composer = new
|
2204
|
+
this.composer = new EffectComposer2(this.renderer, {
|
2205
|
+
frameBufferType: HalfFloatType
|
2206
|
+
});
|
2207
|
+
this.tweakPane = new TweakPane(this.renderer, this.scene, this.composer);
|
1248
2208
|
this.renderPass = new RenderPass(this.scene, this.camera);
|
2209
|
+
this.normalPass = new NormalPass(this.scene, this.camera);
|
2210
|
+
this.normalTextureEffect = new TextureEffect({
|
2211
|
+
blendFunction: BlendFunction3.SKIP,
|
2212
|
+
texture: this.normalPass.texture
|
2213
|
+
});
|
1249
2214
|
this.fxaaEffect = new FXAAEffect();
|
1250
|
-
this.
|
1251
|
-
|
1252
|
-
|
2215
|
+
this.bloomEffect = new BloomEffect2({
|
2216
|
+
intensity: composerValues.bloom
|
2217
|
+
});
|
2218
|
+
this.ssaoEffect = new SSAOEffect2(this.camera, this.normalPass.texture, {
|
2219
|
+
blendFunction: composerValues.ssao.blendFunction,
|
2220
|
+
distanceScaling: composerValues.ssao.distanceScaling,
|
2221
|
+
depthAwareUpsampling: composerValues.ssao.depthAwareUpsampling,
|
2222
|
+
samples: composerValues.ssao.samples,
|
2223
|
+
rings: composerValues.ssao.rings,
|
2224
|
+
luminanceInfluence: composerValues.ssao.luminanceInfluence,
|
2225
|
+
radius: composerValues.ssao.radius,
|
2226
|
+
intensity: composerValues.ssao.intensity,
|
2227
|
+
bias: composerValues.ssao.bias,
|
2228
|
+
fade: composerValues.ssao.fade,
|
2229
|
+
resolutionScale: composerValues.ssao.resolutionScale,
|
2230
|
+
color: new Color4().setRGB(composerValues.ssao.color.r, composerValues.ssao.color.g, composerValues.ssao.color.b),
|
2231
|
+
worldDistanceThreshold: composerValues.ssao.worldDistanceThreshold,
|
2232
|
+
worldDistanceFalloff: composerValues.ssao.worldDistanceFalloff,
|
2233
|
+
worldProximityThreshold: composerValues.ssao.worldProximityThreshold,
|
2234
|
+
worldProximityFalloff: composerValues.ssao.worldProximityFalloff
|
2235
|
+
});
|
2236
|
+
this.fxaaPass = new EffectPass2(this.camera, this.fxaaEffect);
|
2237
|
+
this.bloomPass = new EffectPass2(this.camera, this.bloomEffect);
|
2238
|
+
this.ssaoPass = new EffectPass2(this.camera, this.ssaoEffect, this.normalTextureEffect);
|
2239
|
+
this.toneMappingEffect = new ToneMappingEffect2({
|
2240
|
+
mode: composerValues.toneMapping.mode,
|
2241
|
+
resolution: composerValues.toneMapping.resolution,
|
2242
|
+
whitePoint: composerValues.toneMapping.whitePoint,
|
2243
|
+
middleGrey: composerValues.toneMapping.middleGrey,
|
2244
|
+
minLuminance: composerValues.toneMapping.minLuminance,
|
2245
|
+
averageLuminance: composerValues.toneMapping.averageLuminance,
|
2246
|
+
adaptationRate: composerValues.toneMapping.adaptationRate
|
2247
|
+
});
|
2248
|
+
this.smaaEffect = new SMAAEffect({
|
2249
|
+
preset: SMAAPreset.ULTRA,
|
2250
|
+
edgeDetectionMode: EdgeDetectionMode.COLOR,
|
2251
|
+
predicationMode: PredicationMode.DEPTH
|
2252
|
+
});
|
2253
|
+
this.toneMappingPass = new EffectPass2(this.camera, this.toneMappingEffect);
|
2254
|
+
this.toneMappingPass.enabled = composerValues.renderer.toneMapping === 5 || composerValues.renderer.toneMapping === 0 ? true : false;
|
2255
|
+
this.bcsPass = new ShaderPass(this.bcs, "tDiffuse");
|
2256
|
+
this.bcs.uniforms.brightness.value = composerValues.brightness;
|
2257
|
+
this.bcs.uniforms.contrast.value = composerValues.contrast;
|
2258
|
+
this.bcs.uniforms.saturation.value = composerValues.saturation;
|
1253
2259
|
this.gaussGrainPass = new ShaderPass(this.gaussGrainEffect, "tDiffuse");
|
2260
|
+
this.smaaPass = new EffectPass2(this.camera, this.smaaEffect);
|
1254
2261
|
this.composer.addPass(this.renderPass);
|
2262
|
+
this.composer.addPass(this.normalPass);
|
2263
|
+
this.composer.addPass(this.ssaoPass);
|
1255
2264
|
this.composer.addPass(this.fxaaPass);
|
2265
|
+
this.composer.addPass(this.smaaPass);
|
1256
2266
|
this.composer.addPass(this.bloomPass);
|
2267
|
+
this.composer.addPass(this.toneMappingPass);
|
2268
|
+
this.composer.addPass(this.bcsPass);
|
1257
2269
|
this.composer.addPass(this.gaussGrainPass);
|
1258
|
-
|
1259
|
-
this.
|
1260
|
-
|
2270
|
+
this.tweakPane.setupRenderPane(
|
2271
|
+
this.ssaoEffect,
|
2272
|
+
this.toneMappingEffect,
|
2273
|
+
this.toneMappingPass,
|
2274
|
+
this.bcs,
|
2275
|
+
this.bloomEffect,
|
2276
|
+
this.gaussGrainEffect
|
2277
|
+
);
|
2278
|
+
window.addEventListener("resize", () => this.updateProjection());
|
1261
2279
|
this.updateProjection();
|
1262
2280
|
}
|
1263
2281
|
updateProjection() {
|
1264
2282
|
this.width = window.innerWidth;
|
1265
2283
|
this.height = innerHeight;
|
1266
2284
|
this.resolution = new Vector22(this.width, this.height);
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
2285
|
+
this.composer.setSize(this.width, this.height);
|
2286
|
+
this.renderPass.setSize(this.width, this.height);
|
2287
|
+
this.normalPass.setSize(this.width, this.height);
|
2288
|
+
this.ssaoPass.setSize(this.width, this.height);
|
2289
|
+
this.fxaaPass.setSize(this.width, this.height);
|
2290
|
+
this.smaaPass.setSize(this.width, this.height);
|
2291
|
+
this.bloomPass.setSize(this.width, this.height);
|
2292
|
+
this.toneMappingPass.setSize(this.width, this.height);
|
2293
|
+
this.gaussGrainPass.setSize(this.width, this.height);
|
1273
2294
|
this.renderer.setSize(this.width, this.height);
|
1274
2295
|
}
|
1275
|
-
|
1276
|
-
this.
|
2296
|
+
isTweakPaneVisible() {
|
2297
|
+
return this.tweakPane.guiVisible;
|
2298
|
+
}
|
2299
|
+
render(timeManager) {
|
2300
|
+
this.renderer.info.reset();
|
2301
|
+
this.normalPass.texture.needsUpdate = true;
|
1277
2302
|
this.gaussGrainEffect.uniforms.resolution.value = this.resolution;
|
1278
|
-
this.gaussGrainEffect.uniforms.time.value = time;
|
2303
|
+
this.gaussGrainEffect.uniforms.time.value = timeManager.time;
|
1279
2304
|
this.gaussGrainEffect.uniforms.alpha.value = 1;
|
1280
|
-
this.
|
1281
|
-
this.
|
2305
|
+
this.composer.render();
|
2306
|
+
if (this.tweakPane.guiVisible) {
|
2307
|
+
this.tweakPane.updateStats(timeManager);
|
2308
|
+
}
|
2309
|
+
}
|
2310
|
+
useHDRI(url) {
|
2311
|
+
if (this.isEnvHDRI || !this.renderer)
|
2312
|
+
return;
|
2313
|
+
const pmremGenerator = new PMREMGenerator(this.renderer);
|
2314
|
+
new RGBELoader(new LoadingManager2()).load(
|
2315
|
+
url,
|
2316
|
+
(texture) => {
|
2317
|
+
const envMap = pmremGenerator.fromEquirectangular(texture).texture;
|
2318
|
+
if (envMap) {
|
2319
|
+
envMap.colorSpace = LinearSRGBColorSpace;
|
2320
|
+
envMap.needsUpdate = true;
|
2321
|
+
this.scene.environment = envMap;
|
2322
|
+
this.scene.background = envMap;
|
2323
|
+
this.scene.backgroundIntensity = composerValues.renderer.bgIntensity;
|
2324
|
+
this.isEnvHDRI = true;
|
2325
|
+
texture.dispose();
|
2326
|
+
pmremGenerator.dispose();
|
2327
|
+
}
|
2328
|
+
},
|
2329
|
+
() => {
|
2330
|
+
},
|
2331
|
+
(error) => {
|
2332
|
+
console.error(`Can't load ${url}: ${JSON.stringify(error)}`);
|
2333
|
+
}
|
2334
|
+
);
|
1282
2335
|
}
|
1283
2336
|
};
|
1284
2337
|
|
@@ -1288,7 +2341,7 @@ var TimeManager = class {
|
|
1288
2341
|
constructor() {
|
1289
2342
|
__publicField(this, "clock", new Clock());
|
1290
2343
|
__publicField(this, "roundMagnitude", 2e5);
|
1291
|
-
__publicField(this, "maxAverageFrames",
|
2344
|
+
__publicField(this, "maxAverageFrames", 150);
|
1292
2345
|
__publicField(this, "deltaTimes", []);
|
1293
2346
|
__publicField(this, "targetAverageDeltaTime", 0);
|
1294
2347
|
__publicField(this, "lerpedAverageMagDelta", 0);
|
@@ -1297,17 +2350,18 @@ var TimeManager = class {
|
|
1297
2350
|
__publicField(this, "time", 0);
|
1298
2351
|
__publicField(this, "deltaTime", 0);
|
1299
2352
|
__publicField(this, "rawDeltaTime", 0);
|
2353
|
+
__publicField(this, "smoothDeltaTime", 0);
|
1300
2354
|
__publicField(this, "frame", 0);
|
1301
2355
|
__publicField(this, "fps", 0);
|
2356
|
+
__publicField(this, "averageFPS", 0);
|
1302
2357
|
}
|
1303
2358
|
update() {
|
1304
2359
|
this.rawDeltaTime = this.clock.getDelta();
|
1305
2360
|
this.frame++;
|
1306
2361
|
this.time += this.rawDeltaTime;
|
1307
2362
|
this.deltaTimes.push(this.rawDeltaTime);
|
1308
|
-
if (this.deltaTimes.length > this.maxAverageFrames)
|
2363
|
+
if (this.deltaTimes.length > this.maxAverageFrames)
|
1309
2364
|
this.deltaTimes.shift();
|
1310
|
-
}
|
1311
2365
|
this.targetAverageDeltaTime = this.deltaTimes.reduce((prev, curr) => prev + curr, 0) / this.deltaTimes.length;
|
1312
2366
|
this.lerpedAverageMagDelta += ease(
|
1313
2367
|
this.targetAverageDeltaTime * this.roundMagnitude,
|
@@ -1316,9 +2370,10 @@ var TimeManager = class {
|
|
1316
2370
|
);
|
1317
2371
|
const revertMagnitude = this.lerpedAverageMagDelta / this.roundMagnitude;
|
1318
2372
|
const smoothDT = Math.round(revertMagnitude * this.roundMagnitude) / this.roundMagnitude;
|
1319
|
-
this.
|
2373
|
+
this.smoothDeltaTime = smoothDT > this.rawDeltaTime * 1.75 ? this.rawDeltaTime : smoothDT;
|
2374
|
+
this.deltaTime = this.smoothDeltaTime;
|
1320
2375
|
this.framesSinceLastFPSUpdate++;
|
1321
|
-
if (this.framesSinceLastFPSUpdate >=
|
2376
|
+
if (this.framesSinceLastFPSUpdate >= 60) {
|
1322
2377
|
this.fps = Math.round(this.framesSinceLastFPSUpdate / (this.time - this.fpsUpdateTime) * 100) / 100;
|
1323
2378
|
this.fpsUpdateTime = this.time;
|
1324
2379
|
this.framesSinceLastFPSUpdate = 0;
|
@@ -1332,7 +2387,8 @@ import {
|
|
1332
2387
|
getRelativePositionAndRotationRelativeToObject
|
1333
2388
|
} from "mml-web";
|
1334
2389
|
import {
|
1335
|
-
Color as
|
2390
|
+
Color as Color5,
|
2391
|
+
DoubleSide,
|
1336
2392
|
Euler,
|
1337
2393
|
FrontSide,
|
1338
2394
|
Mesh as Mesh2,
|
@@ -1352,6 +2408,18 @@ var CollisionsManager = class {
|
|
1352
2408
|
this.scene = scene;
|
1353
2409
|
this.collisionTrigger = MMLCollisionTrigger.init();
|
1354
2410
|
}
|
2411
|
+
raycastFirstDistance(ray) {
|
2412
|
+
let minimumDistance = Infinity;
|
2413
|
+
for (const [, value] of this.collisionMeshState) {
|
2414
|
+
const hit = value.meshBVH.raycast(ray, DoubleSide);
|
2415
|
+
if (hit.length > 0) {
|
2416
|
+
if (hit[0].distance < minimumDistance) {
|
2417
|
+
minimumDistance = hit[0].distance;
|
2418
|
+
}
|
2419
|
+
}
|
2420
|
+
}
|
2421
|
+
return minimumDistance;
|
2422
|
+
}
|
1355
2423
|
createCollisionMeshState(group) {
|
1356
2424
|
const geometries = [];
|
1357
2425
|
group.traverse((child) => {
|
@@ -1384,7 +2452,7 @@ var CollisionsManager = class {
|
|
1384
2452
|
);
|
1385
2453
|
mergedMesh.geometry.boundsTree = meshBVH;
|
1386
2454
|
const visualizer = new MeshBVHVisualizer(mergedMesh, 3);
|
1387
|
-
visualizer.edgeMaterial.color = new
|
2455
|
+
visualizer.edgeMaterial.color = new Color5(255);
|
1388
2456
|
visualizer.update();
|
1389
2457
|
return { source: group, visualizer, meshBVH };
|
1390
2458
|
}
|