@mml-io/3d-web-client-core 0.2.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/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";
@@ -34,7 +34,7 @@ var remap = (value, minValue, maxValue, minScaledValue, maxScaledValue) => {
34
34
  return minScaledValue + (maxScaledValue - minScaledValue) * (value - minValue) / (maxValue - minValue);
35
35
  };
36
36
 
37
- // src/rendering/tweakPaneActivity.ts
37
+ // src/tweakpane/tweakPaneActivity.ts
38
38
  var isTweakpaneActive = false;
39
39
  function setTweakpaneActive(status) {
40
40
  isTweakpaneActive = status;
@@ -45,14 +45,15 @@ function getTweakpaneActive() {
45
45
 
46
46
  // src/camera/CameraManager.ts
47
47
  var CameraManager = class {
48
- constructor() {
48
+ constructor(collisionsManager) {
49
+ this.collisionsManager = collisionsManager;
49
50
  __publicField(this, "camera");
50
51
  __publicField(this, "initialDistance", 2.5);
51
52
  __publicField(this, "minDistance", 0.1);
52
53
  __publicField(this, "maxDistance", 6);
53
54
  __publicField(this, "initialFOV", 80);
54
55
  __publicField(this, "fov", this.initialFOV);
55
- __publicField(this, "minFOV", 65);
56
+ __publicField(this, "minFOV", 63);
56
57
  __publicField(this, "maxFOV", 85);
57
58
  __publicField(this, "targetFOV", this.initialFOV);
58
59
  __publicField(this, "minPolarAngle", Math.PI * 0.25);
@@ -67,13 +68,10 @@ var CameraManager = class {
67
68
  __publicField(this, "dragging", false);
68
69
  __publicField(this, "target", new Vector32(0, 1.55, 0));
69
70
  __publicField(this, "hadTarget", false);
70
- this.camera = new PerspectiveCamera(
71
- this.fov,
72
- window.innerWidth / window.innerHeight,
73
- 0.1,
74
- 2e3
75
- );
71
+ __publicField(this, "rayCaster");
72
+ this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
76
73
  this.camera.position.set(0, 1.4, -this.initialDistance);
74
+ this.rayCaster = new Raycaster();
77
75
  document.addEventListener("mousedown", this.onMouseDown.bind(this));
78
76
  document.addEventListener("mouseup", this.onMouseUp.bind(this));
79
77
  document.addEventListener("mousemove", this.onMouseMove.bind(this));
@@ -129,6 +127,18 @@ var CameraManager = class {
129
127
  this.theta = this.targetTheta;
130
128
  this.distance = this.targetDistance;
131
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
+ }
132
142
  update() {
133
143
  if (this.target === null)
134
144
  return;
@@ -149,7 +159,9 @@ var CameraManager = class {
149
159
  this.fov += ease(this.targetFOV, this.fov, 0.07);
150
160
  this.camera.fov = this.fov;
151
161
  this.camera.updateProjectionMatrix();
162
+ this.camera.updateMatrixWorld();
152
163
  this.camera.position.set(x, clamp(y, 0.1, Infinity), z);
164
+ this.adjustCameraPosition();
153
165
  this.camera.lookAt(this.target);
154
166
  }
155
167
  }
@@ -260,6 +272,41 @@ ${before}
260
272
  );
261
273
  }
262
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
+
263
310
  // src/character/CharacterMaterial.ts
264
311
  var CharacterMaterial = class extends MeshPhysicalMaterial {
265
312
  constructor() {
@@ -267,18 +314,32 @@ var CharacterMaterial = class extends MeshPhysicalMaterial {
267
314
  __publicField(this, "uniforms", {});
268
315
  __publicField(this, "colorsCube216", []);
269
316
  this.color = new Color(16777215);
270
- this.transmission = 0.5;
271
- this.metalness = 0.9;
272
- this.roughness = 0.1;
273
- this.ior = 1.2;
274
- this.thickness = 0.1;
275
- this.specularColor = new Color(30719);
276
- this.specularIntensity = 0.1;
277
- this.emissive = new Color(16777215);
278
- this.emissiveIntensity = 0.1;
279
- this.envMapIntensity = 1.8;
280
- this.sheenColor = new Color(16777215);
281
- this.sheen = 0.5;
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;
282
343
  this.onBeforeCompile = (shader) => {
283
344
  this.uniforms = UniformsUtils.clone(shader.uniforms);
284
345
  this.uniforms.nearClip = { value: 0.01 };
@@ -377,6 +438,34 @@ var CharacterMaterial = class extends MeshPhysicalMaterial {
377
438
  hue = (hue + goldenRatioConjugate) % 1;
378
439
  }
379
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
+ }
380
469
  };
381
470
 
382
471
  // src/character/CharacterState.ts
@@ -636,7 +725,7 @@ var CharacterModel = class {
636
725
  };
637
726
 
638
727
  // src/character/LocalController.ts
639
- import { Box3, Line3, Matrix4, Quaternion, Raycaster, Vector3 as Vector33 } from "three";
728
+ import { Box3, Line3, Matrix4, Quaternion, Raycaster as Raycaster2, Vector3 as Vector33 } from "three";
640
729
  var LocalController = class {
641
730
  constructor(model, id, collisionsManager, keyInputManager, cameraManager, timeManager) {
642
731
  this.model = model;
@@ -671,7 +760,7 @@ var LocalController = class {
671
760
  __publicField(this, "tempSegment", new Line3());
672
761
  __publicField(this, "tempVector", new Vector33());
673
762
  __publicField(this, "tempVector2", new Vector33());
674
- __publicField(this, "rayCaster", new Raycaster());
763
+ __publicField(this, "rayCaster", new Raycaster2());
675
764
  __publicField(this, "forward");
676
765
  __publicField(this, "backward");
677
766
  __publicField(this, "left");
@@ -708,9 +797,10 @@ var LocalController = class {
708
797
  this.targetSpeed = this.run ? this.maxRunSpeed : this.maxWalkSpeed;
709
798
  this.speed += ease(this.targetSpeed, this.speed, 0.07);
710
799
  this.rayCaster.set(this.model.mesh.position, this.vectorDown);
711
- const hit = this.rayCaster.intersectObjects([this.collisionsManager.colliders]);
712
- if (hit.length > 0)
713
- this.currentHeight = hit[0].distance;
800
+ const minimumDistance = this.collisionsManager.raycastFirstDistance(this.rayCaster.ray);
801
+ if (minimumDistance !== null) {
802
+ this.currentHeight = minimumDistance;
803
+ }
714
804
  if (anyDirection || !this.characterOnGround) {
715
805
  const targetAnimation = this.getTargetAnimation();
716
806
  this.model.updateAnimation(targetAnimation, this.timeManager.deltaTime);
@@ -761,10 +851,17 @@ var LocalController = class {
761
851
  updateAzimuthalAngle() {
762
852
  if (!this.thirdPersonCamera || !this.model?.mesh)
763
853
  return;
764
- this.azimuthalAngle = Math.atan2(
765
- this.thirdPersonCamera.position.x - this.model.mesh.position.x,
766
- this.thirdPersonCamera.position.z - this.model.mesh.position.z
767
- );
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
+ }
768
865
  }
769
866
  updateRotation() {
770
867
  if (!this.thirdPersonCamera || !this.model?.mesh)
@@ -918,6 +1015,7 @@ var Character = class {
918
1015
  if (typeof this.model.material.uniforms.time !== "undefined") {
919
1016
  this.model.material.uniforms.time.value = time;
920
1017
  this.model.material.uniforms.diffuseRandomColor.value = this.color;
1018
+ this.model.material.update();
921
1019
  }
922
1020
  }
923
1021
  };
@@ -1030,6 +1128,8 @@ var CharacterManager = class {
1030
1128
  __publicField(this, "remoteCharacterControllers", /* @__PURE__ */ new Map());
1031
1129
  __publicField(this, "characterDescription", null);
1032
1130
  __publicField(this, "character", null);
1131
+ __publicField(this, "cameraOffsetTarget", 0);
1132
+ __publicField(this, "cameraOffset", 0);
1033
1133
  __publicField(this, "group");
1034
1134
  this.group = new Group();
1035
1135
  setInterval(() => this.update.bind(this), 3e3);
@@ -1142,7 +1242,13 @@ var CharacterManager = class {
1142
1242
  update() {
1143
1243
  if (this.character) {
1144
1244
  this.character.update(this.timeManager.time);
1145
- this.cameraManager.setTarget(this.character.position.add(new Vector36(0, 1.3, 0)));
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
+ }
1146
1252
  if (this.character.controller) {
1147
1253
  this.character.controller.update();
1148
1254
  if (this.timeManager.frame % 2 === 0) {
@@ -1309,36 +1415,40 @@ var MMLCompositionScene = class {
1309
1415
 
1310
1416
  // src/rendering/composer.ts
1311
1417
  import {
1312
- EffectComposer,
1418
+ EffectComposer as EffectComposer2,
1313
1419
  RenderPass,
1314
- EffectPass,
1420
+ EffectPass as EffectPass2,
1315
1421
  FXAAEffect,
1316
1422
  ShaderPass,
1317
- BloomEffect,
1318
- SSAOEffect,
1319
- NormalPass,
1320
- BlendFunction as BlendFunction2,
1321
- TextureEffect
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
1322
1433
  } from "postprocessing";
1323
1434
  import {
1324
1435
  Color as Color4,
1436
+ HalfFloatType,
1325
1437
  LinearSRGBColorSpace,
1326
1438
  LoadingManager as LoadingManager2,
1327
1439
  PMREMGenerator,
1328
1440
  Vector2 as Vector22,
1329
- WebGLRenderer as WebGLRenderer2
1441
+ WebGLRenderer as WebGLRenderer3
1330
1442
  } from "three";
1331
1443
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
1332
- import { Pane } from "tweakpane";
1333
1444
 
1334
- // src/rendering/composerSettings.ts
1445
+ // src/tweakpane/composerSettings.ts
1335
1446
  import { BlendFunction } from "postprocessing";
1336
- import { Color as Color3 } from "three";
1337
1447
  var composerValues = {
1338
1448
  renderer: {
1339
1449
  shadowMap: 2,
1340
- toneMapping: 1,
1341
- exposure: 0.75,
1450
+ toneMapping: 4,
1451
+ exposure: 1,
1342
1452
  bgIntensity: 0.6,
1343
1453
  bgBlurriness: 0
1344
1454
  },
@@ -1346,28 +1456,40 @@ var composerValues = {
1346
1456
  blendFunction: BlendFunction.MULTIPLY,
1347
1457
  distanceScaling: true,
1348
1458
  depthAwareUpsampling: true,
1349
- samples: 50,
1350
- rings: 11,
1351
- luminanceInfluence: 0.3,
1352
- radius: 0.07,
1353
- intensity: 3,
1354
- bias: 0.03,
1459
+ samples: 17,
1460
+ rings: 7,
1461
+ luminanceInfluence: 0.7,
1462
+ radius: 0.03,
1463
+ intensity: 2.5,
1464
+ bias: 0.05,
1355
1465
  fade: 0.03,
1356
- resolutionScale: 1,
1357
- color: new Color3(0),
1358
- worldDistanceThreshold: 200,
1359
- worldDistanceFalloff: 2,
1360
- worldProximityThreshold: 100,
1361
- worldProximityFalloff: 2
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
1362
1481
  },
1363
- grain: 0.04,
1364
- bloom: 0.7
1482
+ brightness: -0.03,
1483
+ contrast: 1.3,
1484
+ saturation: 0.95,
1485
+ grain: 0.055,
1486
+ bloom: 0.4
1365
1487
  };
1366
1488
  var composerOptions = {
1367
1489
  renderer: {
1368
1490
  shadowMap: { min: 0, max: 2, step: 1 },
1369
1491
  toneMapping: { min: 0, max: 5, step: 1 },
1370
- exposure: { min: 0, max: 1, step: 0.01 },
1492
+ exposure: { min: 0, max: 3, step: 0.01 },
1371
1493
  bgIntensity: { min: 0, max: 1, step: 0.01 },
1372
1494
  bgBlurriness: { min: 0, max: 0.1, step: 1e-3 }
1373
1495
  },
@@ -1385,6 +1507,24 @@ var composerOptions = {
1385
1507
  worldProximityThreshold: { min: 0, max: 2, step: 0.01 },
1386
1508
  worldProximityFalloff: { min: 0, max: 2, step: 0.01 }
1387
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
+ },
1388
1528
  grain: {
1389
1529
  amount: { min: 0, max: 0.2, step: 2e-3 }
1390
1530
  },
@@ -1405,6 +1545,13 @@ var rendererToneMappingTypes = {
1405
1545
  4: "ACESFilmicToneMapping",
1406
1546
  5: "CustomToneMapping"
1407
1547
  };
1548
+ var customToneMappingTypes = {
1549
+ 0: "REINHARD",
1550
+ 1: "REINHARD2",
1551
+ 2: "REINHARD2_ADAPTIVE",
1552
+ 3: "OPTIMIZED_CINEON",
1553
+ 4: "ACES_FILMIC"
1554
+ };
1408
1555
  var rendererBlades = {
1409
1556
  shadowMapType: shadowMapTypes[composerValues.renderer.shadowMap],
1410
1557
  toneMappingType: rendererToneMappingTypes[composerValues.renderer.toneMapping]
@@ -1415,6 +1562,12 @@ var setShadowMapType = (value) => {
1415
1562
  var setToneMappingType = (value) => {
1416
1563
  rendererBlades.toneMappingType = rendererToneMappingTypes[value];
1417
1564
  };
1565
+ var customToneMappingBlade = {
1566
+ customToneMappingType: customToneMappingTypes[composerValues.toneMapping.mode]
1567
+ };
1568
+ var setCustomToneMappingType = (value) => {
1569
+ customToneMappingBlade.customToneMappingType = customToneMappingTypes[value];
1570
+ };
1418
1571
  var ssaoMaterialParams = [
1419
1572
  "fade",
1420
1573
  "bias",
@@ -1431,11 +1584,437 @@ var statsData = {
1431
1584
  shaders: "0",
1432
1585
  postPasses: "0",
1433
1586
  drawCalls: "0",
1587
+ rawDeltaTime: "0",
1588
+ deltaTime: "0",
1434
1589
  FPS: "0"
1435
1590
  };
1436
1591
 
1437
- // src/rendering/post-effects/gauss-grain.ts
1438
- import { ShaderMaterial, Uniform, Vector2 } from "three";
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";
1439
2018
 
1440
2019
  // src/rendering/shaders/vertex-shader.ts
1441
2020
  var vertexShader = (
@@ -1451,14 +2030,86 @@ var vertexShader = (
1451
2030
  `
1452
2031
  );
1453
2032
 
1454
- // src/rendering/post-effects/gauss-grain.ts
1455
- var GaussGrainEffect = new ShaderMaterial({
2033
+ // src/rendering/post-effects/bright-contrast-sat.ts
2034
+ var BrightnessContrastSaturation = new ShaderMaterial({
1456
2035
  uniforms: {
1457
2036
  tDiffuse: new Uniform(null),
1458
- resolution: new Uniform(new Vector2()),
1459
- time: new Uniform(0),
1460
- amount: new Uniform(0),
1461
- alpha: new Uniform(0)
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)
1462
2113
  },
1463
2114
  vertexShader,
1464
2115
  fragmentShader: (
@@ -1485,7 +2136,7 @@ var GaussGrainEffect = new ShaderMaterial({
1485
2136
  }
1486
2137
 
1487
2138
  vec3 gaussgrain() {
1488
- vec2 ps = vec2(1.01) / resolution.xy;
2139
+ vec2 ps = vec2(1.0) / resolution.xy;
1489
2140
  vec2 uv = gl_FragCoord.xy * ps;
1490
2141
  float t = time;
1491
2142
  float seed = dot(uv, vec2(12.9898, 78.233));
@@ -1502,7 +2153,8 @@ var GaussGrainEffect = new ShaderMaterial({
1502
2153
  gl_FragColor = vec4(clamp(col, 0.0, 1.0), alpha);
1503
2154
  }
1504
2155
  `
1505
- )
2156
+ ),
2157
+ dithering: true
1506
2158
  });
1507
2159
 
1508
2160
  // src/rendering/composer.ts
@@ -1521,22 +2173,22 @@ var Composer = class {
1521
2173
  __publicField(this, "fxaaPass");
1522
2174
  __publicField(this, "bloomEffect");
1523
2175
  __publicField(this, "bloomPass");
2176
+ __publicField(this, "toneMappingEffect");
2177
+ __publicField(this, "smaaEffect");
1524
2178
  __publicField(this, "normalPass");
1525
2179
  __publicField(this, "normalTextureEffect");
1526
2180
  __publicField(this, "ssaoEffect");
1527
2181
  __publicField(this, "ssaoPass");
2182
+ __publicField(this, "toneMappingPass");
2183
+ __publicField(this, "smaaPass");
2184
+ __publicField(this, "bcs", BrightnessContrastSaturation);
2185
+ __publicField(this, "bcsPass");
1528
2186
  __publicField(this, "gaussGrainEffect", GaussGrainEffect);
1529
2187
  __publicField(this, "gaussGrainPass");
1530
- __publicField(this, "gui", new Pane());
1531
- __publicField(this, "guiVisible", false);
1532
- __publicField(this, "stats", this.gui.addFolder({ title: "stats", expanded: true }));
1533
- __publicField(this, "renderOptions", this.gui.addFolder({ title: "renderOptions", expanded: false }));
1534
- __publicField(this, "ssao", this.gui.addFolder({ title: "ambientOcclusion", expanded: false }));
1535
- __publicField(this, "post", this.gui.addFolder({ title: "post", expanded: false }));
1536
- __publicField(this, "export", this.gui.addFolder({ title: "import/export", expanded: false }));
2188
+ __publicField(this, "tweakPane");
1537
2189
  this.scene = scene;
1538
2190
  this.camera = camera;
1539
- this.renderer = new WebGLRenderer2({
2191
+ this.renderer = new WebGLRenderer3({
1540
2192
  powerPreference: "high-performance",
1541
2193
  antialias: false,
1542
2194
  stencil: false,
@@ -1547,185 +2199,102 @@ var Composer = class {
1547
2199
  this.renderer.shadowMap.enabled = true;
1548
2200
  this.renderer.shadowMap.type = composerValues.renderer.shadowMap;
1549
2201
  this.renderer.toneMapping = composerValues.renderer.toneMapping;
1550
- this.renderer.toneMappingExposure = 0.7;
2202
+ this.renderer.toneMappingExposure = composerValues.renderer.exposure;
1551
2203
  document.body.appendChild(this.renderer.domElement);
1552
- this.composer = new EffectComposer(this.renderer);
2204
+ this.composer = new EffectComposer2(this.renderer, {
2205
+ frameBufferType: HalfFloatType
2206
+ });
2207
+ this.tweakPane = new TweakPane(this.renderer, this.scene, this.composer);
1553
2208
  this.renderPass = new RenderPass(this.scene, this.camera);
1554
2209
  this.normalPass = new NormalPass(this.scene, this.camera);
1555
2210
  this.normalTextureEffect = new TextureEffect({
1556
- blendFunction: BlendFunction2.SKIP,
2211
+ blendFunction: BlendFunction3.SKIP,
1557
2212
  texture: this.normalPass.texture
1558
2213
  });
1559
2214
  this.fxaaEffect = new FXAAEffect();
1560
- this.bloomEffect = new BloomEffect({
2215
+ this.bloomEffect = new BloomEffect2({
1561
2216
  intensity: composerValues.bloom
1562
2217
  });
1563
- this.ssaoEffect = new SSAOEffect(this.camera, this.normalPass.texture, {
1564
- ...composerValues.ssao
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
1565
2252
  });
1566
- this.fxaaPass = new EffectPass(this.camera, this.fxaaEffect);
1567
- this.bloomPass = new EffectPass(this.camera, this.bloomEffect);
1568
- this.ssaoPass = new EffectPass(this.camera, this.ssaoEffect, this.normalTextureEffect);
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;
1569
2259
  this.gaussGrainPass = new ShaderPass(this.gaussGrainEffect, "tDiffuse");
2260
+ this.smaaPass = new EffectPass2(this.camera, this.smaaEffect);
1570
2261
  this.composer.addPass(this.renderPass);
1571
2262
  this.composer.addPass(this.normalPass);
1572
2263
  this.composer.addPass(this.ssaoPass);
1573
2264
  this.composer.addPass(this.fxaaPass);
2265
+ this.composer.addPass(this.smaaPass);
1574
2266
  this.composer.addPass(this.bloomPass);
2267
+ this.composer.addPass(this.toneMappingPass);
2268
+ this.composer.addPass(this.bcsPass);
1575
2269
  this.composer.addPass(this.gaussGrainPass);
2270
+ this.tweakPane.setupRenderPane(
2271
+ this.ssaoEffect,
2272
+ this.toneMappingEffect,
2273
+ this.toneMappingPass,
2274
+ this.bcs,
2275
+ this.bloomEffect,
2276
+ this.gaussGrainEffect
2277
+ );
1576
2278
  window.addEventListener("resize", () => this.updateProjection());
1577
- window.addEventListener("keydown", this.processKey.bind(this));
1578
- this.setupGUIListeners.bind(this)();
1579
2279
  this.updateProjection();
1580
- this.setupTweakPane();
1581
- }
1582
- setupGUIListeners() {
1583
- const gui = this.gui;
1584
- const paneElement = gui.containerElem_;
1585
- paneElement.style.display = this.guiVisible ? "unset" : "none";
1586
- this.gui.element.addEventListener("mousedown", () => setTweakpaneActive(true));
1587
- this.gui.element.addEventListener("mouseup", () => setTweakpaneActive(false));
1588
- this.gui.element.addEventListener("mouseleave", () => setTweakpaneActive(false));
1589
- }
1590
- setupTweakPane() {
1591
- this.stats.addMonitor(statsData, "triangles");
1592
- this.stats.addMonitor(statsData, "geometries");
1593
- this.stats.addMonitor(statsData, "textures");
1594
- this.stats.addMonitor(statsData, "shaders");
1595
- this.stats.addMonitor(statsData, "postPasses");
1596
- this.stats.addMonitor(statsData, "drawCalls");
1597
- this.stats.addMonitor(statsData, "FPS");
1598
- this.renderOptions.addInput(composerValues.renderer, "shadowMap", composerOptions.renderer.shadowMap);
1599
- this.renderOptions.addMonitor(rendererBlades, "shadowMapType");
1600
- this.renderOptions.addInput(composerValues.renderer, "toneMapping", composerOptions.renderer.toneMapping);
1601
- this.renderOptions.addMonitor(rendererBlades, "toneMappingType");
1602
- this.renderOptions.addInput(composerValues.renderer, "exposure", composerOptions.renderer.exposure);
1603
- this.renderOptions.addInput(composerValues.renderer, "bgIntensity", composerOptions.renderer.bgIntensity);
1604
- this.renderOptions.addInput(composerValues.renderer, "bgBlurriness", composerOptions.renderer.bgBlurriness);
1605
- this.renderOptions.on("change", (e) => {
1606
- const target = e.target;
1607
- switch (target.label) {
1608
- case "shadowMap":
1609
- this.renderer.shadowMap.type = e.value;
1610
- setShadowMapType(e.value);
1611
- break;
1612
- case "toneMapping":
1613
- this.renderer.toneMapping = e.value;
1614
- setToneMappingType(e.value);
1615
- break;
1616
- case "exposure":
1617
- this.renderer.toneMappingExposure = e.value;
1618
- break;
1619
- case "bgIntensity":
1620
- this.scene.backgroundIntensity = e.value;
1621
- break;
1622
- case "bgBlurriness":
1623
- this.scene.backgroundBlurriness = e.value;
1624
- break;
1625
- default:
1626
- break;
1627
- }
1628
- });
1629
- this.ssao.addInput({ showEffectOnly: false }, "showEffectOnly");
1630
- this.ssao.addInput(composerValues.ssao, "samples", composerOptions.ssao.samples);
1631
- this.ssao.addInput(composerValues.ssao, "rings", composerOptions.ssao.rings);
1632
- this.ssao.addInput(composerValues.ssao, "luminanceInfluence", composerOptions.ssao.luminanceInfluence);
1633
- this.ssao.addInput(composerValues.ssao, "radius", composerOptions.ssao.radius);
1634
- this.ssao.addInput(composerValues.ssao, "intensity", composerOptions.ssao.intensity);
1635
- this.ssao.addInput(composerValues.ssao, "bias", composerOptions.ssao.bias);
1636
- this.ssao.addInput(composerValues.ssao, "fade", composerOptions.ssao.fade);
1637
- this.ssao.addInput(composerValues.ssao, "resolutionScale", composerOptions.ssao.resolutionScale);
1638
- this.ssao.addInput(composerValues.ssao, "worldDistanceThreshold", composerOptions.ssao.worldDistanceThreshold);
1639
- this.ssao.addInput(composerValues.ssao, "worldDistanceFalloff", composerOptions.ssao.worldDistanceFalloff);
1640
- this.ssao.addInput(composerValues.ssao, "worldProximityThreshold", composerOptions.ssao.worldProximityThreshold);
1641
- this.ssao.addInput(composerValues.ssao, "worldProximityFalloff", composerOptions.ssao.worldProximityFalloff);
1642
- this.ssao.addInput(composerValues.ssao, "color");
1643
- this.ssao.on("change", (e) => {
1644
- if (!e.presetKey) {
1645
- return;
1646
- }
1647
- const preset = e.presetKey;
1648
- if (preset === "showEffectOnly") {
1649
- this.ssaoEffect.blendMode.blendFunction = e.value === true ? BlendFunction2.NORMAL : BlendFunction2.MULTIPLY;
1650
- return;
1651
- }
1652
- if (preset === "resolutionScale") {
1653
- this.ssaoEffect.resolution.scale = e.value;
1654
- return;
1655
- }
1656
- if (ssaoMaterialParams.includes(e.presetKey)) {
1657
- this.ssaoEffect.ssaoMaterial[preset] = e.value;
1658
- return;
1659
- }
1660
- if (e.presetKey === "color") {
1661
- this.ssaoEffect.color = new Color4().setRGB(
1662
- e.value.r / 255,
1663
- e.value.g / 255,
1664
- e.value.b / 255
1665
- );
1666
- return;
1667
- }
1668
- this.ssaoEffect[preset] = e.value;
1669
- });
1670
- this.post.addInput(composerValues, "bloom", composerOptions.bloom.amount);
1671
- this.post.addInput(composerValues, "grain", composerOptions.grain.amount);
1672
- this.post.on("change", (e) => {
1673
- const target = e.presetKey;
1674
- console.log(target);
1675
- switch (target) {
1676
- case "bloom":
1677
- this.bloomEffect.intensity = e.value;
1678
- break;
1679
- case "grain":
1680
- this.gaussGrainEffect.uniforms.amount.value = e.value;
1681
- break;
1682
- default:
1683
- break;
1684
- }
1685
- });
1686
- const button = this.export.addButton({ title: "export" });
1687
- button.on("click", () => {
1688
- console.log(this.gui.exportPreset());
1689
- });
1690
- }
1691
- toggleGUI() {
1692
- const gui = this.gui;
1693
- const paneElement = gui.containerElem_;
1694
- paneElement.style.display = this.guiVisible ? "none" : "unset";
1695
- this.guiVisible = !this.guiVisible;
1696
- }
1697
- processKey(e) {
1698
- if (e.key === "p")
1699
- this.toggleGUI();
1700
2280
  }
1701
2281
  updateProjection() {
1702
2282
  this.width = window.innerWidth;
1703
2283
  this.height = innerHeight;
1704
2284
  this.resolution = new Vector22(this.width, this.height);
1705
- if (this.composer)
1706
- this.composer.setSize(this.width, this.height);
1707
- if (this.fxaaPass)
1708
- this.fxaaPass.setSize(this.width, this.height);
1709
- if (this.renderPass)
1710
- this.renderPass.setSize(this.width, this.height);
1711
- if (this.bloomPass)
1712
- this.bloomPass.setSize(this.width, this.height);
1713
- if (this.ssaoPass)
1714
- this.ssaoPass.setSize(this.width, this.height);
1715
- if (this.normalPass)
1716
- this.normalPass.setSize(this.width, this.height);
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);
1717
2294
  this.renderer.setSize(this.width, this.height);
1718
2295
  }
1719
- updateStats(timeManager) {
1720
- const { geometries, textures } = this.renderer.info.memory;
1721
- const { triangles, calls } = this.renderer.info.render;
1722
- statsData.triangles = triangles.toString();
1723
- statsData.geometries = geometries.toString();
1724
- statsData.textures = textures.toString();
1725
- statsData.shaders = this.renderer.info.programs.length.toString();
1726
- statsData.postPasses = this.composer.passes.length.toString();
1727
- statsData.drawCalls = calls.toString();
1728
- statsData.FPS = Math.round(timeManager.averageFPS).toString();
2296
+ isTweakPaneVisible() {
2297
+ return this.tweakPane.guiVisible;
1729
2298
  }
1730
2299
  render(timeManager) {
1731
2300
  this.renderer.info.reset();
@@ -1734,7 +2303,9 @@ var Composer = class {
1734
2303
  this.gaussGrainEffect.uniforms.time.value = timeManager.time;
1735
2304
  this.gaussGrainEffect.uniforms.alpha.value = 1;
1736
2305
  this.composer.render();
1737
- this.updateStats(timeManager);
2306
+ if (this.tweakPane.guiVisible) {
2307
+ this.tweakPane.updateStats(timeManager);
2308
+ }
1738
2309
  }
1739
2310
  useHDRI(url) {
1740
2311
  if (this.isEnvHDRI || !this.renderer)
@@ -1749,7 +2320,7 @@ var Composer = class {
1749
2320
  envMap.needsUpdate = true;
1750
2321
  this.scene.environment = envMap;
1751
2322
  this.scene.background = envMap;
1752
- this.scene.backgroundIntensity = 0.5;
2323
+ this.scene.backgroundIntensity = composerValues.renderer.bgIntensity;
1753
2324
  this.isEnvHDRI = true;
1754
2325
  texture.dispose();
1755
2326
  pmremGenerator.dispose();
@@ -1770,10 +2341,8 @@ var TimeManager = class {
1770
2341
  constructor() {
1771
2342
  __publicField(this, "clock", new Clock());
1772
2343
  __publicField(this, "roundMagnitude", 2e5);
1773
- __publicField(this, "maxAverageFrames", 700);
2344
+ __publicField(this, "maxAverageFrames", 150);
1774
2345
  __publicField(this, "deltaTimes", []);
1775
- __publicField(this, "fpsMaxSamples", 10);
1776
- __publicField(this, "fpsSamples", []);
1777
2346
  __publicField(this, "targetAverageDeltaTime", 0);
1778
2347
  __publicField(this, "lerpedAverageMagDelta", 0);
1779
2348
  __publicField(this, "fpsUpdateTime", 0);
@@ -1781,6 +2350,7 @@ var TimeManager = class {
1781
2350
  __publicField(this, "time", 0);
1782
2351
  __publicField(this, "deltaTime", 0);
1783
2352
  __publicField(this, "rawDeltaTime", 0);
2353
+ __publicField(this, "smoothDeltaTime", 0);
1784
2354
  __publicField(this, "frame", 0);
1785
2355
  __publicField(this, "fps", 0);
1786
2356
  __publicField(this, "averageFPS", 0);
@@ -1800,16 +2370,11 @@ var TimeManager = class {
1800
2370
  );
1801
2371
  const revertMagnitude = this.lerpedAverageMagDelta / this.roundMagnitude;
1802
2372
  const smoothDT = Math.round(revertMagnitude * this.roundMagnitude) / this.roundMagnitude;
1803
- this.deltaTime = smoothDT > this.rawDeltaTime * 1.75 ? this.rawDeltaTime : smoothDT;
2373
+ this.smoothDeltaTime = smoothDT > this.rawDeltaTime * 1.75 ? this.rawDeltaTime : smoothDT;
2374
+ this.deltaTime = this.smoothDeltaTime;
1804
2375
  this.framesSinceLastFPSUpdate++;
1805
2376
  if (this.framesSinceLastFPSUpdate >= 60) {
1806
2377
  this.fps = Math.round(this.framesSinceLastFPSUpdate / (this.time - this.fpsUpdateTime) * 100) / 100;
1807
- this.fpsSamples.push(this.fps);
1808
- if (this.fpsSamples.length > this.fpsMaxSamples)
1809
- this.fpsSamples.shift();
1810
- this.averageFPS = this.fpsSamples.length === this.fpsMaxSamples ? Math.round(
1811
- this.fpsSamples.reduce((prev, curr) => prev + curr, 0) / this.fpsSamples.length
1812
- ) : this.fps;
1813
2378
  this.fpsUpdateTime = this.time;
1814
2379
  this.framesSinceLastFPSUpdate = 0;
1815
2380
  }
@@ -1823,9 +2388,9 @@ import {
1823
2388
  } from "mml-web";
1824
2389
  import {
1825
2390
  Color as Color5,
2391
+ DoubleSide,
1826
2392
  Euler,
1827
2393
  FrontSide,
1828
- Group as Group3,
1829
2394
  Mesh as Mesh2,
1830
2395
  MeshStandardMaterial as MeshStandardMaterial2,
1831
2396
  Vector3 as Vector37
@@ -1840,23 +2405,20 @@ var CollisionsManager = class {
1840
2405
  __publicField(this, "tempVector2", new Vector37());
1841
2406
  __publicField(this, "collisionMeshState", /* @__PURE__ */ new Map());
1842
2407
  __publicField(this, "collisionTrigger");
1843
- __publicField(this, "colliders", new Group3());
1844
- __publicField(this, "collisionEnabledMeshes", {});
1845
2408
  this.scene = scene;
1846
2409
  this.collisionTrigger = MMLCollisionTrigger.init();
1847
2410
  }
1848
- safeAddColliders(child) {
1849
- if (!(child.uuid in this.collisionEnabledMeshes)) {
1850
- const clone = child.clone();
1851
- this.collisionEnabledMeshes[child.uuid] = clone;
1852
- this.colliders.add(clone);
1853
- }
1854
- }
1855
- removeFromColliders(child) {
1856
- if (child.uuid in this.collisionEnabledMeshes) {
1857
- this.colliders.remove(this.collisionEnabledMeshes[child.uuid]);
1858
- delete this.collisionEnabledMeshes[child.uuid];
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
+ }
1859
2420
  }
2421
+ return minimumDistance;
1860
2422
  }
1861
2423
  createCollisionMeshState(group) {
1862
2424
  const geometries = [];
@@ -1865,7 +2427,6 @@ var CollisionsManager = class {
1865
2427
  const mesh = child;
1866
2428
  mesh.localToWorld(new Vector37());
1867
2429
  mesh.updateMatrixWorld();
1868
- this.safeAddColliders(mesh);
1869
2430
  const clonedGeometry = mesh.geometry.clone();
1870
2431
  clonedGeometry.applyMatrix4(mesh.matrixWorld);
1871
2432
  for (const key in clonedGeometry.attributes) {
@@ -1926,13 +2487,6 @@ var CollisionsManager = class {
1926
2487
  this.scene.remove(meshState.visualizer);
1927
2488
  }
1928
2489
  this.collisionMeshState.delete(group);
1929
- if (group) {
1930
- group.traverse((child) => {
1931
- if (child.type === "Mesh") {
1932
- this.removeFromColliders(child);
1933
- }
1934
- });
1935
- }
1936
2490
  }
1937
2491
  }
1938
2492
  applyCollider(tempSegment, radius, boundingBox, meshState) {