mage-engine 3.24.2 → 3.24.4

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.
Files changed (2) hide show
  1. package/dist/mage.js +1815 -563
  2. package/package.json +1 -1
package/dist/mage.js CHANGED
@@ -54722,7 +54722,9 @@ let Keyboard = /*#__PURE__*/function (_EventDispatcher) {
54722
54722
  SUBTYPES: {
54723
54723
  DEFAULT: "SCENERY.SUBTYPE.DEFAULT",
54724
54724
  SKY: "SCENERY.SUBTYPE.SKY",
54725
- SKYBOX: "SCENERY.SUBTYPE.SKYBOX"
54725
+ SKYBOX: "SCENERY.SUBTYPE.SKYBOX",
54726
+ WATER: "SCENERY.SUBTYPE.WATER",
54727
+ MIRROR: "SCENERY.SUBTYPE.MIRROR"
54726
54728
  }
54727
54729
  },
54728
54730
  HELPER: {
@@ -54738,7 +54740,7 @@ let Keyboard = /*#__PURE__*/function (_EventDispatcher) {
54738
54740
  UNKNOWN: "UNKNOWN"
54739
54741
  };
54740
54742
  const FLAT_ENTITY_TYPES = [ENTITY_TYPES.SCENE.TYPE, ENTITY_TYPES.CAMERA.TYPE, ENTITY_TYPES.MESH.TYPE, ENTITY_TYPES.LABEL.TYPE, ENTITY_TYPES.LIGHT.TYPE, ENTITY_TYPES.AUDIO.TYPE, ENTITY_TYPES.MODEL.TYPE, ENTITY_TYPES.SPRITE.TYPE, ENTITY_TYPES.PARTICLE.TYPE, ENTITY_TYPES.SCENERY.TYPE, ENTITY_TYPES.HELPER.TYPE, ENTITY_TYPES.UNKNOWN];
54741
- const FLAT_ENTITY_SUBTYPES = [ENTITY_TYPES.SCENE.SUBTYPES.DEFAULT, ENTITY_TYPES.CAMERA.SUBTYPES.DEFAULT, ENTITY_TYPES.CAMERA.SUBTYPES.MAIN, ENTITY_TYPES.CAMERA.SUBTYPES.GAME, ENTITY_TYPES.MESH.SUBTYPES.DEFAULT, ENTITY_TYPES.MESH.SUBTYPES.BOX, ENTITY_TYPES.MESH.SUBTYPES.SPHERE, ENTITY_TYPES.MESH.SUBTYPES.PLANE, ENTITY_TYPES.MESH.SUBTYPES.CYLINDER, ENTITY_TYPES.MESH.SUBTYPES.CONE, ENTITY_TYPES.MESH.SUBTYPES.CUBE, ENTITY_TYPES.MESH.SUBTYPES.LINE, ENTITY_TYPES.MESH.SUBTYPES.CURVE_LINE, ENTITY_TYPES.MESH.SUBTYPES.AXES, ENTITY_TYPES.MESH.SUBTYPES.GRID, ENTITY_TYPES.MESH.SUBTYPES.TARGET, ENTITY_TYPES.LABEL.SUBTYPES.DEFAULT, ENTITY_TYPES.LIGHT.SUBTYPES.DEFAULT, ENTITY_TYPES.LIGHT.SUBTYPES.AMBIENT, ENTITY_TYPES.LIGHT.SUBTYPES.SUN, ENTITY_TYPES.LIGHT.SUBTYPES.HEMISPHERE, ENTITY_TYPES.LIGHT.SUBTYPES.POINT, ENTITY_TYPES.LIGHT.SUBTYPES.SPOT, ENTITY_TYPES.AUDIO.SUBTYPES.DEFAULT, ENTITY_TYPES.AUDIO.SUBTYPES.DIRECTIONAL, ENTITY_TYPES.AUDIO.SUBTYPES.AMBIENT, ENTITY_TYPES.MODEL.SUBTYPES.DEFAULT, ENTITY_TYPES.SPRITE.SUBTYPES.DEFAULT, ENTITY_TYPES.SPRITE.SUBTYPES.ANIMATED_SPRITE, ENTITY_TYPES.PARTICLE.SUBTYPES.DEFAULT, ENTITY_TYPES.PARTICLE.SUBTYPES.EMITTER, ENTITY_TYPES.PARTICLE.SUBTYPES.SYSTEM, ENTITY_TYPES.PARTICLE.SUBTYPES.EMITTER_GROUP, ENTITY_TYPES.PARTICLE.SUBTYPES.PROTON_EMITTER, ENTITY_TYPES.PARTICLE.SUBTYPES.FIRE, ENTITY_TYPES.PARTICLE.SUBTYPES.EXPLOSION, ENTITY_TYPES.PARTICLE.SUBTYPES.TRAIL, ENTITY_TYPES.PARTICLE.SUBTYPES.RAIN, ENTITY_TYPES.PARTICLE.SUBTYPES.SNOW, ENTITY_TYPES.PARTICLE.SUBTYPES.FOUNTAIN, ENTITY_TYPES.SCENERY.SUBTYPES.DEFAULT, ENTITY_TYPES.SCENERY.SUBTYPES.SKY, ENTITY_TYPES.SCENERY.SUBTYPES.SKYBOX, ENTITY_TYPES.HELPER.SUBTYPES.GRID, ENTITY_TYPES.HELPER.SUBTYPES.AXES, ENTITY_TYPES.HELPER.SUBTYPES.HELPER_SPRITE];
54743
+ const FLAT_ENTITY_SUBTYPES = [ENTITY_TYPES.SCENE.SUBTYPES.DEFAULT, ENTITY_TYPES.CAMERA.SUBTYPES.DEFAULT, ENTITY_TYPES.CAMERA.SUBTYPES.MAIN, ENTITY_TYPES.CAMERA.SUBTYPES.GAME, ENTITY_TYPES.MESH.SUBTYPES.DEFAULT, ENTITY_TYPES.MESH.SUBTYPES.BOX, ENTITY_TYPES.MESH.SUBTYPES.SPHERE, ENTITY_TYPES.MESH.SUBTYPES.PLANE, ENTITY_TYPES.MESH.SUBTYPES.CYLINDER, ENTITY_TYPES.MESH.SUBTYPES.CONE, ENTITY_TYPES.MESH.SUBTYPES.CUBE, ENTITY_TYPES.MESH.SUBTYPES.LINE, ENTITY_TYPES.MESH.SUBTYPES.CURVE_LINE, ENTITY_TYPES.MESH.SUBTYPES.AXES, ENTITY_TYPES.MESH.SUBTYPES.GRID, ENTITY_TYPES.MESH.SUBTYPES.TARGET, ENTITY_TYPES.LABEL.SUBTYPES.DEFAULT, ENTITY_TYPES.LIGHT.SUBTYPES.DEFAULT, ENTITY_TYPES.LIGHT.SUBTYPES.AMBIENT, ENTITY_TYPES.LIGHT.SUBTYPES.SUN, ENTITY_TYPES.LIGHT.SUBTYPES.HEMISPHERE, ENTITY_TYPES.LIGHT.SUBTYPES.POINT, ENTITY_TYPES.LIGHT.SUBTYPES.SPOT, ENTITY_TYPES.AUDIO.SUBTYPES.DEFAULT, ENTITY_TYPES.AUDIO.SUBTYPES.DIRECTIONAL, ENTITY_TYPES.AUDIO.SUBTYPES.AMBIENT, ENTITY_TYPES.MODEL.SUBTYPES.DEFAULT, ENTITY_TYPES.SPRITE.SUBTYPES.DEFAULT, ENTITY_TYPES.SPRITE.SUBTYPES.ANIMATED_SPRITE, ENTITY_TYPES.PARTICLE.SUBTYPES.DEFAULT, ENTITY_TYPES.PARTICLE.SUBTYPES.EMITTER, ENTITY_TYPES.PARTICLE.SUBTYPES.SYSTEM, ENTITY_TYPES.PARTICLE.SUBTYPES.EMITTER_GROUP, ENTITY_TYPES.PARTICLE.SUBTYPES.PROTON_EMITTER, ENTITY_TYPES.PARTICLE.SUBTYPES.FIRE, ENTITY_TYPES.PARTICLE.SUBTYPES.EXPLOSION, ENTITY_TYPES.PARTICLE.SUBTYPES.TRAIL, ENTITY_TYPES.PARTICLE.SUBTYPES.RAIN, ENTITY_TYPES.PARTICLE.SUBTYPES.SNOW, ENTITY_TYPES.PARTICLE.SUBTYPES.FOUNTAIN, ENTITY_TYPES.SCENERY.SUBTYPES.DEFAULT, ENTITY_TYPES.SCENERY.SUBTYPES.SKY, ENTITY_TYPES.SCENERY.SUBTYPES.SKYBOX, ENTITY_TYPES.SCENERY.SUBTYPES.WATER, ENTITY_TYPES.SCENERY.SUBTYPES.MIRROR, ENTITY_TYPES.HELPER.SUBTYPES.GRID, ENTITY_TYPES.HELPER.SUBTYPES.AXES, ENTITY_TYPES.HELPER.SUBTYPES.HELPER_SPRITE];
54742
54744
  const ENTITY_EVENTS = {
54743
54745
  DISPOSE: "DISPOSE",
54744
54746
  STATE_MACHINE: {
@@ -54788,9 +54790,9 @@ const createElementFromSelector = function (selector) {
54788
54790
  } catch (e) {
54789
54791
  return null;
54790
54792
  }
54791
- };const DEFAULT_HEIGHT$2 = 600;
54792
- const DEFAULT_WIDTH = 800;
54793
- const DEFAULT_RATIO = DEFAULT_WIDTH / DEFAULT_HEIGHT$2;
54793
+ };const DEFAULT_HEIGHT$3 = 600;
54794
+ const DEFAULT_WIDTH$1 = 800;
54795
+ const DEFAULT_RATIO = DEFAULT_WIDTH$1 / DEFAULT_HEIGHT$3;
54794
54796
  const DEFAULT_CONFIG = {
54795
54797
  tests: [],
54796
54798
  scripts: {// [scriptId]: Script
@@ -54825,7 +54827,7 @@ const DEFAULT_CONFIG = {
54825
54827
  //handling useful informations about our camera.
54826
54828
  fov: 75,
54827
54829
  near: 0.1,
54828
- far: 100
54830
+ far: 10000
54829
54831
  },
54830
54832
  ui: {
54831
54833
  enabled: true
@@ -54918,8 +54920,8 @@ let Config = /*#__PURE__*/function () {
54918
54920
  key: "getScreenDefaults",
54919
54921
  value: function getScreenDefaults() {
54920
54922
  return {
54921
- h: DEFAULT_HEIGHT$2,
54922
- w: DEFAULT_WIDTH,
54923
+ h: DEFAULT_HEIGHT$3,
54924
+ w: DEFAULT_WIDTH$1,
54923
54925
  ratio: DEFAULT_RATIO
54924
54926
  };
54925
54927
  }
@@ -56981,7 +56983,12 @@ var Physics$1 = new Physics();let Scene = /*#__PURE__*/function () {
56981
56983
  }, {
56982
56984
  key: "createCamera",
56983
56985
  value: function createCamera(camera) {
56984
- this.camera = camera;
56986
+ this.camera = camera; // Enable layer 1 so camera can see editor-only objects (helpers, grid, gizmos)
56987
+ // Mirror cameras only use layer 0, so they won't render these
56988
+
56989
+ if (this.camera && this.camera.getBody()) {
56990
+ this.camera.getBody().layers.enable(1);
56991
+ }
56985
56992
  }
56986
56993
  }, {
56987
56994
  key: "getDOMElement",
@@ -57270,7 +57277,9 @@ let Mouse = /*#__PURE__*/function (_EventDispatcher) {
57270
57277
  key: "createRayCaster",
57271
57278
  value: function createRayCaster() {
57272
57279
  if (!this.hasRaycaster()) {
57273
- this.raycaster = new Raycaster();
57280
+ this.raycaster = new Raycaster(); // Enable layer 1 so raycaster can pick editor-only objects (mirrors, etc.)
57281
+
57282
+ this.raycaster.layers.enable(1);
57274
57283
  this.raycaster.setFromCamera(this.mouse, Scene$1.getCameraBody());
57275
57284
  }
57276
57285
  }
@@ -58241,7 +58250,7 @@ function applyMiddleware() {
58241
58250
 
58242
58251
  var thunk = createThunkMiddleware();
58243
58252
  thunk.withExtraArgument = createThunkMiddleware;var name = "mage-engine";
58244
- var version$1 = "3.24.2";
58253
+ var version$1 = "3.24.4";
58245
58254
  var description = "A WebGL Javascript Game Engine, built on top of THREE.js and many other libraries.";
58246
58255
  var main = "dist/mage.js";
58247
58256
  var author$1 = {
@@ -59580,7 +59589,7 @@ if (!self.fetch) {
59580
59589
 
59581
59590
  return BaseCar;
59582
59591
  }(BaseScript);const DEFAULT_DISTANCE$2 = 5.0;
59583
- const DEFAULT_HEIGHT$1 = 3.0;
59592
+ const DEFAULT_HEIGHT$2 = 3.0;
59584
59593
  const DEFAULT_HEIGHT_DAMPING = 2.0;
59585
59594
  const DEFAULT_LOOK_AT_HEIGHT = 1;
59586
59595
  const DEFAULT_ROTATION_SNAP_TIME = 0.3;
@@ -59603,7 +59612,7 @@ let SmoothCarFollow = /*#__PURE__*/function (_BaseScript) {
59603
59612
  value: function start(camera, options) {
59604
59613
  const {
59605
59614
  target,
59606
- height = DEFAULT_HEIGHT$1,
59615
+ height = DEFAULT_HEIGHT$2,
59607
59616
  heightDamping = DEFAULT_HEIGHT_DAMPING,
59608
59617
  lookAtHeight = DEFAULT_LOOK_AT_HEIGHT,
59609
59618
  distance = DEFAULT_DISTANCE$2,
@@ -60657,7 +60666,6 @@ const extractMaterialProperty = (elementBody, property) => {
60657
60666
  return found;
60658
60667
  }
60659
60668
  };
60660
- const serialiseMaterial = material => omit(UNDESIRED_SERIALISED_MATERIAL_PROPERTIES, material === null || material === void 0 ? void 0 : material.toJSON());
60661
60669
  const processMaterial = (material, callback) => Array.isArray(material) ? material.map(callback) : callback(material);
60662
60670
  const replaceMaterialByName = (name, mesh, materialOptions) => {
60663
60671
  if (!hasMaterial(mesh)) return;
@@ -60897,7 +60905,16 @@ const tweenTo = function (origin, target) {
60897
60905
  const qz = Number(z) || 0;
60898
60906
  const qw = Number(w) || 1;
60899
60907
 
60900
- _this.getBody().quaternion.set(qx, qy, qz, qw);
60908
+ _this.getBody().quaternion.set(qx, qy, qz, qw); // Update matrix world and skeleton for skinned meshes
60909
+
60910
+
60911
+ _this.getBody().updateMatrixWorld(true);
60912
+
60913
+ _this.getBody().traverse(child => {
60914
+ if (child.isSkinnedMesh && child.skeleton) {
60915
+ child.skeleton.update();
60916
+ }
60917
+ });
60901
60918
  });
60902
60919
 
60903
60920
  _defineProperty$1(_assertThisInitialized(_this), "setUuid", uuid => {
@@ -61516,7 +61533,9 @@ const tweenTo = function (origin, target) {
61516
61533
  const sx = Number(scale.x) || 1;
61517
61534
  const sy = Number(scale.y) || 1;
61518
61535
  const sz = Number(scale.z) || 1;
61519
- this.body.scale.set(sx, sy, sz);
61536
+ this.body.scale.set(sx, sy, sz); // Update matrix world for all children including skinned meshes
61537
+
61538
+ this.getBody().updateMatrixWorld(true);
61520
61539
  }
61521
61540
  }
61522
61541
  }, {
@@ -61550,7 +61569,17 @@ const tweenTo = function (origin, target) {
61550
61569
  const px = Number(position.x) || 0;
61551
61570
  const py = Number(position.y) || 0;
61552
61571
  const pz = Number(position.z) || 0;
61553
- this.getBody().position.set(px, py, pz);
61572
+ this.getBody().position.set(px, py, pz); // Update matrix world to ensure skinned mesh skeletons follow the parent transform
61573
+
61574
+ this.getBody().updateMatrixWorld(true); // For skinned meshes, we need to rebind the skeleton after position change
61575
+ // The bindMatrix captures where the mesh was when bound, so we need to update it
61576
+
61577
+ this.getBody().traverse(child => {
61578
+ if (child.isSkinnedMesh && child.skeleton) {
61579
+ // Rebind with current matrix to update the bind pose
61580
+ child.bind(child.skeleton, child.matrixWorld);
61581
+ }
61582
+ });
61554
61583
  }
61555
61584
  }
61556
61585
  }, {
@@ -61577,7 +61606,9 @@ const tweenTo = function (origin, target) {
61577
61606
  const rx = Number(rotation.x) || 0;
61578
61607
  const ry = Number(rotation.y) || 0;
61579
61608
  const rz = Number(rotation.z) || 0;
61580
- this.getBody().rotation.set(rx, ry, rz);
61609
+ this.getBody().rotation.set(rx, ry, rz); // Update matrix world for all children including skinned meshes
61610
+
61611
+ this.getBody().updateMatrixWorld(true);
61581
61612
  }
61582
61613
  }
61583
61614
  }, {
@@ -61600,7 +61631,14 @@ const tweenTo = function (origin, target) {
61600
61631
  quaternion
61601
61632
  } = worldTransform;
61602
61633
  this.getBody().setWorldPosition(position);
61603
- this.getBody().setWorldQuaternion(quaternion);
61634
+ this.getBody().setWorldQuaternion(quaternion); // Update matrix world and skeleton for skinned meshes
61635
+
61636
+ this.getBody().updateMatrixWorld(true);
61637
+ this.getBody().traverse(child => {
61638
+ if (child.isSkinnedMesh && child.skeleton) {
61639
+ child.skeleton.update();
61640
+ }
61641
+ });
61604
61642
  }
61605
61643
  }, {
61606
61644
  key: "translate",
@@ -61614,7 +61652,9 @@ const tweenTo = function (origin, target) {
61614
61652
  if (this.hasBody()) {
61615
61653
  this.body.translateX(x);
61616
61654
  this.body.translateY(y);
61617
- this.body.translateZ(z);
61655
+ this.body.translateZ(z); // Update matrix world for all children including skinned meshes
61656
+
61657
+ this.getBody().updateMatrixWorld(true);
61618
61658
  }
61619
61659
  }
61620
61660
  }, {
@@ -61841,7 +61881,9 @@ const tweenTo = function (origin, target) {
61841
61881
  }]);
61842
61882
 
61843
61883
  return Entity;
61844
- }(EventDispatcher);let AnimationHandler = /*#__PURE__*/function (_EventDispatcher) {
61884
+ }(EventDispatcher);const DEFAULT_BLEND_DURATION = 0.3;
61885
+
61886
+ let AnimationHandler = /*#__PURE__*/function (_EventDispatcher) {
61845
61887
  _inherits(AnimationHandler, _EventDispatcher);
61846
61888
 
61847
61889
  var _super = _createSuper(AnimationHandler);
@@ -61871,6 +61913,8 @@ const tweenTo = function (origin, target) {
61871
61913
  _this.mixer = new AnimationMixer(mesh);
61872
61914
  _this.animations = animations;
61873
61915
  _this.isPlaying = false;
61916
+ _this.currentAction = null;
61917
+ _this.activeActions = new Map(); // Track multiple active actions for layered blending
61874
61918
 
61875
61919
  _this.addEventsListeners();
61876
61920
 
@@ -61921,39 +61965,260 @@ const tweenTo = function (origin, target) {
61921
61965
 
61922
61966
  this.isPlaying = false;
61923
61967
  }
61968
+ /**
61969
+ * Stop a specific animation by name/index with optional fade out
61970
+ * @param {string|number} id - Animation name or index
61971
+ * @param {number} fadeOutDuration - Duration to fade out (0 for immediate stop)
61972
+ */
61973
+
61974
+ }, {
61975
+ key: "stopAnimation",
61976
+ value: function stopAnimation(id) {
61977
+ let fadeOutDuration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
61978
+ const clip = this.getAction(id);
61979
+ if (!clip) return;
61980
+ const action = this.mixer.clipAction(clip);
61981
+
61982
+ if (fadeOutDuration > 0) {
61983
+ action.fadeOut(fadeOutDuration);
61984
+ } else {
61985
+ action.stop();
61986
+ }
61987
+
61988
+ this.activeActions.delete(id);
61989
+
61990
+ if (this.currentAction === action) {
61991
+ this.currentAction = null;
61992
+ this.isPlaying = false;
61993
+ }
61994
+ }
61995
+ /**
61996
+ * Play an animation with optional blending from current animation
61997
+ * @param {string|number} id - Animation name or index
61998
+ * @param {Object} options - Playback options
61999
+ * @param {number} options.loop - Loop mode (LoopRepeat, LoopOnce, etc.)
62000
+ * @param {number} options.blendDuration - Duration to blend from previous animation
62001
+ * @param {number} options.timeScale - Playback speed (1 = normal, 2 = double speed)
62002
+ * @param {number} options.weight - Animation weight for layered blending (0-1)
62003
+ * @param {boolean} options.clampWhenFinished - Keep last frame when finished (for LoopOnce)
62004
+ */
62005
+
61924
62006
  }, {
61925
62007
  key: "playAnimation",
61926
- value: function playAnimation(id, options) {
61927
- const action = this.getAction(id);
62008
+ value: function playAnimation(id) {
62009
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
62010
+ const clip = this.getAction(id);
62011
+
62012
+ if (!clip) {
62013
+ console.warn(ANIMATION_NOT_FOUND);
62014
+ return null;
62015
+ }
62016
+
61928
62017
  const {
61929
- loop = LoopRepeat
62018
+ loop = LoopRepeat,
62019
+ blendDuration = DEFAULT_BLEND_DURATION,
62020
+ timeScale = 1,
62021
+ weight = 1,
62022
+ clampWhenFinished = true
61930
62023
  } = options;
61931
62024
  this.isPlaying = true;
61932
62025
 
61933
62026
  if (this.currentAction) {
61934
- this.fadeToAnimation(action, options);
61935
- } else if (action) {
61936
- this.currentAction = this.mixer.clipAction(action).setLoop(loop).play();
62027
+ return this.crossFadeTo(id, { ...options,
62028
+ blendDuration
62029
+ });
61937
62030
  } else {
62031
+ const action = this.mixer.clipAction(clip);
62032
+ this.currentAction = action;
62033
+ this.activeActions.set(id, action);
62034
+ action.reset().setLoop(loop).setEffectiveTimeScale(timeScale).setEffectiveWeight(weight);
62035
+
62036
+ if (loop === LoopOnce) {
62037
+ action.clampWhenFinished = clampWhenFinished;
62038
+ }
62039
+
62040
+ action.play();
62041
+ return action;
62042
+ }
62043
+ }
62044
+ /**
62045
+ * Crossfade from current animation to a new animation
62046
+ * @param {string|number} id - Target animation name or index
62047
+ * @param {Object} options - Blend options
62048
+ * @param {number} options.blendDuration - Duration of the crossfade
62049
+ * @param {number} options.loop - Loop mode for the new animation
62050
+ * @param {number} options.timeScale - Playback speed
62051
+ * @param {boolean} options.warp - Whether to warp time scales during blend
62052
+ */
62053
+
62054
+ }, {
62055
+ key: "crossFadeTo",
62056
+ value: function crossFadeTo(id) {
62057
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
62058
+ const clip = this.getAction(id);
62059
+
62060
+ if (!clip) {
61938
62061
  console.warn(ANIMATION_NOT_FOUND);
62062
+ return null;
62063
+ }
62064
+
62065
+ const {
62066
+ blendDuration = DEFAULT_BLEND_DURATION,
62067
+ loop = LoopRepeat,
62068
+ timeScale = 1,
62069
+ warp = false,
62070
+ clampWhenFinished = true
62071
+ } = options;
62072
+ const previousAction = this.currentAction;
62073
+ const newAction = this.mixer.clipAction(clip);
62074
+
62075
+ if (previousAction === newAction) {
62076
+ return newAction; // Already playing this animation
62077
+ }
62078
+
62079
+ this.currentAction = newAction;
62080
+ this.activeActions.set(id, newAction);
62081
+ newAction.reset().setLoop(loop).setEffectiveTimeScale(timeScale).setEffectiveWeight(1);
62082
+
62083
+ if (loop === LoopOnce) {
62084
+ newAction.clampWhenFinished = clampWhenFinished;
61939
62085
  }
62086
+
62087
+ newAction.play();
62088
+
62089
+ if (previousAction) {
62090
+ if (warp) {
62091
+ // Synchronize time scales during crossfade
62092
+ previousAction.crossFadeTo(newAction, blendDuration, true);
62093
+ } else {
62094
+ // Standard crossfade
62095
+ previousAction.fadeOut(blendDuration);
62096
+ newAction.fadeIn(blendDuration);
62097
+ }
62098
+ }
62099
+
62100
+ return newAction;
61940
62101
  }
62102
+ /**
62103
+ * Legacy method - kept for backwards compatibility
62104
+ */
62105
+
61941
62106
  }, {
61942
62107
  key: "fadeToAnimation",
61943
62108
  value: function fadeToAnimation(action) {
61944
62109
  let {
61945
- duration = 0.2,
62110
+ duration = DEFAULT_BLEND_DURATION,
61946
62111
  loop = LoopRepeat
61947
62112
  } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
61948
62113
  const previousAction = this.currentAction;
61949
62114
  this.currentAction = this.mixer.clipAction(action);
61950
62115
 
61951
- if (previousAction !== this.currentAction) {
62116
+ if (previousAction && previousAction !== this.currentAction) {
61952
62117
  previousAction.fadeOut(duration);
61953
62118
  }
61954
62119
 
61955
62120
  this.currentAction.reset().setEffectiveTimeScale(1).setEffectiveWeight(1).fadeIn(duration).setLoop(loop).play();
61956
62121
  }
62122
+ /**
62123
+ * Set the weight of an animation for layered blending
62124
+ * @param {string|number} id - Animation name or index
62125
+ * @param {number} weight - Weight value (0-1)
62126
+ * @param {number} fadeDuration - Optional fade duration to reach target weight
62127
+ */
62128
+
62129
+ }, {
62130
+ key: "setAnimationWeight",
62131
+ value: function setAnimationWeight(id, weight) {
62132
+ let fadeDuration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
62133
+ const clip = this.getAction(id);
62134
+ if (!clip) return;
62135
+ const action = this.mixer.clipAction(clip);
62136
+
62137
+ if (fadeDuration > 0) {
62138
+ // Gradually change weight
62139
+ const startWeight = action.getEffectiveWeight();
62140
+ const startTime = this.mixer.time;
62141
+
62142
+ const updateWeight = () => {
62143
+ const elapsed = this.mixer.time - startTime;
62144
+ const t = Math.min(elapsed / fadeDuration, 1);
62145
+ action.setEffectiveWeight(startWeight + (weight - startWeight) * t);
62146
+ }; // This will be called in the update loop
62147
+
62148
+
62149
+ action._weightUpdateFn = updateWeight;
62150
+ } else {
62151
+ action.setEffectiveWeight(weight);
62152
+ }
62153
+ }
62154
+ /**
62155
+ * Set the time scale (speed) of an animation
62156
+ * @param {string|number} id - Animation name or index
62157
+ * @param {number} timeScale - Speed multiplier (1 = normal)
62158
+ */
62159
+
62160
+ }, {
62161
+ key: "setAnimationTimeScale",
62162
+ value: function setAnimationTimeScale(id, timeScale) {
62163
+ const clip = this.getAction(id);
62164
+ if (!clip) return;
62165
+ const action = this.mixer.clipAction(clip);
62166
+ action.setEffectiveTimeScale(timeScale);
62167
+ }
62168
+ /**
62169
+ * Get the current time of an animation
62170
+ * @param {string|number} id - Animation name or index
62171
+ * @returns {number} Current time in seconds
62172
+ */
62173
+
62174
+ }, {
62175
+ key: "getAnimationTime",
62176
+ value: function getAnimationTime(id) {
62177
+ const clip = this.getAction(id);
62178
+ if (!clip) return 0;
62179
+ const action = this.mixer.clipAction(clip);
62180
+ return action.time;
62181
+ }
62182
+ /**
62183
+ * Set the current time of an animation
62184
+ * @param {string|number} id - Animation name or index
62185
+ * @param {number} time - Time in seconds
62186
+ */
62187
+
62188
+ }, {
62189
+ key: "setAnimationTime",
62190
+ value: function setAnimationTime(id, time) {
62191
+ const clip = this.getAction(id);
62192
+ if (!clip) return;
62193
+ const action = this.mixer.clipAction(clip);
62194
+ action.time = time;
62195
+ }
62196
+ /**
62197
+ * Check if a specific animation is currently playing
62198
+ * @param {string|number} id - Animation name or index
62199
+ * @returns {boolean}
62200
+ */
62201
+
62202
+ }, {
62203
+ key: "isAnimationPlaying",
62204
+ value: function isAnimationPlaying(id) {
62205
+ const clip = this.getAction(id);
62206
+ if (!clip) return false;
62207
+ const action = this.mixer.clipAction(clip);
62208
+ return action.isRunning();
62209
+ }
62210
+ /**
62211
+ * Get the duration of an animation clip
62212
+ * @param {string|number} id - Animation name or index
62213
+ * @returns {number} Duration in seconds
62214
+ */
62215
+
62216
+ }, {
62217
+ key: "getAnimationDuration",
62218
+ value: function getAnimationDuration(id) {
62219
+ const clip = this.getAction(id);
62220
+ return clip ? clip.duration : 0;
62221
+ }
61957
62222
  }, {
61958
62223
  key: "update",
61959
62224
  value: function update(dt) {
@@ -62398,8 +62663,8 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
62398
62663
  }
62399
62664
  }
62400
62665
  }, {
62401
- key: "stopAnimation",
62402
- value: function stopAnimation() {
62666
+ key: "stopCurrentAnimation",
62667
+ value: function stopCurrentAnimation() {
62403
62668
  if (!this.hasAnimations()) return;
62404
62669
 
62405
62670
  if (this.hasAnimationHandler()) {
@@ -62421,6 +62686,123 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
62421
62686
 
62422
62687
  return [];
62423
62688
  }
62689
+ /**
62690
+ * Crossfade from current animation to a new animation
62691
+ * @param {string|number} id - Target animation name or index
62692
+ * @param {Object} options - Blend options
62693
+ * @param {number} options.blendDuration - Duration of the crossfade (default: 0.3)
62694
+ * @param {number} options.loop - Loop mode (LoopRepeat, LoopOnce)
62695
+ * @param {number} options.timeScale - Playback speed (1 = normal)
62696
+ * @param {boolean} options.warp - Whether to warp time scales during blend
62697
+ */
62698
+
62699
+ }, {
62700
+ key: "crossFadeTo",
62701
+ value: function crossFadeTo(id) {
62702
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
62703
+ if (!this.hasAnimations()) return;
62704
+
62705
+ if (this.hasAnimationHandler()) {
62706
+ return this.animationHandler.crossFadeTo(id, options);
62707
+ } else {
62708
+ console.warn(ANIMATION_HANDLER_NOT_FOUND);
62709
+ }
62710
+ }
62711
+ /**
62712
+ * Stop an animation. If no id is provided, stops the current animation.
62713
+ * @param {string|number} [id] - Animation name or index (optional)
62714
+ * @param {number} fadeOutDuration - Duration to fade out (0 for immediate)
62715
+ */
62716
+
62717
+ }, {
62718
+ key: "stopAnimation",
62719
+ value: function stopAnimation(id) {
62720
+ let fadeOutDuration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
62721
+ if (!this.hasAnimations()) return;
62722
+
62723
+ if (this.hasAnimationHandler()) {
62724
+ // If no id provided, stop the current animation
62725
+ if (id === undefined || id === null) {
62726
+ this.animationHandler.stopCurrentAnimation();
62727
+ } else {
62728
+ this.animationHandler.stopAnimation(id, fadeOutDuration);
62729
+ }
62730
+ } else {
62731
+ console.warn(ANIMATION_HANDLER_NOT_FOUND);
62732
+ }
62733
+ }
62734
+ /**
62735
+ * Set the weight of an animation for layered blending
62736
+ * @param {string|number} id - Animation name or index
62737
+ * @param {number} weight - Weight value (0-1)
62738
+ * @param {number} fadeDuration - Optional fade duration
62739
+ */
62740
+
62741
+ }, {
62742
+ key: "setAnimationWeight",
62743
+ value: function setAnimationWeight(id, weight) {
62744
+ let fadeDuration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
62745
+ if (!this.hasAnimations()) return;
62746
+
62747
+ if (this.hasAnimationHandler()) {
62748
+ this.animationHandler.setAnimationWeight(id, weight, fadeDuration);
62749
+ } else {
62750
+ console.warn(ANIMATION_HANDLER_NOT_FOUND);
62751
+ }
62752
+ }
62753
+ /**
62754
+ * Set the playback speed of an animation
62755
+ * @param {string|number} id - Animation name or index
62756
+ * @param {number} timeScale - Speed multiplier (1 = normal, 2 = double speed)
62757
+ */
62758
+
62759
+ }, {
62760
+ key: "setAnimationTimeScale",
62761
+ value: function setAnimationTimeScale(id, timeScale) {
62762
+ if (!this.hasAnimations()) return;
62763
+
62764
+ if (this.hasAnimationHandler()) {
62765
+ this.animationHandler.setAnimationTimeScale(id, timeScale);
62766
+ } else {
62767
+ console.warn(ANIMATION_HANDLER_NOT_FOUND);
62768
+ }
62769
+ }
62770
+ /**
62771
+ * Get the duration of an animation clip
62772
+ * @param {string|number} id - Animation name or index
62773
+ * @returns {number} Duration in seconds
62774
+ */
62775
+
62776
+ }, {
62777
+ key: "getAnimationDuration",
62778
+ value: function getAnimationDuration(id) {
62779
+ if (!this.hasAnimations()) return 0;
62780
+
62781
+ if (this.hasAnimationHandler()) {
62782
+ return this.animationHandler.getAnimationDuration(id);
62783
+ } else {
62784
+ console.warn(ANIMATION_HANDLER_NOT_FOUND);
62785
+ return 0;
62786
+ }
62787
+ }
62788
+ /**
62789
+ * Check if a specific animation is currently playing
62790
+ * @param {string|number} id - Animation name or index
62791
+ * @returns {boolean}
62792
+ */
62793
+
62794
+ }, {
62795
+ key: "isAnimationPlaying",
62796
+ value: function isAnimationPlaying(id) {
62797
+ if (!this.hasAnimations()) return false;
62798
+
62799
+ if (this.hasAnimationHandler()) {
62800
+ return this.animationHandler.isAnimationPlaying(id);
62801
+ } else {
62802
+ console.warn(ANIMATION_HANDLER_NOT_FOUND);
62803
+ return false;
62804
+ }
62805
+ }
62424
62806
  /**
62425
62807
  * TODO: the entire physics system needs to be a component
62426
62808
  * e.g.
@@ -63152,6 +63534,50 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
63152
63534
 
63153
63535
  Physics$1.disposeElement(this);
63154
63536
  }
63537
+ /**
63538
+ * Serialize only the material properties that the Importer actually uses.
63539
+ * This avoids bloating the JSON with full Three.js material data.
63540
+ */
63541
+
63542
+ }, {
63543
+ key: "serializeMaterialProperties",
63544
+ value: function serializeMaterialProperties() {
63545
+ const materialType = this.getMaterialType(); // Use allowed properties for known material types, or fallback to STANDARD properties
63546
+ // which has the most comprehensive set
63547
+
63548
+ const allowedProperties = MATERIAL_PROPERTIES_MAP[materialType] || MATERIAL_PROPERTIES_MAP[MATERIALS.STANDARD] || [];
63549
+ const materials = this.getMaterials();
63550
+ if (!materials.length) return [];
63551
+ return materials.map(material => {
63552
+ const serialized = {
63553
+ // Always include the material type for the inspector
63554
+ type: material.type
63555
+ };
63556
+
63557
+ for (const prop of allowedProperties) {
63558
+ if (material[prop] !== undefined) {
63559
+ const value = material[prop]; // Serialize Color objects to plain objects
63560
+
63561
+ if (value && value.isColor) {
63562
+ serialized[prop] = {
63563
+ r: value.r,
63564
+ g: value.g,
63565
+ b: value.b
63566
+ };
63567
+ } else if (value && value.isVector2) {
63568
+ serialized[prop] = {
63569
+ x: value.x,
63570
+ y: value.y
63571
+ };
63572
+ } else {
63573
+ serialized[prop] = value;
63574
+ }
63575
+ }
63576
+ }
63577
+
63578
+ return serialized;
63579
+ });
63580
+ }
63155
63581
  }, {
63156
63582
  key: "toJSON",
63157
63583
  value: function toJSON() {
@@ -63160,18 +63586,26 @@ let Element$1 = /*#__PURE__*/function (_Entity) {
63160
63586
  if (this.isSerializable()) {
63161
63587
  const color = this.getColor();
63162
63588
  return { ..._get(_getPrototypeOf(Element.prototype), "toJSON", this).call(this, parseJSON),
63589
+ // Physics options (state is not used by Importer, only options)
63163
63590
  physics: {
63164
- state: serializeMap(this.getPhysicsState()),
63165
63591
  options: this.getPhysicsOptions()
63166
63592
  },
63167
- // body: this.body.toJSON(),
63593
+ // Textures with serialized map
63168
63594
  textures: serializeMap(this.textures),
63595
+ // Material type name (e.g., "STANDARD", "BASIC")
63169
63596
  materialType: this.getMaterialType(),
63170
- materials: this.getMaterials().map(serialiseMaterial),
63171
- // no need to have geometry, for basic entities we can build from the type
63172
- // models have a reference to the model itself
63597
+ // Lightweight material properties (type + allowed properties only)
63598
+ materials: this.serializeMaterialProperties(),
63599
+ // Opacity
63173
63600
  opacity: this.opacity,
63174
- color: parseJSON ? serializeColor(color) : color
63601
+ // Color (for inspector display)
63602
+ color: parseJSON ? {
63603
+ r: color === null || color === void 0 ? void 0 : color.r,
63604
+ g: color === null || color === void 0 ? void 0 : color.g,
63605
+ b: color === null || color === void 0 ? void 0 : color.b
63606
+ } : color,
63607
+ // Animation names (for inspector display - actual animations loaded from model file)
63608
+ animations: this.getAvailableAnimations()
63175
63609
  };
63176
63610
  }
63177
63611
  }
@@ -63356,7 +63790,13 @@ let Sprite = /*#__PURE__*/function (_Element) {
63356
63790
 
63357
63791
  _this.setEntityType(ENTITY_TYPES.HELPER.TYPE);
63358
63792
 
63359
- _this.setEntitySubtype(ENTITY_TYPES.HELPER.SUBTYPES.HELPER_SPRITE);
63793
+ _this.setEntitySubtype(ENTITY_TYPES.HELPER.SUBTYPES.HELPER_SPRITE); // Set to layer 1 ONLY so mirrors don't render helper sprites
63794
+ // Main camera must enable layer 1 to see these
63795
+
63796
+
63797
+ if (_this.hasBody()) {
63798
+ _this.getBody().layers.set(1);
63799
+ }
63360
63800
 
63361
63801
  return _this;
63362
63802
  }
@@ -63464,7 +63904,30 @@ let Sprite = /*#__PURE__*/function (_Element) {
63464
63904
  holderSize = 0.05
63465
63905
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
63466
63906
  // Add THREE.js CameraHelper for visual feedback
63467
- this.helper = new CameraHelper(this.getBody());
63907
+ this.helper = new CameraHelper(this.getBody()); // Set to layer 1 ONLY so mirrors don't render camera helper
63908
+
63909
+ this.helper.layers.set(1); // Disable depth test so helper always renders on top of sky/water
63910
+
63911
+ this.helper.renderOrder = 999; // Helper function to set depth properties on materials
63912
+
63913
+ const setMaterialDepth = material => {
63914
+ if (!material) return;
63915
+ const mats = Array.isArray(material) ? material : [material];
63916
+ mats.forEach(mat => {
63917
+ mat.depthTest = false;
63918
+ mat.depthWrite = false;
63919
+ mat.transparent = true;
63920
+ mat.needsUpdate = true;
63921
+ });
63922
+ };
63923
+
63924
+ setMaterialDepth(this.helper.material); // Also apply to all children
63925
+
63926
+ this.helper.traverse(child => {
63927
+ child.layers.set(1);
63928
+ child.renderOrder = 999;
63929
+ setMaterialDepth(child.material);
63930
+ });
63468
63931
  Scene$1.add(this.helper, null, false); // Add holder sprite for selection
63469
63932
 
63470
63933
  this.addHolder(holderName, holderSize);
@@ -63688,7 +64151,10 @@ let Sprite = /*#__PURE__*/function (_Element) {
63688
64151
  name: generateRandomName("GridHelper")
63689
64152
  };
63690
64153
  _this = _super.call(this, options);
63691
- const body = new GridHelper(size, division, color1, color2);
64154
+ const body = new GridHelper(size, division, color1, color2); // Set to layer 1 ONLY so mirrors don't render the grid
64155
+ // Main camera must enable layer 1 to see the grid
64156
+
64157
+ body.layers.set(1);
63692
64158
 
63693
64159
  _this.setBody({
63694
64160
  body
@@ -81196,6 +81662,10 @@ const glbParser = gltf => {
81196
81662
  if (object.isMesh) {
81197
81663
  object.castShadow = true;
81198
81664
  }
81665
+
81666
+ if (object.isSkinnedMesh) {
81667
+ object.frustumCulled = false;
81668
+ }
81199
81669
  });
81200
81670
  return {
81201
81671
  animations,
@@ -81215,6 +81685,11 @@ const gltfParser = gltf => {
81215
81685
  return null;
81216
81686
  }
81217
81687
 
81688
+ gltf.scene.traverse(node => {
81689
+ if (node.isSkinnedMesh) {
81690
+ node.frustumCulled = false;
81691
+ }
81692
+ });
81218
81693
  return {
81219
81694
  scene: gltf.scene,
81220
81695
  animations: gltf.animations
@@ -81285,6 +81760,7 @@ const fbxParser = scene => {
81285
81760
 
81286
81761
  scene.traverse(node => {
81287
81762
  if (node.isSkinnedMesh) {
81763
+ node.frustumCulled = false;
81288
81764
  processMaterial(node.material, material => material.skinning = true);
81289
81765
  }
81290
81766
  });
@@ -81342,6 +81818,8 @@ let Models = /*#__PURE__*/function (_EventDispatcher) {
81342
81818
  });
81343
81819
 
81344
81820
  _defineProperty$1(_assertThisInitialized(_this), "create", function (name) {
81821
+ var _scene$children, _scene$traverse, _element$getBody;
81822
+
81345
81823
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
81346
81824
  const builtAssetId = buildAssetId(name, _this.currentLevel);
81347
81825
  const modelData = _this.map[name] || _this.map[builtAssetId];
@@ -81355,7 +81833,23 @@ let Models = /*#__PURE__*/function (_EventDispatcher) {
81355
81833
  scene,
81356
81834
  animations,
81357
81835
  extension
81358
- } = modelData; // Validate that scene is a valid THREE.js object with required methods
81836
+ } = modelData; // Debug: Log model structure
81837
+
81838
+ console.log(`[Mage] Creating model "${name}":`, {
81839
+ hasScene: !!scene,
81840
+ sceneType: scene === null || scene === void 0 ? void 0 : scene.type,
81841
+ childrenCount: scene === null || scene === void 0 ? void 0 : (_scene$children = scene.children) === null || _scene$children === void 0 ? void 0 : _scene$children.length,
81842
+ animations: (animations === null || animations === void 0 ? void 0 : animations.length) || 0,
81843
+ extension
81844
+ }); // Debug: Check for meshes in the scene
81845
+
81846
+ let meshCount = 0;
81847
+ let skinnedMeshCount = 0;
81848
+ scene === null || scene === void 0 ? void 0 : (_scene$traverse = scene.traverse) === null || _scene$traverse === void 0 ? void 0 : _scene$traverse.call(scene, node => {
81849
+ if (node.isMesh) meshCount++;
81850
+ if (node.isSkinnedMesh) skinnedMeshCount++;
81851
+ });
81852
+ console.log(`[Mage] Model "${name}" contains: ${meshCount} meshes, ${skinnedMeshCount} skinned meshes`); // Validate that scene is a valid THREE.js object with required methods
81359
81853
 
81360
81854
  if (!scene || typeof scene.clone !== 'function' || typeof scene.traverse !== 'function') {
81361
81855
  console.warn(`[Mage] Model "${name}" has invalid scene object. Got:`, Object.keys(modelData));
@@ -81367,8 +81861,17 @@ let Models = /*#__PURE__*/function (_EventDispatcher) {
81367
81861
  builtAssetId,
81368
81862
  ...options
81369
81863
  };
81370
- let model;
81371
- const useSkeletonClone = extension !== EXTENSIONS.COLLADA && hasAnimations(animations);
81864
+ let model; // Check if the scene contains any skinned meshes
81865
+
81866
+ let hasSkinnedMeshes = false;
81867
+ scene.traverse(node => {
81868
+ if (node.isSkinnedMesh) {
81869
+ hasSkinnedMeshes = true;
81870
+ }
81871
+ }); // Use SkeletonUtils.clone for models with skinned meshes OR animations
81872
+ // Regular clone() doesn't properly handle skeleton binding
81873
+
81874
+ const useSkeletonClone = extension !== EXTENSIONS.COLLADA && (hasAnimations(animations) || hasSkinnedMeshes);
81372
81875
 
81373
81876
  try {
81374
81877
  if (useSkeletonClone) {
@@ -81399,6 +81902,21 @@ let Models = /*#__PURE__*/function (_EventDispatcher) {
81399
81902
 
81400
81903
  if (hasAnimations(animations)) {
81401
81904
  element.addAnimationHandler(animations);
81905
+ } // Debug: Log element body info
81906
+
81907
+
81908
+ const body = (_element$getBody = element.getBody) === null || _element$getBody === void 0 ? void 0 : _element$getBody.call(element);
81909
+
81910
+ if (body) {
81911
+ var _body$position, _body$position$toArra, _body$scale, _body$scale$toArray, _body$children;
81912
+
81913
+ console.log(`[Mage] Element "${name}" body:`, {
81914
+ type: body.type,
81915
+ visible: body.visible,
81916
+ position: (_body$position = body.position) === null || _body$position === void 0 ? void 0 : (_body$position$toArra = _body$position.toArray) === null || _body$position$toArra === void 0 ? void 0 : _body$position$toArra.call(_body$position),
81917
+ scale: (_body$scale = body.scale) === null || _body$scale === void 0 ? void 0 : (_body$scale$toArray = _body$scale.toArray) === null || _body$scale$toArray === void 0 ? void 0 : _body$scale$toArray.call(_body$scale),
81918
+ childrenCount: (_body$children = body.children) === null || _body$children === void 0 ? void 0 : _body$children.length
81919
+ });
81402
81920
  }
81403
81921
 
81404
81922
  return element;
@@ -86800,7 +87318,7 @@ let PixelEffect = /*#__PURE__*/function (_ShaderPass) {
86800
87318
  */
86801
87319
 
86802
87320
  const DEFAULT_THICKNESS = 0.003;
86803
- const DEFAULT_COLOR = 0x000000;
87321
+ const DEFAULT_COLOR$1 = 0x000000;
86804
87322
  const DEFAULT_ALPHA = 1.0;
86805
87323
  const DEFAULT_KEEPALIVE = false;
86806
87324
 
@@ -86808,7 +87326,7 @@ let OutlineEffect = /*#__PURE__*/function () {
86808
87326
  function OutlineEffect(_ref) {
86809
87327
  let {
86810
87328
  defaultThickness = DEFAULT_THICKNESS,
86811
- defaultColor = DEFAULT_COLOR,
87329
+ defaultColor = DEFAULT_COLOR$1,
86812
87330
  defaultAlpha = DEFAULT_ALPHA,
86813
87331
  defaultKeepAlive = DEFAULT_KEEPALIVE
86814
87332
  } = _ref;
@@ -90923,7 +91441,10 @@ var Particles$1 = new Particles();let Orbit = /*#__PURE__*/function (_EventDispa
90923
91441
  object.quaternion.copy(_this._tempQuaternion.setFromAxisAngle(_this.rotationAxis, _this.rotationAngle));
90924
91442
  object.quaternion.multiply(_this._quaternionStart);
90925
91443
  }
90926
- }
91444
+ } // Update skinned mesh skeletons after transform
91445
+
91446
+
91447
+ _this.updateSkinnedMeshSkeletons();
90927
91448
 
90928
91449
  _this.dispatchEvent(_this.changeEvent);
90929
91450
 
@@ -90994,7 +91515,38 @@ var Particles$1 = new Particles();let Orbit = /*#__PURE__*/function (_EventDispa
90994
91515
  _this.domElement = domElement !== undefined ? domElement : document;
90995
91516
  _this.visible = false;
90996
91517
  _this.gizmo = new Gizmo();
90997
- _this.plane = new TransformControlsPlane();
91518
+ _this.plane = new TransformControlsPlane(); // Set gizmo and plane to layer 1 ONLY so mirrors don't render them
91519
+ // Main camera must enable layer 1 to see these
91520
+
91521
+ _this.gizmo.layers.set(1);
91522
+
91523
+ _this.plane.layers.set(1); // Helper function to set depth properties on materials
91524
+
91525
+
91526
+ const setMaterialDepth = material => {
91527
+ if (!material) return;
91528
+ const mats = Array.isArray(material) ? material : [material];
91529
+ mats.forEach(mat => {
91530
+ mat.depthTest = false;
91531
+ mat.depthWrite = false;
91532
+ mat.transparent = true;
91533
+ mat.needsUpdate = true;
91534
+ });
91535
+ }; // Also set layer 1 on all children recursively
91536
+ // Set high renderOrder and disable depthTest so gizmos render on top of sky/water
91537
+
91538
+
91539
+ _this.gizmo.traverse(child => {
91540
+ child.layers.set(1);
91541
+ child.renderOrder = 999;
91542
+ setMaterialDepth(child.material);
91543
+ });
91544
+
91545
+ _this.plane.traverse(child => {
91546
+ child.layers.set(1);
91547
+ child.renderOrder = 999;
91548
+ setMaterialDepth(child.material);
91549
+ });
90998
91550
 
90999
91551
  _this.add(_this.gizmo);
91000
91552
 
@@ -91048,7 +91600,10 @@ var Particles$1 = new Particles();let Orbit = /*#__PURE__*/function (_EventDispa
91048
91600
 
91049
91601
  _this.setAndDispatch("showZ", true);
91050
91602
 
91051
- _this.ray = new Raycaster();
91603
+ _this.ray = new Raycaster(); // Enable layer 1 so raycaster can pick gizmo objects (which are on layer 1)
91604
+
91605
+ _this.ray.layers.enable(1);
91606
+
91052
91607
  _this._tempVector = new Vector3$1();
91053
91608
  _this._tempVector2 = new Vector3$1();
91054
91609
  _this._tempQuaternion = new Quaternion();
@@ -91172,7 +91727,19 @@ var Particles$1 = new Particles();let Orbit = /*#__PURE__*/function (_EventDispa
91172
91727
  value: function attach(element) {
91173
91728
  if (!element) return;
91174
91729
  this.object = element.getBody();
91175
- this.visible = true;
91730
+ this.visible = true; // Force immediate matrix world update to ensure gizmo position is correct
91731
+ // This is especially important for skinned meshes where the matrix may not be current
91732
+
91733
+ if (this.object) {
91734
+ this.object.updateMatrixWorld(true);
91735
+ }
91736
+ } // Update matrix world for skinned meshes after transform changes
91737
+
91738
+ }, {
91739
+ key: "updateSkinnedMeshSkeletons",
91740
+ value: function updateSkinnedMeshSkeletons() {
91741
+ if (!this.object) return;
91742
+ this.object.updateMatrixWorld(true);
91176
91743
  }
91177
91744
  }, {
91178
91745
  key: "detach",
@@ -93015,7 +93582,30 @@ let PointLight$1 = /*#__PURE__*/function (_Light) {
93015
93582
  holderSize = 0.05
93016
93583
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
93017
93584
  this.helper = new PointLightHelper(this.getBody(), 2, GREEN$5);
93018
- this.shadowHelper = new CameraHelper(this.getBody().shadow.camera);
93585
+ this.shadowHelper = new CameraHelper(this.getBody().shadow.camera); // Set to layer 1 ONLY so mirrors don't render light helpers
93586
+ // Disable depth test so helpers always render on top of sky/water
93587
+
93588
+ const setMaterialDepth = material => {
93589
+ if (!material) return;
93590
+ const mats = Array.isArray(material) ? material : [material];
93591
+ mats.forEach(mat => {
93592
+ mat.depthTest = false;
93593
+ mat.depthWrite = false;
93594
+ mat.transparent = true;
93595
+ mat.needsUpdate = true;
93596
+ });
93597
+ };
93598
+
93599
+ [this.helper, this.shadowHelper].forEach(helper => {
93600
+ helper.layers.set(1);
93601
+ helper.renderOrder = 999;
93602
+ setMaterialDepth(helper.material);
93603
+ helper.traverse(child => {
93604
+ child.layers.set(1);
93605
+ child.renderOrder = 999;
93606
+ setMaterialDepth(child.material);
93607
+ });
93608
+ });
93019
93609
  Scene$1.add(this.helper, null, false);
93020
93610
  Scene$1.add(this.shadowHelper, null, false);
93021
93611
  this.addHolder(holderName, holderSize);
@@ -93451,7 +94041,30 @@ let SpotLight$1 = /*#__PURE__*/function (_Light) {
93451
94041
  targetHolderSize = 0.05
93452
94042
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
93453
94043
  this.helper = new SpotLightHelper(this.getBody(), GREEN$4);
93454
- this.shadowHelper = new CameraHelper(this.getBody().shadow.camera);
94044
+ this.shadowHelper = new CameraHelper(this.getBody().shadow.camera); // Set to layer 1 ONLY so mirrors don't render light helpers
94045
+ // Disable depth test so helpers always render on top of sky/water
94046
+
94047
+ const setMaterialDepth = material => {
94048
+ if (!material) return;
94049
+ const mats = Array.isArray(material) ? material : [material];
94050
+ mats.forEach(mat => {
94051
+ mat.depthTest = false;
94052
+ mat.depthWrite = false;
94053
+ mat.transparent = true;
94054
+ mat.needsUpdate = true;
94055
+ });
94056
+ };
94057
+
94058
+ [this.helper, this.shadowHelper].forEach(helper => {
94059
+ helper.layers.set(1);
94060
+ helper.renderOrder = 999;
94061
+ setMaterialDepth(helper.material);
94062
+ helper.traverse(child => {
94063
+ child.layers.set(1);
94064
+ child.renderOrder = 999;
94065
+ setMaterialDepth(child.material);
94066
+ });
94067
+ });
93455
94068
  Scene$1.add(this.helper, null, false);
93456
94069
  Scene$1.add(this.shadowHelper, null, false);
93457
94070
  this.addHolder(holderName, holderSize);
@@ -93899,7 +94512,28 @@ let HemisphereLight$1 = /*#__PURE__*/function (_Light) {
93899
94512
  holderName = "hemispherelightholder",
93900
94513
  holderSize = 0.05
93901
94514
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
93902
- this.helper = new HemisphereLightHelper(this.getBody(), 2, GREEN$3);
94515
+ this.helper = new HemisphereLightHelper(this.getBody(), 2, GREEN$3); // Set to layer 1 ONLY so mirrors don't render light helpers
94516
+ // Disable depth test so helpers always render on top of sky/water
94517
+
94518
+ const setMaterialDepth = material => {
94519
+ if (!material) return;
94520
+ const mats = Array.isArray(material) ? material : [material];
94521
+ mats.forEach(mat => {
94522
+ mat.depthTest = false;
94523
+ mat.depthWrite = false;
94524
+ mat.transparent = true;
94525
+ mat.needsUpdate = true;
94526
+ });
94527
+ };
94528
+
94529
+ this.helper.layers.set(1);
94530
+ this.helper.renderOrder = 999;
94531
+ setMaterialDepth(this.helper.material);
94532
+ this.helper.traverse(child => {
94533
+ child.layers.set(1);
94534
+ child.renderOrder = 999;
94535
+ setMaterialDepth(child.material);
94536
+ });
93903
94537
  this.addHolder(holderName, holderSize);
93904
94538
  this.isUsingHelper = true;
93905
94539
  Scene$1.add(this.helper, null, false);
@@ -94145,7 +94779,30 @@ let SunLight$1 = /*#__PURE__*/function (_Light) {
94145
94779
  targetHolderSize = 0.05
94146
94780
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
94147
94781
  this.helper = new DirectionalLightHelper(this.getBody(), 5);
94148
- this.shadowHelper = new CameraHelper(this.getBody().shadow.camera);
94782
+ this.shadowHelper = new CameraHelper(this.getBody().shadow.camera); // Set to layer 1 ONLY so mirrors don't render light helpers
94783
+ // Disable depth test so helpers always render on top of sky/water
94784
+
94785
+ const setMaterialDepth = material => {
94786
+ if (!material) return;
94787
+ const mats = Array.isArray(material) ? material : [material];
94788
+ mats.forEach(mat => {
94789
+ mat.depthTest = false;
94790
+ mat.depthWrite = false;
94791
+ mat.transparent = true;
94792
+ mat.needsUpdate = true;
94793
+ });
94794
+ };
94795
+
94796
+ [this.helper, this.shadowHelper].forEach(helper => {
94797
+ helper.layers.set(1);
94798
+ helper.renderOrder = 999;
94799
+ setMaterialDepth(helper.material);
94800
+ helper.traverse(child => {
94801
+ child.layers.set(1);
94802
+ child.renderOrder = 999;
94803
+ setMaterialDepth(child.material);
94804
+ });
94805
+ });
94149
94806
  Scene$1.add(this.helper, null, false);
94150
94807
  Scene$1.add(this.shadowHelper, null, false);
94151
94808
  this.addHolder(holderName, holderSize);
@@ -94965,9 +95622,11 @@ let Sky = /*#__PURE__*/function (_Element) {
94965
95622
  fragmentShader: SkyShader.fragmentShader(),
94966
95623
  vertexShader: SkyShader.vertexShader(),
94967
95624
  uniforms: UniformsUtils.clone(SkyShader.uniforms()),
94968
- side: BackSide
95625
+ side: BackSide,
95626
+ depthWrite: false
94969
95627
  });
94970
95628
  const body = new Mesh(new BoxGeometry(1, 1, 1), material);
95629
+ body.renderOrder = -1000;
94971
95630
 
94972
95631
  _this.setBody({
94973
95632
  body
@@ -95026,6 +95685,20 @@ let Sky = /*#__PURE__*/function (_Element) {
95026
95685
  this.setData("mieDirectionalG", value);
95027
95686
  this.getBody().material.uniforms.mieDirectionalG.value = value;
95028
95687
  }
95688
+ }, {
95689
+ key: "setSunInclination",
95690
+ value: function setSunInclination(value) {
95691
+ const azimuth = this.getData("sunAzimuth") || 0.1;
95692
+ const distance = this.getData("sunDistance") || 100;
95693
+ this.setSun(value, azimuth, distance);
95694
+ }
95695
+ }, {
95696
+ key: "setSunAzimuth",
95697
+ value: function setSunAzimuth(value) {
95698
+ const inclination = this.getData("sunInclination") || 0.21;
95699
+ const distance = this.getData("sunDistance") || 100;
95700
+ this.setSun(inclination, value, distance);
95701
+ }
95029
95702
  }, {
95030
95703
  key: "setSun",
95031
95704
  value: function setSun(inclination, azimuth, distance) {
@@ -95049,6 +95722,731 @@ let Sky = /*#__PURE__*/function (_Element) {
95049
95722
  }]);
95050
95723
 
95051
95724
  return Sky;
95725
+ }(Element$1);let Skybox = /*#__PURE__*/function (_Element) {
95726
+ _inherits(Skybox, _Element);
95727
+
95728
+ var _super = _createSuper(Skybox);
95729
+
95730
+ function Skybox(options) {
95731
+ var _this;
95732
+
95733
+ _classCallCheck(this, Skybox);
95734
+
95735
+ const {
95736
+ name = generateRandomName("Skybox"),
95737
+ texture = "skybox",
95738
+ ...rest
95739
+ } = options;
95740
+ _this = _super.call(this, {
95741
+ name,
95742
+ texture,
95743
+ ...rest
95744
+ });
95745
+ _this.cubeMap = typeof texture === "string" ? Images$1.get(texture) : texture;
95746
+ const material = new MeshBasicMaterial({
95747
+ envMap: _this.cubeMap,
95748
+ side: BackSide
95749
+ });
95750
+ const geometry = new BoxGeometry(1000000, 1000000, 1000000);
95751
+
95752
+ _this.setBody({
95753
+ material,
95754
+ geometry
95755
+ });
95756
+
95757
+ _this.setEntityType(ENTITY_TYPES.SCENERY.TYPE);
95758
+
95759
+ _this.setEntitySubtype(ENTITY_TYPES.SCENERY.SUBTYPES.SKYBOX);
95760
+
95761
+ return _this;
95762
+ }
95763
+
95764
+ _createClass(Skybox, null, [{
95765
+ key: "create",
95766
+ value: function create(data) {
95767
+ return new Skybox(data.options || data);
95768
+ }
95769
+ }]);
95770
+
95771
+ return Skybox;
95772
+ }(Element$1);var WaterMesh = function (geometry, options) {
95773
+ Mesh.call(this, geometry);
95774
+ var scope = this;
95775
+ options = options || {};
95776
+ var textureWidth = options.textureWidth !== undefined ? options.textureWidth : 512;
95777
+ var textureHeight = options.textureHeight !== undefined ? options.textureHeight : 512;
95778
+ var clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
95779
+ var alpha = options.alpha !== undefined ? options.alpha : 1.0;
95780
+ var time = options.time !== undefined ? options.time : 0.0;
95781
+ var normalSampler = options.waterNormals !== undefined ? options.waterNormals : null;
95782
+ var sunDirection = options.sunDirection !== undefined ? options.sunDirection : new Vector3$1(0.70707, 0.70707, 0.0);
95783
+ var sunColor = new Color$1(options.sunColor !== undefined ? options.sunColor : 0xffffff);
95784
+ var waterColor = new Color$1(options.waterColor !== undefined ? options.waterColor : 0x7F7F7F);
95785
+ var eye = options.eye !== undefined ? options.eye : new Vector3$1(0, 0, 0);
95786
+ var distortionScale = options.distortionScale !== undefined ? options.distortionScale : 20.0;
95787
+ var side = options.side !== undefined ? options.side : FrontSide;
95788
+ var fog = options.fog !== undefined ? options.fog : false; //
95789
+
95790
+ var mirrorPlane = new Plane$1();
95791
+ var normal = new Vector3$1();
95792
+ var mirrorWorldPosition = new Vector3$1();
95793
+ var cameraWorldPosition = new Vector3$1();
95794
+ var rotationMatrix = new Matrix4();
95795
+ var lookAtPosition = new Vector3$1(0, 0, -1);
95796
+ var clipPlane = new Vector4();
95797
+ var view = new Vector3$1();
95798
+ var target = new Vector3$1();
95799
+ var q = new Vector4();
95800
+ var textureMatrix = new Matrix4();
95801
+ var mirrorCamera = new PerspectiveCamera();
95802
+ var parameters = {
95803
+ minFilter: LinearFilter,
95804
+ magFilter: LinearFilter,
95805
+ format: RGBFormat
95806
+ };
95807
+ var renderTarget = new WebGLRenderTarget(textureWidth, textureHeight, parameters);
95808
+
95809
+ if (!MathUtils.isPowerOfTwo(textureWidth) || !MathUtils.isPowerOfTwo(textureHeight)) {
95810
+ renderTarget.texture.generateMipmaps = false;
95811
+ }
95812
+
95813
+ var mirrorShader = {
95814
+ uniforms: UniformsUtils.merge([UniformsLib['fog'], UniformsLib['lights'], {
95815
+ 'normalSampler': {
95816
+ value: null
95817
+ },
95818
+ 'mirrorSampler': {
95819
+ value: null
95820
+ },
95821
+ 'alpha': {
95822
+ value: 1.0
95823
+ },
95824
+ 'time': {
95825
+ value: 0.0
95826
+ },
95827
+ 'size': {
95828
+ value: 1.0
95829
+ },
95830
+ 'distortionScale': {
95831
+ value: 20.0
95832
+ },
95833
+ 'textureMatrix': {
95834
+ value: new Matrix4()
95835
+ },
95836
+ 'sunColor': {
95837
+ value: new Color$1(0x7F7F7F)
95838
+ },
95839
+ 'sunDirection': {
95840
+ value: new Vector3$1(0.70707, 0.70707, 0)
95841
+ },
95842
+ 'eye': {
95843
+ value: new Vector3$1()
95844
+ },
95845
+ 'waterColor': {
95846
+ value: new Color$1(0x555555)
95847
+ }
95848
+ }]),
95849
+ vertexShader: ['uniform mat4 textureMatrix;', 'uniform float time;', 'varying vec4 mirrorCoord;', 'varying vec4 worldPosition;', '#include <common>', '#include <fog_pars_vertex>', '#include <shadowmap_pars_vertex>', '#include <logdepthbuf_pars_vertex>', 'void main() {', ' mirrorCoord = modelMatrix * vec4( position, 1.0 );', ' worldPosition = mirrorCoord.xyzw;', ' mirrorCoord = textureMatrix * mirrorCoord;', ' vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );', ' gl_Position = projectionMatrix * mvPosition;', '#include <beginnormal_vertex>', '#include <defaultnormal_vertex>', '#include <logdepthbuf_vertex>', '#include <fog_vertex>', '#include <shadowmap_vertex>', '}'].join('\n'),
95850
+ fragmentShader: ['uniform sampler2D mirrorSampler;', 'uniform float alpha;', 'uniform float time;', 'uniform float size;', 'uniform float distortionScale;', 'uniform sampler2D normalSampler;', 'uniform vec3 sunColor;', 'uniform vec3 sunDirection;', 'uniform vec3 eye;', 'uniform vec3 waterColor;', 'varying vec4 mirrorCoord;', 'varying vec4 worldPosition;', 'vec4 getNoise( vec2 uv ) {', ' vec2 uv0 = ( uv / 103.0 ) + vec2(time / 17.0, time / 29.0);', ' vec2 uv1 = uv / 107.0-vec2( time / -19.0, time / 31.0 );', ' vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( time / 101.0, time / 97.0 );', ' vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( time / 109.0, time / -113.0 );', ' vec4 noise = texture2D( normalSampler, uv0 ) +', ' texture2D( normalSampler, uv1 ) +', ' texture2D( normalSampler, uv2 ) +', ' texture2D( normalSampler, uv3 );', ' return noise * 0.5 - 1.0;', '}', 'void sunLight( const vec3 surfaceNormal, const vec3 eyeDirection, float shiny, float spec, float diffuse, inout vec3 diffuseColor, inout vec3 specularColor ) {', ' vec3 reflection = normalize( reflect( -sunDirection, surfaceNormal ) );', ' float direction = max( 0.0, dot( eyeDirection, reflection ) );', ' specularColor += pow( direction, shiny ) * sunColor * spec;', ' diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * sunColor * diffuse;', '}', '#include <common>', '#include <packing>', '#include <bsdfs>', '#include <fog_pars_fragment>', '#include <logdepthbuf_pars_fragment>', '#include <lights_pars_begin>', '#include <shadowmap_pars_fragment>', '#include <shadowmask_pars_fragment>', 'void main() {', '#include <logdepthbuf_fragment>', ' vec4 noise = getNoise( worldPosition.xz * size );', ' vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) );', ' vec3 diffuseLight = vec3(0.0);', ' vec3 specularLight = vec3(0.0);', ' vec3 worldToEye = eye-worldPosition.xyz;', ' vec3 eyeDirection = normalize( worldToEye );', ' sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight );', ' float distance = length(worldToEye);', ' vec2 distortion = surfaceNormal.xz * ( 0.001 + 1.0 / distance ) * distortionScale;', ' vec3 reflectionSample = vec3( texture2D( mirrorSampler, mirrorCoord.xy / mirrorCoord.w + distortion ) );', ' float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 );', ' float rf0 = 0.3;', ' float reflectance = rf0 + ( 1.0 - rf0 ) * pow( ( 1.0 - theta ), 5.0 );', ' vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ) * waterColor;', ' vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), ( vec3( 0.1 ) + reflectionSample * 0.9 + reflectionSample * specularLight ), reflectance);', ' vec3 outgoingLight = albedo;', ' gl_FragColor = vec4( outgoingLight, alpha );', '#include <tonemapping_fragment>', '#include <fog_fragment>', '}'].join('\n')
95851
+ };
95852
+ var material = new ShaderMaterial({
95853
+ fragmentShader: mirrorShader.fragmentShader,
95854
+ vertexShader: mirrorShader.vertexShader,
95855
+ uniforms: UniformsUtils.clone(mirrorShader.uniforms),
95856
+ lights: true,
95857
+ side: side,
95858
+ fog: fog,
95859
+ depthWrite: false // Water should not write to depth buffer so gizmos render on top
95860
+
95861
+ });
95862
+ material.uniforms['mirrorSampler'].value = renderTarget.texture;
95863
+ material.uniforms['textureMatrix'].value = textureMatrix;
95864
+ material.uniforms['alpha'].value = alpha;
95865
+ material.uniforms['time'].value = time;
95866
+ material.uniforms['normalSampler'].value = normalSampler;
95867
+ material.uniforms['sunColor'].value = sunColor;
95868
+ material.uniforms['waterColor'].value = waterColor;
95869
+ material.uniforms['sunDirection'].value = sunDirection;
95870
+ material.uniforms['distortionScale'].value = distortionScale;
95871
+ material.uniforms['eye'].value = eye;
95872
+ scope.material = material;
95873
+
95874
+ scope.onBeforeRender = function (renderer, scene, camera) {
95875
+ mirrorWorldPosition.setFromMatrixPosition(scope.matrixWorld);
95876
+ cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
95877
+ rotationMatrix.extractRotation(scope.matrixWorld);
95878
+ normal.set(0, 0, 1);
95879
+ normal.applyMatrix4(rotationMatrix);
95880
+ view.subVectors(mirrorWorldPosition, cameraWorldPosition); // Avoid rendering when mirror is facing away
95881
+
95882
+ if (view.dot(normal) > 0) return;
95883
+ view.reflect(normal).negate();
95884
+ view.add(mirrorWorldPosition);
95885
+ rotationMatrix.extractRotation(camera.matrixWorld);
95886
+ lookAtPosition.set(0, 0, -1);
95887
+ lookAtPosition.applyMatrix4(rotationMatrix);
95888
+ lookAtPosition.add(cameraWorldPosition);
95889
+ target.subVectors(mirrorWorldPosition, lookAtPosition);
95890
+ target.reflect(normal).negate();
95891
+ target.add(mirrorWorldPosition);
95892
+ mirrorCamera.position.copy(view);
95893
+ mirrorCamera.up.set(0, 1, 0);
95894
+ mirrorCamera.up.applyMatrix4(rotationMatrix);
95895
+ mirrorCamera.up.reflect(normal);
95896
+ mirrorCamera.lookAt(target);
95897
+ mirrorCamera.far = camera.far; // Used in WebGLBackground
95898
+
95899
+ mirrorCamera.updateMatrixWorld();
95900
+ mirrorCamera.projectionMatrix.copy(camera.projectionMatrix); // Update the texture matrix
95901
+
95902
+ textureMatrix.set(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
95903
+ textureMatrix.multiply(mirrorCamera.projectionMatrix);
95904
+ textureMatrix.multiply(mirrorCamera.matrixWorldInverse); // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
95905
+ // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
95906
+
95907
+ mirrorPlane.setFromNormalAndCoplanarPoint(normal, mirrorWorldPosition);
95908
+ mirrorPlane.applyMatrix4(mirrorCamera.matrixWorldInverse);
95909
+ clipPlane.set(mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant);
95910
+ var projectionMatrix = mirrorCamera.projectionMatrix;
95911
+ q.x = (Math.sign(clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
95912
+ q.y = (Math.sign(clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5];
95913
+ q.z = -1.0;
95914
+ q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]; // Calculate the scaled plane vector
95915
+
95916
+ clipPlane.multiplyScalar(2.0 / clipPlane.dot(q)); // Replacing the third row of the projection matrix
95917
+
95918
+ projectionMatrix.elements[2] = clipPlane.x;
95919
+ projectionMatrix.elements[6] = clipPlane.y;
95920
+ projectionMatrix.elements[10] = clipPlane.z + 1.0 - clipBias;
95921
+ projectionMatrix.elements[14] = clipPlane.w;
95922
+ eye.setFromMatrixPosition(camera.matrixWorld); // Render
95923
+
95924
+ if (renderer.outputEncoding !== LinearEncoding) {
95925
+ console.warn('THREE.WaterMesh: WebGLRenderer must use LinearEncoding as outputEncoding.');
95926
+
95927
+ scope.onBeforeRender = function () {};
95928
+
95929
+ return;
95930
+ }
95931
+
95932
+ if (renderer.toneMapping !== NoToneMapping) {
95933
+ console.warn('THREE.WaterMesh: WebGLRenderer must use NoToneMapping as toneMapping.');
95934
+
95935
+ scope.onBeforeRender = function () {};
95936
+
95937
+ return;
95938
+ }
95939
+
95940
+ var currentRenderTarget = renderer.getRenderTarget();
95941
+ var currentXrEnabled = renderer.xr.enabled;
95942
+ var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
95943
+ scope.visible = false;
95944
+ renderer.xr.enabled = false; // Avoid camera modification and recursion
95945
+
95946
+ renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
95947
+
95948
+ renderer.setRenderTarget(renderTarget);
95949
+ renderer.state.buffers.depth.setMask(true); // make sure the depth buffer is writable so it can be properly cleared, see #18897
95950
+
95951
+ if (renderer.autoClear === false) renderer.clear();
95952
+ renderer.render(scene, mirrorCamera);
95953
+ scope.visible = true;
95954
+ renderer.xr.enabled = currentXrEnabled;
95955
+ renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
95956
+ renderer.setRenderTarget(currentRenderTarget); // Restore viewport
95957
+
95958
+ var viewport = camera.viewport;
95959
+
95960
+ if (viewport !== undefined) {
95961
+ renderer.state.viewport(viewport);
95962
+ }
95963
+ };
95964
+ };
95965
+
95966
+ WaterMesh.prototype = Object.create(Mesh.prototype);
95967
+ WaterMesh.prototype.constructor = WaterMesh;
95968
+ const DEFAULT_WATER_HEIGHT = 512;
95969
+ const DEFAULT_WATER_WIDTH = 512;
95970
+ const DEFAULT_WATER_ALPHA = 1.0;
95971
+ const DEFAULT_WATER_DISTORTION_SCALE = 3.7; // Create a simple procedural normal map for water when no texture is available
95972
+
95973
+ const createDefaultWaterNormalTexture = () => {
95974
+ const size = 256;
95975
+ const data = new Uint8Array(size * size * 4);
95976
+
95977
+ for (let i = 0; i < size; i++) {
95978
+ for (let j = 0; j < size; j++) {
95979
+ const idx = (i * size + j) * 4; // Create a subtle wave pattern using sine waves
95980
+
95981
+ const wave1 = Math.sin(i * 0.1) * 0.5 + 0.5;
95982
+ const wave2 = Math.sin(j * 0.1) * 0.5 + 0.5;
95983
+ const wave3 = Math.sin((i + j) * 0.05) * 0.5 + 0.5; // Normal map colors (x, y, z mapped to r, g, b)
95984
+ // Flat normal pointing up is (0.5, 0.5, 1.0) in 0-1 range
95985
+
95986
+ data[idx] = 128 + (wave1 - 0.5) * 20; // R (X normal)
95987
+
95988
+ data[idx + 1] = 128 + (wave2 - 0.5) * 20; // G (Y normal)
95989
+
95990
+ data[idx + 2] = 255 * (0.9 + wave3 * 0.1); // B (Z normal - mostly up)
95991
+
95992
+ data[idx + 3] = 255; // A
95993
+ }
95994
+ }
95995
+
95996
+ const texture = new DataTexture(data, size, size, RGBAFormat, UnsignedByteType);
95997
+ texture.wrapS = texture.wrapT = RepeatWrapping$1;
95998
+ texture.needsUpdate = true;
95999
+ return texture;
96000
+ };
96001
+
96002
+ let Water = /*#__PURE__*/function (_Element) {
96003
+ _inherits(Water, _Element);
96004
+
96005
+ var _super = _createSuper(Water);
96006
+
96007
+ function Water() {
96008
+ var _thisSuper, _this;
96009
+
96010
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
96011
+
96012
+ _classCallCheck(this, Water);
96013
+
96014
+ _this = _super.call(this, options);
96015
+
96016
+ _defineProperty$1(_assertThisInitialized(_this), "update", dt => {
96017
+ _get((_thisSuper = _assertThisInitialized(_this), _getPrototypeOf(Water.prototype)), "update", _thisSuper).call(_thisSuper, dt);
96018
+
96019
+ _this.getBody().material.uniforms.time.value += dt;
96020
+ });
96021
+
96022
+ const {
96023
+ texture,
96024
+ textureNormalName,
96025
+ width = DEFAULT_WATER_WIDTH,
96026
+ height = DEFAULT_WATER_HEIGHT,
96027
+ textureWidth = DEFAULT_WATER_WIDTH,
96028
+ textureHeight = DEFAULT_WATER_HEIGHT,
96029
+ alpha = DEFAULT_WATER_ALPHA,
96030
+ distortionScale = DEFAULT_WATER_DISTORTION_SCALE
96031
+ } = options; // Get water normal texture, falling back to a procedural one if not available
96032
+
96033
+ let waterNormals = texture || Images$1.get(textureNormalName || 'waterNormal');
96034
+
96035
+ if (!waterNormals || waterNormals === false) {
96036
+ waterNormals = createDefaultWaterNormalTexture();
96037
+ } else {
96038
+ waterNormals.wrapS = waterNormals.wrapT = RepeatWrapping$1;
96039
+ }
96040
+
96041
+ const body = new WaterMesh(new PlaneGeometry(width * 500, height * 500), {
96042
+ textureWidth,
96043
+ textureHeight,
96044
+ waterNormals,
96045
+ alpha,
96046
+ sunDirection: new Vector3$1(-0.5773502691896258, 0.5773502691896258, -0.5773502691896258),
96047
+ sunColor: 0xffffff,
96048
+ waterColor: 0x001e0f,
96049
+ distortionScale,
96050
+ fog: Scene$1.getScene().fog !== undefined
96051
+ });
96052
+
96053
+ _this.setBody({
96054
+ body
96055
+ });
96056
+
96057
+ _this.setEntityType(ENTITY_TYPES.SCENERY.TYPE);
96058
+
96059
+ _this.setEntitySubtype(ENTITY_TYPES.SCENERY.SUBTYPES.WATER); // Store original dimensions for scaling calculations
96060
+
96061
+
96062
+ _this.setData("originalWidth", width);
96063
+
96064
+ _this.setData("originalHeight", height);
96065
+
96066
+ _this.setData("width", width);
96067
+
96068
+ _this.setData("height", height);
96069
+
96070
+ _this.setData("alpha", alpha);
96071
+
96072
+ _this.setData("distortionScale", distortionScale);
96073
+
96074
+ _this.setData("waterColor", 0x001e0f);
96075
+
96076
+ _this.setData("sunColor", 0xffffff);
96077
+
96078
+ _this.setData("sunDirection", {
96079
+ x: -0.577,
96080
+ y: 0.577,
96081
+ z: -0.577
96082
+ });
96083
+
96084
+ _this.setRotation({
96085
+ x: -Math.PI / 2
96086
+ });
96087
+
96088
+ return _this;
96089
+ }
96090
+
96091
+ _createClass(Water, [{
96092
+ key: "setSize",
96093
+ value: function setSize(size) {
96094
+ const clampedSize = clamp(size, 0.1, 100);
96095
+ this.setData("size", clampedSize);
96096
+ this.getBody().material.uniforms.size.value = clampedSize;
96097
+ }
96098
+ }, {
96099
+ key: "setAlpha",
96100
+ value: function setAlpha(alpha) {
96101
+ const clampedAlpha = clamp(alpha, 0, 1);
96102
+ this.setData("alpha", clampedAlpha);
96103
+ this.getBody().material.uniforms.alpha.value = clampedAlpha;
96104
+ }
96105
+ }, {
96106
+ key: "setDistortionScale",
96107
+ value: function setDistortionScale(scale) {
96108
+ const clampedScale = clamp(scale, 0, 100);
96109
+ this.setData("distortionScale", clampedScale);
96110
+ this.getBody().material.uniforms.distortionScale.value = clampedScale;
96111
+ }
96112
+ }, {
96113
+ key: "setWaterColor",
96114
+ value: function setWaterColor(color) {
96115
+ this.setData("waterColor", color);
96116
+ const colorValue = typeof color === 'object' && color.hex ? color.hex : color;
96117
+ this.getBody().material.uniforms.waterColor.value.set(colorValue);
96118
+ }
96119
+ }, {
96120
+ key: "setSunColor",
96121
+ value: function setSunColor(color) {
96122
+ this.setData("sunColor", color);
96123
+ const colorValue = typeof color === 'object' && color.hex ? color.hex : color;
96124
+ this.getBody().material.uniforms.sunColor.value.set(colorValue);
96125
+ }
96126
+ }, {
96127
+ key: "setSunDirection",
96128
+ value: function setSunDirection(x, y, z) {
96129
+ this.setData("sunDirection", {
96130
+ x,
96131
+ y,
96132
+ z
96133
+ });
96134
+ this.getBody().material.uniforms.sunDirection.value.set(x, y, z).normalize();
96135
+ }
96136
+ }, {
96137
+ key: "setWidth",
96138
+ value: function setWidth(width) {
96139
+ const clampedWidth = clamp(width, 1, 10000);
96140
+ this.setData("width", clampedWidth);
96141
+
96142
+ this._recreateGeometry();
96143
+ }
96144
+ }, {
96145
+ key: "setHeight",
96146
+ value: function setHeight(height) {
96147
+ const clampedHeight = clamp(height, 1, 10000);
96148
+ this.setData("height", clampedHeight);
96149
+
96150
+ this._recreateGeometry();
96151
+ }
96152
+ }, {
96153
+ key: "_recreateGeometry",
96154
+ value: function _recreateGeometry() {
96155
+ const width = this.getData("width") || 1000;
96156
+ const height = this.getData("height") || 1000; // Dispose old geometry
96157
+
96158
+ if (this.getBody().geometry) {
96159
+ this.getBody().geometry.dispose();
96160
+ } // Create new geometry with updated dimensions
96161
+
96162
+
96163
+ this.getBody().geometry = new PlaneGeometry(width * 500, height * 500);
96164
+ }
96165
+ }], [{
96166
+ key: "create",
96167
+ value: function create(data) {
96168
+ return new Water(data.options || data);
96169
+ }
96170
+ }]);
96171
+
96172
+ return Water;
96173
+ }(Element$1);const DEFAULT_TEXTURE_WIDTH = 512;
96174
+ const DEFAULT_TEXTURE_HEIGHT = 512;
96175
+ const DEFAULT_CLIP_BIAS = 0.003;
96176
+ const DEFAULT_COLOR = 0x7f7f7f;
96177
+ const DEFAULT_WIDTH = 100;
96178
+ const DEFAULT_HEIGHT$1 = 100; // Mirror shader uniforms
96179
+
96180
+ const mirrorUniforms = () => ({
96181
+ "mirrorColor": {
96182
+ type: "c",
96183
+ value: new Color$1(0x7F7F7F)
96184
+ },
96185
+ "mirrorSampler": {
96186
+ type: "t",
96187
+ value: null
96188
+ },
96189
+ "textureMatrix": {
96190
+ type: "m4",
96191
+ value: new Matrix4()
96192
+ }
96193
+ }); // Mirror vertex shader
96194
+
96195
+
96196
+ const mirrorVertexShader = `
96197
+ uniform mat4 textureMatrix;
96198
+ varying vec4 mirrorCoord;
96199
+ void main() {
96200
+ vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
96201
+ vec4 worldPosition = modelMatrix * vec4(position, 1.0);
96202
+ mirrorCoord = textureMatrix * worldPosition;
96203
+ gl_Position = projectionMatrix * mvPosition;
96204
+ }
96205
+ `; // Mirror fragment shader
96206
+
96207
+ const mirrorFragmentShader = `
96208
+ uniform vec3 mirrorColor;
96209
+ uniform sampler2D mirrorSampler;
96210
+ varying vec4 mirrorCoord;
96211
+ float blendOverlay(float base, float blend) {
96212
+ return(base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));
96213
+ }
96214
+ void main() {
96215
+ vec4 color = texture2DProj(mirrorSampler, mirrorCoord);
96216
+ color = vec4(blendOverlay(mirrorColor.r, color.r), blendOverlay(mirrorColor.g, color.g), blendOverlay(mirrorColor.b, color.b), 1.0);
96217
+ gl_FragColor = color;
96218
+ }
96219
+ `;
96220
+ /**
96221
+ * MirrorElement wraps mirror reflection rendering to fit the Entity system.
96222
+ * - Entity lifecycle management (serialization, deserialization)
96223
+ * - Integration with the editor's hierarchy and inspector
96224
+ * - Automatic render loop hook via onBeforeRender
96225
+ */
96226
+
96227
+ let MirrorElement = /*#__PURE__*/function (_Element) {
96228
+ _inherits(MirrorElement, _Element);
96229
+
96230
+ var _super = _createSuper(MirrorElement);
96231
+
96232
+ function MirrorElement() {
96233
+ var _this;
96234
+
96235
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
96236
+
96237
+ _classCallCheck(this, MirrorElement);
96238
+
96239
+ const {
96240
+ name = generateRandomName("Mirror"),
96241
+ textureWidth = DEFAULT_TEXTURE_WIDTH,
96242
+ textureHeight = DEFAULT_TEXTURE_HEIGHT,
96243
+ clipBias = DEFAULT_CLIP_BIAS,
96244
+ color = DEFAULT_COLOR,
96245
+ width = DEFAULT_WIDTH,
96246
+ height = DEFAULT_HEIGHT$1
96247
+ } = options;
96248
+ const cleanedOptions = {
96249
+ textureWidth,
96250
+ textureHeight,
96251
+ clipBias,
96252
+ color,
96253
+ width,
96254
+ height
96255
+ };
96256
+ _this = _super.call(this, {
96257
+ name,
96258
+ ...cleanedOptions
96259
+ }); // Store references
96260
+
96261
+ _this.renderer = Scene$1.getRenderer();
96262
+ _this.clipBias = clipBias;
96263
+ _this.textureWidth = textureWidth;
96264
+ _this.textureHeight = textureHeight; // Create render target for mirror reflection
96265
+
96266
+ const parameters = {
96267
+ minFilter: LinearFilter,
96268
+ magFilter: LinearFilter,
96269
+ format: RGBFormat,
96270
+ stencilBuffer: false
96271
+ };
96272
+ _this.renderTarget = new WebGLRenderTarget(textureWidth, textureHeight, parameters); // Create mirror camera - only renders layer 0, excludes layer 1 (editor-only objects)
96273
+
96274
+ _this.mirrorCamera = new PerspectiveCamera();
96275
+ _this.mirrorCamera.matrixAutoUpdate = true;
96276
+
96277
+ _this.mirrorCamera.layers.set(0); // Only see layer 0
96278
+ // Create mirror material
96279
+
96280
+
96281
+ _this.mirrorMaterial = new ShaderMaterial({
96282
+ fragmentShader: mirrorFragmentShader,
96283
+ vertexShader: mirrorVertexShader,
96284
+ uniforms: UniformsUtils.clone(mirrorUniforms())
96285
+ });
96286
+ _this.mirrorMaterial.uniforms.mirrorSampler.value = _this.renderTarget.texture;
96287
+ _this.mirrorMaterial.uniforms.mirrorColor.value = new Color$1(color); // Reflection calculation helpers
96288
+
96289
+ _this.mirrorPlane = new Plane$1();
96290
+ _this.normal = new Vector3$1(0, 0, 1);
96291
+ _this.mirrorWorldPosition = new Vector3$1();
96292
+ _this.cameraWorldPosition = new Vector3$1();
96293
+ _this.rotationMatrix = new Matrix4();
96294
+ _this.lookAtPosition = new Vector3$1(0, 0, -1);
96295
+ _this.clipPlane = new Vector4();
96296
+ _this.textureMatrix = new Matrix4(); // Create a plane geometry for the mirror surface
96297
+
96298
+ const geometry = new PlaneGeometry(width, height);
96299
+ const body = new Mesh(geometry, _this.mirrorMaterial); // Set mirror to layer 1 ONLY so it doesn't reflect itself
96300
+ // The mirrorCamera only sees layer 0, so it won't render the mirror
96301
+ // Main camera has layer 1 enabled so it can see the mirror
96302
+
96303
+ body.layers.set(1); // Hook mirror rendering into THREE.js render loop
96304
+
96305
+ const self = _assertThisInitialized(_this);
96306
+
96307
+ body.onBeforeRender = function (renderer, scene, camera) {
96308
+ self.renderMirror(renderer, scene, camera, this);
96309
+ };
96310
+
96311
+ _this.setBody({
96312
+ body
96313
+ });
96314
+
96315
+ _this.setEntityType(ENTITY_TYPES.SCENERY.TYPE);
96316
+
96317
+ _this.setEntitySubtype(ENTITY_TYPES.SCENERY.SUBTYPES.MIRROR);
96318
+
96319
+ return _this;
96320
+ }
96321
+
96322
+ _createClass(MirrorElement, [{
96323
+ key: "renderMirror",
96324
+ value: function renderMirror(renderer, scene, camera, mesh) {
96325
+ // Update matrices
96326
+ mesh.updateMatrixWorld();
96327
+ camera.updateMatrixWorld();
96328
+ this.mirrorWorldPosition.setFromMatrixPosition(mesh.matrixWorld);
96329
+ this.cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
96330
+ this.rotationMatrix.extractRotation(mesh.matrixWorld);
96331
+ this.normal.set(0, 0, 1);
96332
+ this.normal.applyMatrix4(this.rotationMatrix);
96333
+ const view = this.mirrorWorldPosition.clone().sub(this.cameraWorldPosition);
96334
+ view.reflect(this.normal).negate();
96335
+ view.add(this.mirrorWorldPosition);
96336
+ this.rotationMatrix.extractRotation(camera.matrixWorld);
96337
+ this.lookAtPosition.set(0, 0, -1);
96338
+ this.lookAtPosition.applyMatrix4(this.rotationMatrix);
96339
+ this.lookAtPosition.add(this.cameraWorldPosition);
96340
+ const target = this.mirrorWorldPosition.clone().sub(this.lookAtPosition);
96341
+ target.reflect(this.normal).negate();
96342
+ target.add(this.mirrorWorldPosition);
96343
+ this.mirrorCamera.position.copy(view);
96344
+ this.mirrorCamera.up.set(0, -1, 0);
96345
+ this.mirrorCamera.up.applyMatrix4(this.rotationMatrix);
96346
+ this.mirrorCamera.up.reflect(this.normal).negate();
96347
+ this.mirrorCamera.lookAt(target);
96348
+ this.mirrorCamera.far = camera.far;
96349
+ this.mirrorCamera.updateProjectionMatrix();
96350
+ this.mirrorCamera.projectionMatrix.copy(camera.projectionMatrix);
96351
+ this.mirrorCamera.updateMatrixWorld();
96352
+ this.mirrorCamera.matrixWorldInverse.copy(this.mirrorCamera.matrixWorld).invert(); // Update the texture matrix
96353
+
96354
+ this.textureMatrix.set(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
96355
+ this.textureMatrix.multiply(this.mirrorCamera.projectionMatrix);
96356
+ this.textureMatrix.multiply(this.mirrorCamera.matrixWorldInverse); // Update clip plane
96357
+
96358
+ this.mirrorPlane.setFromNormalAndCoplanarPoint(this.normal, this.mirrorWorldPosition);
96359
+ this.mirrorPlane.applyMatrix4(this.mirrorCamera.matrixWorldInverse);
96360
+ this.clipPlane.set(this.mirrorPlane.normal.x, this.mirrorPlane.normal.y, this.mirrorPlane.normal.z, this.mirrorPlane.constant);
96361
+ const q = new Vector4();
96362
+ const projectionMatrix = this.mirrorCamera.projectionMatrix;
96363
+ q.x = (Math.sign(this.clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
96364
+ q.y = (Math.sign(this.clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5];
96365
+ q.z = -1.0;
96366
+ q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]; // Calculate the scaled plane vector
96367
+
96368
+ this.clipPlane.multiplyScalar(2.0 / this.clipPlane.dot(q)); // Replacing the third row of the projection matrix
96369
+
96370
+ projectionMatrix.elements[2] = this.clipPlane.x;
96371
+ projectionMatrix.elements[6] = this.clipPlane.y;
96372
+ projectionMatrix.elements[10] = this.clipPlane.z + 1.0 - this.clipBias;
96373
+ projectionMatrix.elements[14] = this.clipPlane.w;
96374
+ this.mirrorMaterial.uniforms.textureMatrix.value = this.textureMatrix; // Render the mirrored scene
96375
+
96376
+ mesh.visible = false;
96377
+ const currentRenderTarget = renderer.getRenderTarget(); // Save current clear color and set to scene background if available
96378
+
96379
+ const currentClearColor = renderer.getClearColor(new Color$1());
96380
+ const currentClearAlpha = renderer.getClearAlpha(); // Use scene background color for mirror clear if available
96381
+
96382
+ if (scene.background && scene.background.isColor) {
96383
+ renderer.setClearColor(scene.background, 1);
96384
+ }
96385
+
96386
+ renderer.setRenderTarget(this.renderTarget);
96387
+ renderer.clear();
96388
+ renderer.render(scene, this.mirrorCamera);
96389
+ renderer.setRenderTarget(currentRenderTarget); // Restore clear color
96390
+
96391
+ renderer.setClearColor(currentClearColor, currentClearAlpha);
96392
+ mesh.visible = true;
96393
+ }
96394
+ /**
96395
+ * Set the mirror color
96396
+ * @param {number|string} color - The color value (hex number or string)
96397
+ */
96398
+
96399
+ }, {
96400
+ key: "setColor",
96401
+ value: function setColor(color) {
96402
+ this.setData("color", color);
96403
+
96404
+ if (this.mirrorMaterial) {
96405
+ this.mirrorMaterial.uniforms.mirrorColor.value.set(color);
96406
+ }
96407
+ }
96408
+ /**
96409
+ * Set the clip bias for the mirror
96410
+ * @param {number} bias - The clip bias value
96411
+ */
96412
+
96413
+ }, {
96414
+ key: "setClipBias",
96415
+ value: function setClipBias(bias) {
96416
+ this.setData("clipBias", bias);
96417
+ this.clipBias = bias;
96418
+ }
96419
+ /**
96420
+ * Dispose the mirror and its resources
96421
+ */
96422
+
96423
+ }, {
96424
+ key: "dispose",
96425
+ value: function dispose() {
96426
+ if (this.renderTarget) {
96427
+ this.renderTarget.dispose();
96428
+ }
96429
+
96430
+ if (this.mirrorMaterial) {
96431
+ this.mirrorMaterial.dispose();
96432
+ }
96433
+
96434
+ _get(_getPrototypeOf(MirrorElement.prototype), "dispose", this).call(this);
96435
+ }
96436
+ /**
96437
+ * Factory method for deserialization
96438
+ * @param {object} data - The serialized data
96439
+ * @returns {MirrorElement} A new MirrorElement instance
96440
+ */
96441
+
96442
+ }], [{
96443
+ key: "create",
96444
+ value: function create(data) {
96445
+ return new MirrorElement(data.options || data);
96446
+ }
96447
+ }]);
96448
+
96449
+ return MirrorElement;
95052
96450
  }(Element$1);let Importer = /*#__PURE__*/function () {
95053
96451
  function Importer() {
95054
96452
  _classCallCheck(this, Importer);
@@ -95300,6 +96698,57 @@ let Sky = /*#__PURE__*/function (_Element) {
95300
96698
  sky.setSun(sunInclination, sunAzimuth, sunDistance);
95301
96699
  }
95302
96700
  }
96701
+ }, {
96702
+ key: "completeSkyboxCreation",
96703
+ value: function completeSkyboxCreation(skybox, skyboxData, options) {
96704
+ Importer.completeCommonCreationSteps(skybox, skyboxData, { ...options,
96705
+ skipScale: true
96706
+ }); // Skybox texture is set during construction via the texture option
96707
+ // No additional setup needed beyond common creation steps
96708
+ }
96709
+ }, {
96710
+ key: "completeWaterCreation",
96711
+ value: function completeWaterCreation(water, waterData, options) {
96712
+ Importer.completeCommonCreationSteps(water, waterData, { ...options,
96713
+ skipScale: true
96714
+ });
96715
+ const waterOptions = waterData.options || {};
96716
+ const {
96717
+ alpha,
96718
+ distortionScale,
96719
+ size
96720
+ } = waterOptions;
96721
+
96722
+ if (alpha !== undefined) {
96723
+ water.setAlpha(alpha);
96724
+ }
96725
+
96726
+ if (distortionScale !== undefined) {
96727
+ water.setDistortionScale(distortionScale);
96728
+ }
96729
+
96730
+ if (size !== undefined) {
96731
+ water.setSize(size);
96732
+ }
96733
+ }
96734
+ }, {
96735
+ key: "completeMirrorCreation",
96736
+ value: function completeMirrorCreation(mirror, mirrorData, options) {
96737
+ Importer.completeCommonCreationSteps(mirror, mirrorData, options);
96738
+ const mirrorOptions = mirrorData.options || {};
96739
+ const {
96740
+ color,
96741
+ clipBias
96742
+ } = mirrorOptions;
96743
+
96744
+ if (color !== undefined) {
96745
+ mirror.setColor(color);
96746
+ }
96747
+
96748
+ if (clipBias !== undefined) {
96749
+ mirror.setClipBias(clipBias);
96750
+ }
96751
+ }
95303
96752
  }, {
95304
96753
  key: "completeSpriteCreation",
95305
96754
  value: async function completeSpriteCreation(sprite, spriteData, options) {
@@ -95398,12 +96847,17 @@ let Sky = /*#__PURE__*/function (_Element) {
95398
96847
 
95399
96848
  for (const cameraData of cameras) {
95400
96849
  if (cameraData.entitySubType === ENTITY_TYPES.CAMERA.SUBTYPES.GAME) {
95401
- // Create a Camera entity that will appear in the hierarchy (for editor)
96850
+ // Use config defaults, but prefer saved values if they're reasonable
96851
+ // (old default was 100, which is too small for most scenes)
96852
+ const configFar = Config$1.camera().far;
96853
+ const savedFar = cameraData.far;
96854
+ const cameraFar = savedFar && savedFar > 100 ? savedFar : configFar; // Create a Camera entity that will appear in the hierarchy (for editor)
96855
+
95402
96856
  const gameCamera = new Camera({
95403
96857
  name: cameraData.name || "Game Camera",
95404
- fov: cameraData.fov || 75,
95405
- near: cameraData.near || 0.1,
95406
- far: cameraData.far || 3000000,
96858
+ fov: cameraData.fov || Config$1.camera().fov,
96859
+ near: cameraData.near || Config$1.camera().near,
96860
+ far: cameraFar,
95407
96861
  serializable: true
95408
96862
  });
95409
96863
  gameCamera.setEntitySubtype(ENTITY_TYPES.CAMERA.SUBTYPES.GAME); // Set position and rotation
@@ -95423,7 +96877,7 @@ let Sky = /*#__PURE__*/function (_Element) {
95423
96877
  if (cameraData.rotation) sceneCamera.setRotation(cameraData.rotation);
95424
96878
  if (cameraData.fov) sceneCamera.setFov(cameraData.fov);
95425
96879
  if (cameraData.near) sceneCamera.setNear(cameraData.near);
95426
- if (cameraData.far) sceneCamera.setFar(cameraData.far);
96880
+ sceneCamera.setFar(cameraFar);
95427
96881
  }
95428
96882
  } // Use for...of to properly await async completeElementCreation calls
95429
96883
 
@@ -95510,6 +96964,18 @@ let Sky = /*#__PURE__*/function (_Element) {
95510
96964
  Importer.completeSkyCreation(Sky.create(elementData), elementData, options);
95511
96965
  break;
95512
96966
 
96967
+ case ENTITY_TYPES.SCENERY.SUBTYPES.SKYBOX:
96968
+ Importer.completeSkyboxCreation(Skybox.create(elementData), elementData, options);
96969
+ break;
96970
+
96971
+ case ENTITY_TYPES.SCENERY.SUBTYPES.WATER:
96972
+ Importer.completeWaterCreation(Water.create(elementData), elementData, options);
96973
+ break;
96974
+
96975
+ case ENTITY_TYPES.SCENERY.SUBTYPES.MIRROR:
96976
+ Importer.completeMirrorCreation(MirrorElement.create(elementData), elementData, options);
96977
+ break;
96978
+
95513
96979
  default:
95514
96980
  console.warn(IMPORTER_ERROR_UNKNOWN_ELEMENT_SUBTYPE, elementData.entitySubType);
95515
96981
  }
@@ -97369,7 +98835,30 @@ let SunLight = /*#__PURE__*/function (_Light) {
97369
98835
  targetHolderSize = 0.05
97370
98836
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
97371
98837
  this.helper = new DirectionalLightHelper(this.getBody(), 5);
97372
- this.shadowHelper = new CameraHelper(this.getBody().shadow.camera);
98838
+ this.shadowHelper = new CameraHelper(this.getBody().shadow.camera); // Set to layer 1 ONLY so mirrors don't render light helpers
98839
+ // Disable depth test so helpers always render on top of sky/water
98840
+
98841
+ const setMaterialDepth = material => {
98842
+ if (!material) return;
98843
+ const mats = Array.isArray(material) ? material : [material];
98844
+ mats.forEach(mat => {
98845
+ mat.depthTest = false;
98846
+ mat.depthWrite = false;
98847
+ mat.transparent = true;
98848
+ mat.needsUpdate = true;
98849
+ });
98850
+ };
98851
+
98852
+ [this.helper, this.shadowHelper].forEach(helper => {
98853
+ helper.layers.set(1);
98854
+ helper.renderOrder = 999;
98855
+ setMaterialDepth(helper.material);
98856
+ helper.traverse(child => {
98857
+ child.layers.set(1);
98858
+ child.renderOrder = 999;
98859
+ setMaterialDepth(child.material);
98860
+ });
98861
+ });
97373
98862
  Scene$1.add(this.helper, null, false);
97374
98863
  Scene$1.add(this.shadowHelper, null, false);
97375
98864
  this.addHolder(holderName, holderSize);
@@ -97630,7 +99119,30 @@ let PointLight = /*#__PURE__*/function (_Light) {
97630
99119
  holderSize = 0.05
97631
99120
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
97632
99121
  this.helper = new PointLightHelper(this.getBody(), 2, GREEN$2);
97633
- this.shadowHelper = new CameraHelper(this.getBody().shadow.camera);
99122
+ this.shadowHelper = new CameraHelper(this.getBody().shadow.camera); // Set to layer 1 ONLY so mirrors don't render light helpers
99123
+ // Disable depth test so helpers always render on top of sky/water
99124
+
99125
+ const setMaterialDepth = material => {
99126
+ if (!material) return;
99127
+ const mats = Array.isArray(material) ? material : [material];
99128
+ mats.forEach(mat => {
99129
+ mat.depthTest = false;
99130
+ mat.depthWrite = false;
99131
+ mat.transparent = true;
99132
+ mat.needsUpdate = true;
99133
+ });
99134
+ };
99135
+
99136
+ [this.helper, this.shadowHelper].forEach(helper => {
99137
+ helper.layers.set(1);
99138
+ helper.renderOrder = 999;
99139
+ setMaterialDepth(helper.material);
99140
+ helper.traverse(child => {
99141
+ child.layers.set(1);
99142
+ child.renderOrder = 999;
99143
+ setMaterialDepth(child.material);
99144
+ });
99145
+ });
97634
99146
  Scene$1.add(this.helper, null, false);
97635
99147
  Scene$1.add(this.shadowHelper, null, false);
97636
99148
  this.addHolder(holderName, holderSize);
@@ -97947,7 +99459,30 @@ let SpotLight = /*#__PURE__*/function (_Light) {
97947
99459
  targetHolderSize = 0.05
97948
99460
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
97949
99461
  this.helper = new SpotLightHelper(this.getBody(), GREEN$1);
97950
- this.shadowHelper = new CameraHelper(this.getBody().shadow.camera);
99462
+ this.shadowHelper = new CameraHelper(this.getBody().shadow.camera); // Set to layer 1 ONLY so mirrors don't render light helpers
99463
+ // Disable depth test so helpers always render on top of sky/water
99464
+
99465
+ const setMaterialDepth = material => {
99466
+ if (!material) return;
99467
+ const mats = Array.isArray(material) ? material : [material];
99468
+ mats.forEach(mat => {
99469
+ mat.depthTest = false;
99470
+ mat.depthWrite = false;
99471
+ mat.transparent = true;
99472
+ mat.needsUpdate = true;
99473
+ });
99474
+ };
99475
+
99476
+ [this.helper, this.shadowHelper].forEach(helper => {
99477
+ helper.layers.set(1);
99478
+ helper.renderOrder = 999;
99479
+ setMaterialDepth(helper.material);
99480
+ helper.traverse(child => {
99481
+ child.layers.set(1);
99482
+ child.renderOrder = 999;
99483
+ setMaterialDepth(child.material);
99484
+ });
99485
+ });
97951
99486
  Scene$1.add(this.helper, null, false);
97952
99487
  Scene$1.add(this.shadowHelper, null, false);
97953
99488
  this.addHolder(holderName, holderSize);
@@ -98143,7 +99678,28 @@ let HemisphereLight = /*#__PURE__*/function (_Light) {
98143
99678
  holderName = "hemispherelightholder",
98144
99679
  holderSize = 0.05
98145
99680
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
98146
- this.helper = new HemisphereLightHelper(this.getBody(), 2, GREEN);
99681
+ this.helper = new HemisphereLightHelper(this.getBody(), 2, GREEN); // Set to layer 1 ONLY so mirrors don't render light helpers
99682
+ // Disable depth test so helpers always render on top of sky/water
99683
+
99684
+ const setMaterialDepth = material => {
99685
+ if (!material) return;
99686
+ const mats = Array.isArray(material) ? material : [material];
99687
+ mats.forEach(mat => {
99688
+ mat.depthTest = false;
99689
+ mat.depthWrite = false;
99690
+ mat.transparent = true;
99691
+ mat.needsUpdate = true;
99692
+ });
99693
+ };
99694
+
99695
+ this.helper.layers.set(1);
99696
+ this.helper.renderOrder = 999;
99697
+ setMaterialDepth(this.helper.material);
99698
+ this.helper.traverse(child => {
99699
+ child.layers.set(1);
99700
+ child.renderOrder = 999;
99701
+ setMaterialDepth(child.material);
99702
+ });
98147
99703
  this.addHolder(holderName, holderSize);
98148
99704
  this.isUsingHelper = true;
98149
99705
  Scene$1.add(this.helper, null, false);
@@ -98235,236 +99791,7 @@ let HemisphereLight = /*#__PURE__*/function (_Light) {
98235
99791
  }]);
98236
99792
 
98237
99793
  return Atmosphere;
98238
- }();let Mirror = /*#__PURE__*/function (_Object3D) {
98239
- _inherits(Mirror, _Object3D);
98240
-
98241
- var _super = _createSuper(Mirror);
98242
-
98243
- _createClass(Mirror, [{
98244
- key: "mirroruniforms",
98245
- value: function mirroruniforms() {
98246
- return {
98247
- "mirrorColor": {
98248
- type: "c",
98249
- value: new Color$1(0x7F7F7F)
98250
- },
98251
- "mirrorSampler": {
98252
- type: "t",
98253
- value: null
98254
- },
98255
- "textureMatrix": {
98256
- type: "m4",
98257
- value: new Matrix4()
98258
- }
98259
- };
98260
- }
98261
- }, {
98262
- key: "mirrorvertex",
98263
- value: function mirrorvertex() {
98264
- return ["uniform mat4 textureMatrix;", "varying vec4 mirrorCoord;", "void main() {", "vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);", "vec4 worldPosition = modelMatrix * vec4(position, 1.0);", "mirrorCoord = textureMatrix * worldPosition;", "gl_Position = projectionMatrix * mvPosition;", "}"].join("\n");
98265
- }
98266
- }, {
98267
- key: "mirrorfragment",
98268
- value: function mirrorfragment() {
98269
- return ["uniform vec3 mirrorColor;", "uniform sampler2D mirrorSampler;", "varying vec4 mirrorCoord;", "float blendOverlay(float base, float blend) {", "return(base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));", "}", "void main() {", "vec4 color = texture2DProj(mirrorSampler, mirrorCoord);", "color = vec4(blendOverlay(mirrorColor.r, color.r), blendOverlay(mirrorColor.g, color.g), blendOverlay(mirrorColor.b, color.b), 1.0);", "gl_FragColor = color;", "}"].join("\n");
98270
- }
98271
- }]);
98272
-
98273
- function Mirror(renderer, camera, scene, options) {
98274
- var _this;
98275
-
98276
- _classCallCheck(this, Mirror);
98277
-
98278
- _this = _super.call(this);
98279
- _this.name = 'mirror_' + _this.id;
98280
- options = options || {};
98281
- _this.matrixNeedsUpdate = true;
98282
- var width = options.textureWidth !== undefined ? options.textureWidth : 512;
98283
- var height = options.textureHeight !== undefined ? options.textureHeight : 512;
98284
- _this.clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
98285
- var mirrorColor = options.color !== undefined ? new Color$1(options.color) : new Color$1(0x7F7F7F);
98286
- _this.renderer = renderer;
98287
- _this.mirrorPlane = new Plane$1();
98288
- _this.normal = new Vector3$1(0, 0, 1);
98289
- _this.mirrorWorldPosition = new Vector3$1();
98290
- _this.cameraWorldPosition = new Vector3$1();
98291
- _this.rotationMatrix = new Matrix4();
98292
- _this.lookAtPosition = new Vector3$1(0, 0, -1);
98293
- _this.clipPlane = new Vector4(); // For debug only, show the normal and plane of the mirror
98294
-
98295
- var debugMode = options.debugMode !== undefined ? options.debugMode : false;
98296
-
98297
- if (debugMode) {
98298
- // var arrow = new ArrowHelper(new Vector3(0, 0, 1), new Vector3(0, 0, 0), 10, 0xffff80);
98299
- // var planeGeometry = new Geometry();
98300
- // planeGeometry.vertices.push(new Vector3(- 10, - 10, 0));
98301
- // planeGeometry.vertices.push(new Vector3(10, - 10, 0));
98302
- // planeGeometry.vertices.push(new Vector3(10, 10, 0));
98303
- // planeGeometry.vertices.push(new Vector3(- 10, 10, 0));
98304
- // planeGeometry.vertices.push(planeGeometry.vertices[ 0 ]);
98305
- // var plane = new Line(planeGeometry, new LineBasicMaterial({ color: 0xffff80 }));
98306
- // this.add(arrow);
98307
- // this.add(plane);
98308
- console.log('[Mage] Mirror is trying to use deprecated geometry.');
98309
- }
98310
-
98311
- if (camera instanceof PerspectiveCamera) {
98312
- _this.camera = camera;
98313
- } else {
98314
- _this.camera = new PerspectiveCamera();
98315
- }
98316
-
98317
- _this.textureMatrix = new Matrix4();
98318
- _this.mirrorCamera = _this.camera.clone();
98319
- _this.mirrorCamera.matrixAutoUpdate = true;
98320
- var parameters = {
98321
- minFilter: LinearFilter,
98322
- magFilter: LinearFilter,
98323
- format: RGBFormat,
98324
- stencilBuffer: false
98325
- };
98326
- _this.renderTarget = new WebGLRenderTarget(width, height, parameters);
98327
- _this.renderTarget2 = new WebGLRenderTarget(width, height, parameters);
98328
- _this.material = new ShaderMaterial({
98329
- fragmentShader: _this.mirrorfragment(),
98330
- vertexShader: _this.mirrorvertex(),
98331
- uniforms: UniformsUtils.clone(_this.mirroruniforms())
98332
- });
98333
- _this.material.uniforms.mirrorSampler.value = _this.renderTarget.texture;
98334
- _this.material.uniforms.mirrorColor.value = mirrorColor;
98335
- _this.material.uniforms.textureMatrix.value = _this.textureMatrix;
98336
-
98337
- if (!MathUtils.isPowerOfTwo(width) || !MathUtils.isPowerOfTwo(height)) {
98338
- _this.renderTarget.texture.generateMipmaps = false;
98339
- _this.renderTarget2.texture.generateMipmaps = false;
98340
- }
98341
-
98342
- _this.updateTextureMatrix();
98343
-
98344
- _this.render();
98345
-
98346
- return _this;
98347
- }
98348
-
98349
- _createClass(Mirror, [{
98350
- key: "renderWithMirror",
98351
- value: function renderWithMirror(otherMirror) {
98352
- // update the mirror matrix to mirror the current view
98353
- this.updateTextureMatrix();
98354
- this.matrixNeedsUpdate = false; // set the camera of the other mirror so the mirrored view is the reference view
98355
-
98356
- var tempCamera = otherMirror.camera;
98357
- otherMirror.camera = this.mirrorCamera; // render the other mirror in temp texture
98358
-
98359
- otherMirror.renderTemp();
98360
- otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget2.texture; // render the current mirror
98361
-
98362
- this.render();
98363
- this.matrixNeedsUpdate = true; // restore material and camera of other mirror
98364
-
98365
- otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget.texture;
98366
- otherMirror.camera = tempCamera; // restore texture matrix of other mirror
98367
-
98368
- otherMirror.updateTextureMatrix();
98369
- }
98370
- }, {
98371
- key: "renderWithMirror",
98372
- value: function renderWithMirror(otherMirror) {
98373
- // update the mirror matrix to mirror the current view
98374
- this.updateTextureMatrix();
98375
- this.matrixNeedsUpdate = false; // set the camera of the other mirror so the mirrored view is the reference view
98376
-
98377
- const tempCamera = otherMirror.camera;
98378
- otherMirror.camera = this.mirrorCamera; // render the other mirror in temp texture
98379
-
98380
- otherMirror.renderTemp();
98381
- otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget2.texture; // render the current mirror
98382
-
98383
- this.render();
98384
- this.matrixNeedsUpdate = true; // restore material and camera of other mirror
98385
-
98386
- otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget.texture;
98387
- otherMirror.camera = tempCamera; // restore texture matrix of other mirror
98388
-
98389
- otherMirror.updateTextureMatrix();
98390
- }
98391
- }, {
98392
- key: "updateTextureMatrix",
98393
- value: function updateTextureMatrix() {
98394
- this.updateMatrixWorld();
98395
- this.camera.updateMatrixWorld();
98396
- this.mirrorWorldPosition.setFromMatrixPosition(this.matrixWorld);
98397
- this.cameraWorldPosition.setFromMatrixPosition(this.camera.matrixWorld);
98398
- this.rotationMatrix.extractRotation(this.matrixWorld);
98399
- this.normal.set(0, 0, 1);
98400
- this.normal.applyMatrix4(this.rotationMatrix);
98401
- var view = this.mirrorWorldPosition.clone().sub(this.cameraWorldPosition);
98402
- view.reflect(this.normal).negate();
98403
- view.add(this.mirrorWorldPosition);
98404
- this.rotationMatrix.extractRotation(this.camera.matrixWorld);
98405
- this.lookAtPosition.set(0, 0, -1);
98406
- this.lookAtPosition.applyMatrix4(this.rotationMatrix);
98407
- this.lookAtPosition.add(this.cameraWorldPosition);
98408
- var target = this.mirrorWorldPosition.clone().sub(this.lookAtPosition);
98409
- target.reflect(this.normal).negate();
98410
- target.add(this.mirrorWorldPosition);
98411
- this.up.set(0, -1, 0);
98412
- this.up.applyMatrix4(this.rotationMatrix);
98413
- this.up.reflect(this.normal).negate();
98414
- this.mirrorCamera.position.copy(view);
98415
- this.mirrorCamera.up = this.up;
98416
- this.mirrorCamera.lookAt(target);
98417
- this.mirrorCamera.updateProjectionMatrix();
98418
- this.mirrorCamera.updateMatrixWorld();
98419
- this.mirrorCamera.matrixWorldInverse.getInverse(this.mirrorCamera.matrixWorld); // Update the texture matrix
98420
-
98421
- this.textureMatrix.set(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
98422
- this.textureMatrix.multiply(this.mirrorCamera.projectionMatrix);
98423
- this.textureMatrix.multiply(this.mirrorCamera.matrixWorldInverse); // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
98424
- // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
98425
-
98426
- this.mirrorPlane.setFromNormalAndCoplanarPoint(this.normal, this.mirrorWorldPosition);
98427
- this.mirrorPlane.applyMatrix4(this.mirrorCamera.matrixWorldInverse);
98428
- this.clipPlane.set(this.mirrorPlane.normal.x, this.mirrorPlane.normal.y, this.mirrorPlane.normal.z, this.mirrorPlane.constant);
98429
- var q = new Vector4();
98430
- var projectionMatrix = this.mirrorCamera.projectionMatrix;
98431
- q.x = (window.Math.sign(this.clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
98432
- q.y = (window.Math.sign(this.clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5];
98433
- q.z = -1.0;
98434
- q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]; // Calculate the scaled plane vector
98435
-
98436
- var c = new Vector4();
98437
- c = this.clipPlane.multiplyScalar(2.0 / this.clipPlane.dot(q)); // Replacing the third row of the projection matrix
98438
-
98439
- projectionMatrix.elements[2] = c.x;
98440
- projectionMatrix.elements[6] = c.y;
98441
- projectionMatrix.elements[10] = c.z + 1.0 - this.clipBias;
98442
- projectionMatrix.elements[14] = c.w;
98443
- }
98444
- }, {
98445
- key: "render",
98446
- value: function render() {
98447
- if (this.matrixNeedsUpdate) this.updateTextureMatrix();
98448
- this.matrixNeedsUpdate = true; // Render the mirrored view of the current scene into the target texture
98449
-
98450
- var scene = this;
98451
-
98452
- while (scene.parent !== null) {
98453
- scene = scene.parent;
98454
- }
98455
-
98456
- if (scene !== undefined && scene instanceof Scene$2) {
98457
- // We can't render ourself to ourself
98458
- var visible = this.material.visible;
98459
- this.material.visible = false;
98460
- this.renderer.render(scene, this.mirrorCamera, this.renderTarget, true);
98461
- this.material.visible = visible;
98462
- }
98463
- }
98464
- }]);
98465
-
98466
- return Mirror;
98467
- }(Object3D);let OceanMain = /*#__PURE__*/function () {
99794
+ }();let OceanMain = /*#__PURE__*/function () {
98468
99795
  function OceanMain() {
98469
99796
  _classCallCheck(this, OceanMain);
98470
99797
  }
@@ -99202,311 +100529,236 @@ let Ocean = /*#__PURE__*/function () {
99202
100529
  }]);
99203
100530
 
99204
100531
  return Ocean;
99205
- }();var WaterMesh = function (geometry, options) {
99206
- Mesh.call(this, geometry);
99207
- var scope = this;
99208
- options = options || {};
99209
- var textureWidth = options.textureWidth !== undefined ? options.textureWidth : 512;
99210
- var textureHeight = options.textureHeight !== undefined ? options.textureHeight : 512;
99211
- var clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
99212
- var alpha = options.alpha !== undefined ? options.alpha : 1.0;
99213
- var time = options.time !== undefined ? options.time : 0.0;
99214
- var normalSampler = options.waterNormals !== undefined ? options.waterNormals : null;
99215
- var sunDirection = options.sunDirection !== undefined ? options.sunDirection : new Vector3$1(0.70707, 0.70707, 0.0);
99216
- var sunColor = new Color$1(options.sunColor !== undefined ? options.sunColor : 0xffffff);
99217
- var waterColor = new Color$1(options.waterColor !== undefined ? options.waterColor : 0x7F7F7F);
99218
- var eye = options.eye !== undefined ? options.eye : new Vector3$1(0, 0, 0);
99219
- var distortionScale = options.distortionScale !== undefined ? options.distortionScale : 20.0;
99220
- var side = options.side !== undefined ? options.side : FrontSide;
99221
- var fog = options.fog !== undefined ? options.fog : false; //
99222
-
99223
- var mirrorPlane = new Plane$1();
99224
- var normal = new Vector3$1();
99225
- var mirrorWorldPosition = new Vector3$1();
99226
- var cameraWorldPosition = new Vector3$1();
99227
- var rotationMatrix = new Matrix4();
99228
- var lookAtPosition = new Vector3$1(0, 0, -1);
99229
- var clipPlane = new Vector4();
99230
- var view = new Vector3$1();
99231
- var target = new Vector3$1();
99232
- var q = new Vector4();
99233
- var textureMatrix = new Matrix4();
99234
- var mirrorCamera = new PerspectiveCamera();
99235
- var parameters = {
99236
- minFilter: LinearFilter,
99237
- magFilter: LinearFilter,
99238
- format: RGBFormat
99239
- };
99240
- var renderTarget = new WebGLRenderTarget(textureWidth, textureHeight, parameters);
99241
-
99242
- if (!MathUtils.isPowerOfTwo(textureWidth) || !MathUtils.isPowerOfTwo(textureHeight)) {
99243
- renderTarget.texture.generateMipmaps = false;
99244
- }
99245
-
99246
- var mirrorShader = {
99247
- uniforms: UniformsUtils.merge([UniformsLib['fog'], UniformsLib['lights'], {
99248
- 'normalSampler': {
99249
- value: null
99250
- },
99251
- 'mirrorSampler': {
99252
- value: null
99253
- },
99254
- 'alpha': {
99255
- value: 1.0
99256
- },
99257
- 'time': {
99258
- value: 0.0
99259
- },
99260
- 'size': {
99261
- value: 1.0
99262
- },
99263
- 'distortionScale': {
99264
- value: 20.0
99265
- },
99266
- 'textureMatrix': {
99267
- value: new Matrix4()
99268
- },
99269
- 'sunColor': {
99270
- value: new Color$1(0x7F7F7F)
99271
- },
99272
- 'sunDirection': {
99273
- value: new Vector3$1(0.70707, 0.70707, 0)
99274
- },
99275
- 'eye': {
99276
- value: new Vector3$1()
99277
- },
99278
- 'waterColor': {
99279
- value: new Color$1(0x555555)
99280
- }
99281
- }]),
99282
- vertexShader: ['uniform mat4 textureMatrix;', 'uniform float time;', 'varying vec4 mirrorCoord;', 'varying vec4 worldPosition;', '#include <common>', '#include <fog_pars_vertex>', '#include <shadowmap_pars_vertex>', '#include <logdepthbuf_pars_vertex>', 'void main() {', ' mirrorCoord = modelMatrix * vec4( position, 1.0 );', ' worldPosition = mirrorCoord.xyzw;', ' mirrorCoord = textureMatrix * mirrorCoord;', ' vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );', ' gl_Position = projectionMatrix * mvPosition;', '#include <beginnormal_vertex>', '#include <defaultnormal_vertex>', '#include <logdepthbuf_vertex>', '#include <fog_vertex>', '#include <shadowmap_vertex>', '}'].join('\n'),
99283
- fragmentShader: ['uniform sampler2D mirrorSampler;', 'uniform float alpha;', 'uniform float time;', 'uniform float size;', 'uniform float distortionScale;', 'uniform sampler2D normalSampler;', 'uniform vec3 sunColor;', 'uniform vec3 sunDirection;', 'uniform vec3 eye;', 'uniform vec3 waterColor;', 'varying vec4 mirrorCoord;', 'varying vec4 worldPosition;', 'vec4 getNoise( vec2 uv ) {', ' vec2 uv0 = ( uv / 103.0 ) + vec2(time / 17.0, time / 29.0);', ' vec2 uv1 = uv / 107.0-vec2( time / -19.0, time / 31.0 );', ' vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( time / 101.0, time / 97.0 );', ' vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( time / 109.0, time / -113.0 );', ' vec4 noise = texture2D( normalSampler, uv0 ) +', ' texture2D( normalSampler, uv1 ) +', ' texture2D( normalSampler, uv2 ) +', ' texture2D( normalSampler, uv3 );', ' return noise * 0.5 - 1.0;', '}', 'void sunLight( const vec3 surfaceNormal, const vec3 eyeDirection, float shiny, float spec, float diffuse, inout vec3 diffuseColor, inout vec3 specularColor ) {', ' vec3 reflection = normalize( reflect( -sunDirection, surfaceNormal ) );', ' float direction = max( 0.0, dot( eyeDirection, reflection ) );', ' specularColor += pow( direction, shiny ) * sunColor * spec;', ' diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * sunColor * diffuse;', '}', '#include <common>', '#include <packing>', '#include <bsdfs>', '#include <fog_pars_fragment>', '#include <logdepthbuf_pars_fragment>', '#include <lights_pars_begin>', '#include <shadowmap_pars_fragment>', '#include <shadowmask_pars_fragment>', 'void main() {', '#include <logdepthbuf_fragment>', ' vec4 noise = getNoise( worldPosition.xz * size );', ' vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) );', ' vec3 diffuseLight = vec3(0.0);', ' vec3 specularLight = vec3(0.0);', ' vec3 worldToEye = eye-worldPosition.xyz;', ' vec3 eyeDirection = normalize( worldToEye );', ' sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight );', ' float distance = length(worldToEye);', ' vec2 distortion = surfaceNormal.xz * ( 0.001 + 1.0 / distance ) * distortionScale;', ' vec3 reflectionSample = vec3( texture2D( mirrorSampler, mirrorCoord.xy / mirrorCoord.w + distortion ) );', ' float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 );', ' float rf0 = 0.3;', ' float reflectance = rf0 + ( 1.0 - rf0 ) * pow( ( 1.0 - theta ), 5.0 );', ' vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ) * waterColor;', ' vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), ( vec3( 0.1 ) + reflectionSample * 0.9 + reflectionSample * specularLight ), reflectance);', ' vec3 outgoingLight = albedo;', ' gl_FragColor = vec4( outgoingLight, alpha );', '#include <tonemapping_fragment>', '#include <fog_fragment>', '}'].join('\n')
99284
- };
99285
- var material = new ShaderMaterial({
99286
- fragmentShader: mirrorShader.fragmentShader,
99287
- vertexShader: mirrorShader.vertexShader,
99288
- uniforms: UniformsUtils.clone(mirrorShader.uniforms),
99289
- lights: true,
99290
- side: side,
99291
- fog: fog
99292
- });
99293
- material.uniforms['mirrorSampler'].value = renderTarget.texture;
99294
- material.uniforms['textureMatrix'].value = textureMatrix;
99295
- material.uniforms['alpha'].value = alpha;
99296
- material.uniforms['time'].value = time;
99297
- material.uniforms['normalSampler'].value = normalSampler;
99298
- material.uniforms['sunColor'].value = sunColor;
99299
- material.uniforms['waterColor'].value = waterColor;
99300
- material.uniforms['sunDirection'].value = sunDirection;
99301
- material.uniforms['distortionScale'].value = distortionScale;
99302
- material.uniforms['eye'].value = eye;
99303
- scope.material = material;
99304
-
99305
- scope.onBeforeRender = function (renderer, scene, camera) {
99306
- mirrorWorldPosition.setFromMatrixPosition(scope.matrixWorld);
99307
- cameraWorldPosition.setFromMatrixPosition(camera.matrixWorld);
99308
- rotationMatrix.extractRotation(scope.matrixWorld);
99309
- normal.set(0, 0, 1);
99310
- normal.applyMatrix4(rotationMatrix);
99311
- view.subVectors(mirrorWorldPosition, cameraWorldPosition); // Avoid rendering when mirror is facing away
99312
-
99313
- if (view.dot(normal) > 0) return;
99314
- view.reflect(normal).negate();
99315
- view.add(mirrorWorldPosition);
99316
- rotationMatrix.extractRotation(camera.matrixWorld);
99317
- lookAtPosition.set(0, 0, -1);
99318
- lookAtPosition.applyMatrix4(rotationMatrix);
99319
- lookAtPosition.add(cameraWorldPosition);
99320
- target.subVectors(mirrorWorldPosition, lookAtPosition);
99321
- target.reflect(normal).negate();
99322
- target.add(mirrorWorldPosition);
99323
- mirrorCamera.position.copy(view);
99324
- mirrorCamera.up.set(0, 1, 0);
99325
- mirrorCamera.up.applyMatrix4(rotationMatrix);
99326
- mirrorCamera.up.reflect(normal);
99327
- mirrorCamera.lookAt(target);
99328
- mirrorCamera.far = camera.far; // Used in WebGLBackground
99329
-
99330
- mirrorCamera.updateMatrixWorld();
99331
- mirrorCamera.projectionMatrix.copy(camera.projectionMatrix); // Update the texture matrix
100532
+ }();let Mirror = /*#__PURE__*/function (_Object3D) {
100533
+ _inherits(Mirror, _Object3D);
99332
100534
 
99333
- textureMatrix.set(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
99334
- textureMatrix.multiply(mirrorCamera.projectionMatrix);
99335
- textureMatrix.multiply(mirrorCamera.matrixWorldInverse); // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
99336
- // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
100535
+ var _super = _createSuper(Mirror);
99337
100536
 
99338
- mirrorPlane.setFromNormalAndCoplanarPoint(normal, mirrorWorldPosition);
99339
- mirrorPlane.applyMatrix4(mirrorCamera.matrixWorldInverse);
99340
- clipPlane.set(mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant);
99341
- var projectionMatrix = mirrorCamera.projectionMatrix;
99342
- q.x = (Math.sign(clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
99343
- q.y = (Math.sign(clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5];
99344
- q.z = -1.0;
99345
- q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]; // Calculate the scaled plane vector
100537
+ _createClass(Mirror, [{
100538
+ key: "mirroruniforms",
100539
+ value: function mirroruniforms() {
100540
+ return {
100541
+ "mirrorColor": {
100542
+ type: "c",
100543
+ value: new Color$1(0x7F7F7F)
100544
+ },
100545
+ "mirrorSampler": {
100546
+ type: "t",
100547
+ value: null
100548
+ },
100549
+ "textureMatrix": {
100550
+ type: "m4",
100551
+ value: new Matrix4()
100552
+ }
100553
+ };
100554
+ }
100555
+ }, {
100556
+ key: "mirrorvertex",
100557
+ value: function mirrorvertex() {
100558
+ return ["uniform mat4 textureMatrix;", "varying vec4 mirrorCoord;", "void main() {", "vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);", "vec4 worldPosition = modelMatrix * vec4(position, 1.0);", "mirrorCoord = textureMatrix * worldPosition;", "gl_Position = projectionMatrix * mvPosition;", "}"].join("\n");
100559
+ }
100560
+ }, {
100561
+ key: "mirrorfragment",
100562
+ value: function mirrorfragment() {
100563
+ return ["uniform vec3 mirrorColor;", "uniform sampler2D mirrorSampler;", "varying vec4 mirrorCoord;", "float blendOverlay(float base, float blend) {", "return(base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));", "}", "void main() {", "vec4 color = texture2DProj(mirrorSampler, mirrorCoord);", "color = vec4(blendOverlay(mirrorColor.r, color.r), blendOverlay(mirrorColor.g, color.g), blendOverlay(mirrorColor.b, color.b), 1.0);", "gl_FragColor = color;", "}"].join("\n");
100564
+ }
100565
+ }]);
99346
100566
 
99347
- clipPlane.multiplyScalar(2.0 / clipPlane.dot(q)); // Replacing the third row of the projection matrix
100567
+ function Mirror(renderer, camera, scene, options) {
100568
+ var _this;
99348
100569
 
99349
- projectionMatrix.elements[2] = clipPlane.x;
99350
- projectionMatrix.elements[6] = clipPlane.y;
99351
- projectionMatrix.elements[10] = clipPlane.z + 1.0 - clipBias;
99352
- projectionMatrix.elements[14] = clipPlane.w;
99353
- eye.setFromMatrixPosition(camera.matrixWorld); // Render
100570
+ _classCallCheck(this, Mirror);
99354
100571
 
99355
- if (renderer.outputEncoding !== LinearEncoding) {
99356
- console.warn('THREE.WaterMesh: WebGLRenderer must use LinearEncoding as outputEncoding.');
100572
+ _this = _super.call(this);
100573
+ _this.name = 'mirror_' + _this.id;
100574
+ options = options || {};
100575
+ _this.matrixNeedsUpdate = true;
100576
+ var width = options.textureWidth !== undefined ? options.textureWidth : 512;
100577
+ var height = options.textureHeight !== undefined ? options.textureHeight : 512;
100578
+ _this.clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
100579
+ var mirrorColor = options.color !== undefined ? new Color$1(options.color) : new Color$1(0x7F7F7F);
100580
+ _this.renderer = renderer;
100581
+ _this.mirrorPlane = new Plane$1();
100582
+ _this.normal = new Vector3$1(0, 0, 1);
100583
+ _this.mirrorWorldPosition = new Vector3$1();
100584
+ _this.cameraWorldPosition = new Vector3$1();
100585
+ _this.rotationMatrix = new Matrix4();
100586
+ _this.lookAtPosition = new Vector3$1(0, 0, -1);
100587
+ _this.clipPlane = new Vector4(); // For debug only, show the normal and plane of the mirror
99357
100588
 
99358
- scope.onBeforeRender = function () {};
100589
+ var debugMode = options.debugMode !== undefined ? options.debugMode : false;
99359
100590
 
99360
- return;
100591
+ if (debugMode) {
100592
+ // var arrow = new ArrowHelper(new Vector3(0, 0, 1), new Vector3(0, 0, 0), 10, 0xffff80);
100593
+ // var planeGeometry = new Geometry();
100594
+ // planeGeometry.vertices.push(new Vector3(- 10, - 10, 0));
100595
+ // planeGeometry.vertices.push(new Vector3(10, - 10, 0));
100596
+ // planeGeometry.vertices.push(new Vector3(10, 10, 0));
100597
+ // planeGeometry.vertices.push(new Vector3(- 10, 10, 0));
100598
+ // planeGeometry.vertices.push(planeGeometry.vertices[ 0 ]);
100599
+ // var plane = new Line(planeGeometry, new LineBasicMaterial({ color: 0xffff80 }));
100600
+ // this.add(arrow);
100601
+ // this.add(plane);
100602
+ console.log('[Mage] Mirror is trying to use deprecated geometry.');
99361
100603
  }
99362
100604
 
99363
- if (renderer.toneMapping !== NoToneMapping) {
99364
- console.warn('THREE.WaterMesh: WebGLRenderer must use NoToneMapping as toneMapping.');
99365
-
99366
- scope.onBeforeRender = function () {};
99367
-
99368
- return;
100605
+ if (camera instanceof PerspectiveCamera) {
100606
+ _this.camera = camera;
100607
+ } else {
100608
+ _this.camera = new PerspectiveCamera();
99369
100609
  }
99370
100610
 
99371
- var currentRenderTarget = renderer.getRenderTarget();
99372
- var currentXrEnabled = renderer.xr.enabled;
99373
- var currentShadowAutoUpdate = renderer.shadowMap.autoUpdate;
99374
- scope.visible = false;
99375
- renderer.xr.enabled = false; // Avoid camera modification and recursion
99376
-
99377
- renderer.shadowMap.autoUpdate = false; // Avoid re-computing shadows
99378
-
99379
- renderer.setRenderTarget(renderTarget);
99380
- renderer.state.buffers.depth.setMask(true); // make sure the depth buffer is writable so it can be properly cleared, see #18897
99381
-
99382
- if (renderer.autoClear === false) renderer.clear();
99383
- renderer.render(scene, mirrorCamera);
99384
- scope.visible = true;
99385
- renderer.xr.enabled = currentXrEnabled;
99386
- renderer.shadowMap.autoUpdate = currentShadowAutoUpdate;
99387
- renderer.setRenderTarget(currentRenderTarget); // Restore viewport
99388
-
99389
- var viewport = camera.viewport;
100611
+ _this.textureMatrix = new Matrix4();
100612
+ _this.mirrorCamera = _this.camera.clone();
100613
+ _this.mirrorCamera.matrixAutoUpdate = true;
100614
+ var parameters = {
100615
+ minFilter: LinearFilter,
100616
+ magFilter: LinearFilter,
100617
+ format: RGBFormat,
100618
+ stencilBuffer: false
100619
+ };
100620
+ _this.renderTarget = new WebGLRenderTarget(width, height, parameters);
100621
+ _this.renderTarget2 = new WebGLRenderTarget(width, height, parameters);
100622
+ _this.material = new ShaderMaterial({
100623
+ fragmentShader: _this.mirrorfragment(),
100624
+ vertexShader: _this.mirrorvertex(),
100625
+ uniforms: UniformsUtils.clone(_this.mirroruniforms())
100626
+ });
100627
+ _this.material.uniforms.mirrorSampler.value = _this.renderTarget.texture;
100628
+ _this.material.uniforms.mirrorColor.value = mirrorColor;
100629
+ _this.material.uniforms.textureMatrix.value = _this.textureMatrix;
99390
100630
 
99391
- if (viewport !== undefined) {
99392
- renderer.state.viewport(viewport);
100631
+ if (!MathUtils.isPowerOfTwo(width) || !MathUtils.isPowerOfTwo(height)) {
100632
+ _this.renderTarget.texture.generateMipmaps = false;
100633
+ _this.renderTarget2.texture.generateMipmaps = false;
99393
100634
  }
99394
- };
99395
- };
99396
-
99397
- WaterMesh.prototype = Object.create(Mesh.prototype);
99398
- WaterMesh.prototype.constructor = WaterMesh;
99399
- const DEFAULT_WATER_HEIGHT = 512;
99400
- const DEFAULT_WATER_WIDTH = 512;
99401
- const DEFAULT_WATER_ALPHA = 1.0;
99402
- const DEFAULT_WATER_DISTORTION_SCALE = 3.7;
99403
100635
 
99404
- let Water = /*#__PURE__*/function (_Element) {
99405
- _inherits(Water, _Element);
100636
+ _this.updateTextureMatrix();
99406
100637
 
99407
- var _super = _createSuper(Water);
100638
+ _this.render();
99408
100639
 
99409
- function Water() {
99410
- var _thisSuper, _this;
100640
+ return _this;
100641
+ }
99411
100642
 
99412
- let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
100643
+ _createClass(Mirror, [{
100644
+ key: "renderWithMirror",
100645
+ value: function renderWithMirror(otherMirror) {
100646
+ // update the mirror matrix to mirror the current view
100647
+ this.updateTextureMatrix();
100648
+ this.matrixNeedsUpdate = false; // set the camera of the other mirror so the mirrored view is the reference view
99413
100649
 
99414
- _classCallCheck(this, Water);
100650
+ var tempCamera = otherMirror.camera;
100651
+ otherMirror.camera = this.mirrorCamera; // render the other mirror in temp texture
99415
100652
 
99416
- _this = _super.call(this, options);
100653
+ otherMirror.renderTemp();
100654
+ otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget2.texture; // render the current mirror
99417
100655
 
99418
- _defineProperty$1(_assertThisInitialized(_this), "update", dt => {
99419
- _get((_thisSuper = _assertThisInitialized(_this), _getPrototypeOf(Water.prototype)), "update", _thisSuper).call(_thisSuper, dt);
100656
+ this.render();
100657
+ this.matrixNeedsUpdate = true; // restore material and camera of other mirror
99420
100658
 
99421
- _this.getBody().material.uniforms.time.value += dt; //1.0 / 60.0;
99422
- });
100659
+ otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget.texture;
100660
+ otherMirror.camera = tempCamera; // restore texture matrix of other mirror
99423
100661
 
99424
- const {
99425
- texture,
99426
- textureNormalName,
99427
- width = DEFAULT_WATER_WIDTH,
99428
- height = DEFAULT_WATER_HEIGHT,
99429
- textureWidth = DEFAULT_WATER_WIDTH,
99430
- textureHeight = DEFAULT_WATER_HEIGHT,
99431
- alpha = DEFAULT_WATER_ALPHA,
99432
- distortionScale = DEFAULT_WATER_DISTORTION_SCALE
99433
- } = options;
99434
- const waterNormals = texture || Images$1.get(textureNormalName || 'waterNormal');
99435
- waterNormals.wrapS = waterNormals.wrapT = RepeatWrapping$1;
99436
- const body = new WaterMesh(new PlaneGeometry(width * 500, height * 500), {
99437
- textureWidth,
99438
- textureHeight,
99439
- waterNormals,
99440
- alpha,
99441
- sunDirection: new Vector3$1(-0.5773502691896258, 0.5773502691896258, -0.5773502691896258),
99442
- sunColor: 0xffffff,
99443
- waterColor: 0x001e0f,
99444
- distortionScale,
99445
- fog: Scene$1.getScene().fog !== undefined
99446
- });
100662
+ otherMirror.updateTextureMatrix();
100663
+ }
100664
+ }, {
100665
+ key: "renderWithMirror",
100666
+ value: function renderWithMirror(otherMirror) {
100667
+ // update the mirror matrix to mirror the current view
100668
+ this.updateTextureMatrix();
100669
+ this.matrixNeedsUpdate = false; // set the camera of the other mirror so the mirrored view is the reference view
99447
100670
 
99448
- _this.setBody({
99449
- body
99450
- });
100671
+ const tempCamera = otherMirror.camera;
100672
+ otherMirror.camera = this.mirrorCamera; // render the other mirror in temp texture
99451
100673
 
99452
- _this.setEntityType(ENTITY_TYPES.MESH);
100674
+ otherMirror.renderTemp();
100675
+ otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget2.texture; // render the current mirror
99453
100676
 
99454
- _this.setRotation({
99455
- x: -Math.PI / 2
99456
- });
100677
+ this.render();
100678
+ this.matrixNeedsUpdate = true; // restore material and camera of other mirror
99457
100679
 
99458
- return _this;
99459
- }
100680
+ otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget.texture;
100681
+ otherMirror.camera = tempCamera; // restore texture matrix of other mirror
99460
100682
 
99461
- _createClass(Water, [{
99462
- key: "setSize",
99463
- value: function setSize(size) {
99464
- this.getBody().material.uniforms.size.value = clamp(size, 0.1, 100);
100683
+ otherMirror.updateTextureMatrix();
99465
100684
  }
99466
- }]);
99467
-
99468
- return Water;
99469
- }(Element$1);let Skybox = /*#__PURE__*/function (_Element) {
99470
- _inherits(Skybox, _Element);
99471
-
99472
- var _super = _createSuper(Skybox);
100685
+ }, {
100686
+ key: "updateTextureMatrix",
100687
+ value: function updateTextureMatrix() {
100688
+ this.updateMatrixWorld();
100689
+ this.camera.updateMatrixWorld();
100690
+ this.mirrorWorldPosition.setFromMatrixPosition(this.matrixWorld);
100691
+ this.cameraWorldPosition.setFromMatrixPosition(this.camera.matrixWorld);
100692
+ this.rotationMatrix.extractRotation(this.matrixWorld);
100693
+ this.normal.set(0, 0, 1);
100694
+ this.normal.applyMatrix4(this.rotationMatrix);
100695
+ var view = this.mirrorWorldPosition.clone().sub(this.cameraWorldPosition);
100696
+ view.reflect(this.normal).negate();
100697
+ view.add(this.mirrorWorldPosition);
100698
+ this.rotationMatrix.extractRotation(this.camera.matrixWorld);
100699
+ this.lookAtPosition.set(0, 0, -1);
100700
+ this.lookAtPosition.applyMatrix4(this.rotationMatrix);
100701
+ this.lookAtPosition.add(this.cameraWorldPosition);
100702
+ var target = this.mirrorWorldPosition.clone().sub(this.lookAtPosition);
100703
+ target.reflect(this.normal).negate();
100704
+ target.add(this.mirrorWorldPosition);
100705
+ this.up.set(0, -1, 0);
100706
+ this.up.applyMatrix4(this.rotationMatrix);
100707
+ this.up.reflect(this.normal).negate();
100708
+ this.mirrorCamera.position.copy(view);
100709
+ this.mirrorCamera.up = this.up;
100710
+ this.mirrorCamera.lookAt(target);
100711
+ this.mirrorCamera.updateProjectionMatrix();
100712
+ this.mirrorCamera.updateMatrixWorld();
100713
+ this.mirrorCamera.matrixWorldInverse.getInverse(this.mirrorCamera.matrixWorld); // Update the texture matrix
99473
100714
 
99474
- function Skybox(options) {
99475
- var _this;
100715
+ this.textureMatrix.set(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0);
100716
+ this.textureMatrix.multiply(this.mirrorCamera.projectionMatrix);
100717
+ this.textureMatrix.multiply(this.mirrorCamera.matrixWorldInverse); // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
100718
+ // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
99476
100719
 
99477
- _classCallCheck(this, Skybox);
100720
+ this.mirrorPlane.setFromNormalAndCoplanarPoint(this.normal, this.mirrorWorldPosition);
100721
+ this.mirrorPlane.applyMatrix4(this.mirrorCamera.matrixWorldInverse);
100722
+ this.clipPlane.set(this.mirrorPlane.normal.x, this.mirrorPlane.normal.y, this.mirrorPlane.normal.z, this.mirrorPlane.constant);
100723
+ var q = new Vector4();
100724
+ var projectionMatrix = this.mirrorCamera.projectionMatrix;
100725
+ q.x = (window.Math.sign(this.clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0];
100726
+ q.y = (window.Math.sign(this.clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5];
100727
+ q.z = -1.0;
100728
+ q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]; // Calculate the scaled plane vector
99478
100729
 
99479
- const {
99480
- name = generateRandomName("Skybox"),
99481
- texture = "skybox",
99482
- ...rest
99483
- } = options;
99484
- _this = _super.call(this, {
99485
- name,
99486
- texture,
99487
- ...rest
99488
- });
99489
- _this.cubeMap = typeof texture === "string" ? Images$1.get(texture) : texture;
99490
- const material = new MeshBasicMaterial({
99491
- envMap: _this.cubeMap,
99492
- side: BackSide
99493
- });
99494
- const geometry = new BoxGeometry(1000000, 1000000, 1000000);
100730
+ var c = new Vector4();
100731
+ c = this.clipPlane.multiplyScalar(2.0 / this.clipPlane.dot(q)); // Replacing the third row of the projection matrix
99495
100732
 
99496
- _this.setBody({
99497
- material,
99498
- geometry
99499
- });
100733
+ projectionMatrix.elements[2] = c.x;
100734
+ projectionMatrix.elements[6] = c.y;
100735
+ projectionMatrix.elements[10] = c.z + 1.0 - this.clipBias;
100736
+ projectionMatrix.elements[14] = c.w;
100737
+ }
100738
+ }, {
100739
+ key: "render",
100740
+ value: function render() {
100741
+ if (this.matrixNeedsUpdate) this.updateTextureMatrix();
100742
+ this.matrixNeedsUpdate = true; // Render the mirrored view of the current scene into the target texture
99500
100743
 
99501
- _this.setEntityType(ENTITY_TYPES.SCENERY.TYPE);
100744
+ var scene = this;
99502
100745
 
99503
- _this.setEntitySubtype(ENTITY_TYPES.SCENERY.SUBTYPES.SKYBOX);
100746
+ while (scene.parent !== null) {
100747
+ scene = scene.parent;
100748
+ }
99504
100749
 
99505
- return _this;
99506
- }
100750
+ if (scene !== undefined && scene instanceof Scene$2) {
100751
+ // We can't render ourself to ourself
100752
+ var visible = this.material.visible;
100753
+ this.material.visible = false;
100754
+ this.renderer.render(scene, this.mirrorCamera, this.renderTarget, true);
100755
+ this.material.visible = visible;
100756
+ }
100757
+ }
100758
+ }]);
99507
100759
 
99508
- return Skybox;
99509
- }(Element$1);let Shaders = /*#__PURE__*/function () {
100760
+ return Mirror;
100761
+ }(Object3D);let Shaders = /*#__PURE__*/function () {
99510
100762
  function Shaders() {
99511
100763
  _classCallCheck(this, Shaders);
99512
100764
 
@@ -99584,4 +100836,4 @@ var Shaders$1 = new Shaders();let Shader = function Shader(name, attributes, uni
99584
100836
  ...light_contants,
99585
100837
  ...material_constants,
99586
100838
  ...controls_contants
99587
- };export{AUDIO_RAMPS,AmbientLight,AmbientSound,Atmosphere,Audio$1 as Audio,Axes,BUILTIN,BaseScript,Box,CONTROL_EVENTS,Camera,Color,Cone,Config$1 as Config,Controls$1 as Controls,Cube,CurveLine,Cylinder,DirectionalSound,ENTITY_EVENTS,ENTITY_TYPES,Element$1 as Element,Entity,EventDispatcher,Explosion,Exporter,FEATURES,Features$1 as Features,Fire,Fountain,GameRunner$1 as GameRunner,Grid,HelperSprite,HemisphereLight,INPUT_EVENTS,Images$1 as Images,Importer,Input$1 as Input,Label,LabelComponent,Level,Lights$1 as Lights,Line,Mirror,Models$1 as Models,Ocean,PALETTES,PARTICLES,PHYSICS_CONSTANTS,PHYSICS_EVENTS,ParticleEmitter,ParticleEmitterGroup,Particles$1 as Particles,Physics$1 as Physics,Plane,PointLight,PostProcessing$1 as PostProcessing,Proton,ProtonParticleEmitter,Provider,Rain,Router$1 as Router,Scene$1 as Scene,Scripts$1 as Scripts,Shader,Sky,Skybox,Snow,Sound,Sphere,SpotLight,Sprite,Stats$1 as Stats,SunLight,three_module as THREE,THREEJS_CONTROL_EVENTS,Trail,Universe$1 as Universe,Vector3$1 as Vector3,Water,author,connect,constants,createElement,easing,functions,hitbox as hitboxUtils,index_esm as inferno,map$1 as map,math,object,physicsUtils,index$1 as rxjs,index as store,strings,uuid$1 as uuid,workers,index$2 as xstate};
100839
+ };export{AUDIO_RAMPS,AmbientLight,AmbientSound,Atmosphere,Audio$1 as Audio,Axes,BUILTIN,BaseScript,Box,CONTROL_EVENTS,Camera,Color,Cone,Config$1 as Config,Controls$1 as Controls,Cube,CurveLine,Cylinder,DirectionalSound,ENTITY_EVENTS,ENTITY_TYPES,Element$1 as Element,Entity,EventDispatcher,Explosion,Exporter,FEATURES,Features$1 as Features,Fire,Fountain,GameRunner$1 as GameRunner,Grid,HelperSprite,HemisphereLight,INPUT_EVENTS,Images$1 as Images,Importer,Input$1 as Input,Label,LabelComponent,Level,Lights$1 as Lights,Line,MirrorElement as Mirror,Models$1 as Models,Ocean,PALETTES,PARTICLES,PHYSICS_CONSTANTS,PHYSICS_EVENTS,ParticleEmitter,ParticleEmitterGroup,Particles$1 as Particles,Physics$1 as Physics,Plane,PointLight,PostProcessing$1 as PostProcessing,Proton,ProtonParticleEmitter,Provider,Rain,Router$1 as Router,Scene$1 as Scene,Scripts$1 as Scripts,Shader,Sky,Skybox,Snow,Sound,Sphere,SpotLight,Sprite,Stats$1 as Stats,SunLight,three_module as THREE,THREEJS_CONTROL_EVENTS,Trail,Universe$1 as Universe,Vector3$1 as Vector3,Water,author,connect,constants,createElement,easing,functions,hitbox as hitboxUtils,index_esm as inferno,map$1 as map,math,object,physicsUtils,index$1 as rxjs,index as store,strings,uuid$1 as uuid,workers,index$2 as xstate};