lythreeframe 1.2.51 → 1.2.53

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.
@@ -1,4 +1,4 @@
1
- import { MathUtils, Object3D, Vector3, Box3, Quaternion, Euler, Matrix4, Mesh, LoadingManager, BufferGeometry, Texture, FileLoader, Material, NearestFilter, WebGPURenderer, PostProcessing, Color, Vector2, Raycaster, OrthographicCamera, PerspectiveCamera, Clock, DirectionalLight, AmbientLight, MeshStandardMaterial, BoxGeometry, MeshBasicMaterial, PlaneGeometry, SphereGeometry } from 'three/webgpu';
1
+ import { MathUtils, Object3D, Vector3, Box3, Quaternion, Euler, Matrix4, Mesh, LoadingManager, BufferGeometry, Texture, FileLoader, Material, NearestFilter, PostProcessing, Color, WebGPURenderer, Vector2, Raycaster, OrthographicCamera, PerspectiveCamera, Clock, DirectionalLight, AmbientLight, MeshStandardMaterial, BoxGeometry, MeshBasicMaterial, PlaneGeometry, SphereGeometry } from 'three/webgpu';
2
2
  import { GLTFLoader, DRACOLoader, CSS2DRenderer, OrbitControls } from 'three/examples/jsm/Addons.js';
3
3
  import { pass, mrt, output, uniform, metalness, transformedNormalView, time, oscSine } from 'three/tsl';
4
4
  import { dof } from 'three/addons/tsl/display/DepthOfFieldNode.js';
@@ -892,32 +892,48 @@ class TSmartPointer {
892
892
  getRefCount() {
893
893
  return this.referenceCount;
894
894
  }
895
+ isValid() {
896
+ return this.value !== null;
897
+ }
895
898
  addRef(count = 1) {
896
899
  if (this.value !== null) {
897
900
  this.referenceCount += count;
898
901
  }
899
902
  }
900
903
  release() {
901
- if (this.value !== null) {
904
+ if (this.value !== null && this.referenceCount > 0) {
902
905
  this.referenceCount--;
903
- //console.log(`Reference count decreased to: ${this.referenceCount}`);
904
906
  if (this.referenceCount === 0) {
905
- //console.log("No more references. Deleting object.");
906
- this.value = null;
907
+ this.dispose();
907
908
  }
908
909
  }
909
910
  }
910
911
  forceRelease() {
911
912
  if (this.value !== null) {
912
- this.value = null;
913
+ this.dispose();
913
914
  this.referenceCount = 0;
914
915
  }
915
916
  }
917
+ /**
918
+ * 子类覆盖此方法以执行清理逻辑
919
+ */
920
+ dispose() {
921
+ this.value = null;
922
+ }
916
923
  getValue() {
917
924
  return this.value;
918
925
  }
919
926
  }
920
927
 
928
+ /**
929
+ * userData 键名常量
930
+ */
931
+ const ASSET_POINTER_KEY = 'assetPointer';
932
+ const EDITOR_ASSET_ID_KEY = 'editorAssetId';
933
+ /**
934
+ * Three.js 资源的智能指针
935
+ * 管理 BufferGeometry、Material、Texture 的生命周期
936
+ */
921
937
  class TAssetPointer extends TSmartPointer {
922
938
  get uuid() {
923
939
  return this._uuid;
@@ -925,40 +941,32 @@ class TAssetPointer extends TSmartPointer {
925
941
  constructor(value, referenceCount = 0) {
926
942
  super(value, referenceCount);
927
943
  this._uuid = value.uuid;
928
- value.userData["assetPointer"] = this;
929
- }
930
- release() {
931
- if (this.value) {
932
- this.referenceCount--;
933
- if (this.referenceCount === 0) {
934
- setTimeout(() => {
935
- this.value.dispose();
936
- this.value = null;
937
- }, 0);
938
- }
939
- }
940
- console.log("realease", this);
944
+ value.userData[ASSET_POINTER_KEY] = this;
941
945
  }
942
- forceRelease() {
943
- console.log("forceRelease", this);
946
+ /**
947
+ * 释放资源,清理 userData 并调用 Three.js 的 dispose
948
+ */
949
+ dispose() {
944
950
  if (this.value) {
945
- if (this.value.userData && this.value.userData["assetPointer"]) {
946
- delete this.value.userData["assetPointer"];
951
+ // 清理 userData 中的引用
952
+ if (this.value.userData) {
953
+ delete this.value.userData[ASSET_POINTER_KEY];
954
+ delete this.value.userData[EDITOR_ASSET_ID_KEY];
947
955
  }
956
+ // 调用 Three.js 资源的 dispose 方法
948
957
  if (typeof this.value.dispose === "function") {
949
- setTimeout(() => {
950
- this.value.dispose();
951
- this.value = null;
952
- }, 0);
958
+ this.value.dispose();
953
959
  }
954
- setTimeout(() => {
955
- //this.value = null;
956
- this.referenceCount = 0;
957
- }, 0);
958
960
  }
961
+ // 调用父类清理 value = null
962
+ super.dispose();
959
963
  }
960
964
  }
961
965
 
966
+ /**
967
+ * 材质资产指针
968
+ * 管理材质及其关联的纹理引用
969
+ */
962
970
  class MaterialAssetPointer extends TAssetPointer {
963
971
  constructor(value, usedTextures, referenceCount = 0) {
964
972
  super(value, referenceCount);
@@ -967,41 +975,57 @@ class MaterialAssetPointer extends TAssetPointer {
967
975
  get texturePointers() {
968
976
  return this.textures;
969
977
  }
978
+ /**
979
+ * 设置材质的纹理属性
980
+ */
970
981
  setTexture(name, texturePtr) {
971
- let mat = this.getValue();
972
- let texture = texturePtr.getValue();
982
+ const mat = this.getValue();
983
+ const texture = texturePtr.getValue();
973
984
  if (!texture) {
974
985
  throw new Error("Texture is null");
975
986
  }
976
987
  if (!mat) {
977
988
  throw new Error("Material is null");
978
989
  }
979
- if (this.textures.has(name)) {
980
- this.textures.get(name).release();
981
- this.textures.delete(name);
982
- }
983
- try {
990
+ const oldTexture = this.textures.get(name);
991
+ if (oldTexture !== texturePtr) {
992
+ // 释放旧纹理引用
993
+ if (oldTexture) {
994
+ oldTexture.release();
995
+ }
996
+ // 设置新纹理
984
997
  this.textures.set(name, texturePtr);
985
- const matAny = mat;
986
- matAny[name] = texture;
998
+ mat[name] = texture;
987
999
  texturePtr.addRef();
988
1000
  mat.needsUpdate = true;
989
1001
  }
990
- catch (e) {
991
- throw e;
992
- }
993
1002
  }
994
- release() {
995
- for (let texture of this.textures.values()) {
996
- texture.release();
1003
+ /**
1004
+ * 移除纹理属性
1005
+ */
1006
+ removeTexture(name) {
1007
+ const mat = this.getValue();
1008
+ const oldTexture = this.textures.get(name);
1009
+ if (oldTexture) {
1010
+ oldTexture.release();
1011
+ this.textures.delete(name);
1012
+ if (mat) {
1013
+ mat[name] = null;
1014
+ mat.needsUpdate = true;
1015
+ }
997
1016
  }
998
- super.release();
999
1017
  }
1000
- forceRelease() {
1001
- for (let texture of this.textures.values()) {
1018
+ /**
1019
+ * 释放材质时同时释放所有关联的纹理引用
1020
+ */
1021
+ dispose() {
1022
+ // 释放所有纹理引用
1023
+ for (const texture of this.textures.values()) {
1002
1024
  texture.release();
1003
1025
  }
1004
- super.forceRelease();
1026
+ this.textures.clear();
1027
+ // 调用父类清理材质
1028
+ super.dispose();
1005
1029
  }
1006
1030
  }
1007
1031
 
@@ -1043,63 +1067,58 @@ class AssetManager {
1043
1067
  }
1044
1068
  }
1045
1069
  convertThreeObjectToLYObject(parentLYComponent, threejsObject) {
1046
- let location = threejsObject.position.clone();
1047
- let rotation = threejsObject.rotation.clone();
1048
- let scale = threejsObject.scale.clone();
1070
+ const location = threejsObject.position.clone();
1071
+ const rotation = threejsObject.rotation.clone();
1072
+ const scale = threejsObject.scale.clone();
1049
1073
  let newComp = null;
1050
- let children = threejsObject.children;
1074
+ const children = threejsObject.children;
1051
1075
  threejsObject.children = [];
1052
1076
  if (threejsObject.type === "Group" || threejsObject.type === "Object3D") {
1053
- newComp = new SceneComponent(this.app, threejsObject);
1077
+ newComp = new SceneComponent(this.app, threejsObject.uuid);
1054
1078
  }
1055
1079
  else if (threejsObject.isMesh) {
1056
- let obj = threejsObject;
1080
+ const obj = threejsObject;
1057
1081
  newComp = new MeshComponent(this.app, obj.geometry, obj.material);
1058
- // assetManager.#collectMatAndGeoInMesh(threejsObject)
1059
1082
  threejsObject.layers.set(0);
1060
1083
  }
1061
1084
  else {
1062
- newComp = new SceneComponent(this.app, threejsObject);
1085
+ newComp = new SceneComponent(this.app, threejsObject.uuid);
1063
1086
  }
1064
1087
  if (newComp === null) {
1065
1088
  threejsObject.children = children;
1066
- //threejsObject.parent = parent
1067
- //console.log("Unprocess", threejsObject);
1068
1089
  return null;
1069
1090
  }
1070
1091
  parentLYComponent.addChildComponent(newComp);
1071
1092
  newComp.setPosition(location);
1072
1093
  newComp.setRotation(rotation);
1073
1094
  newComp.setScale(scale);
1074
- for (let i = 0; i < children.length; ++i) {
1075
- this.convertThreeObjectToLYObject(newComp, children[i]);
1095
+ for (const child of children) {
1096
+ this.convertThreeObjectToLYObject(newComp, child);
1076
1097
  }
1077
1098
  return newComp;
1078
1099
  }
1079
1100
  collectResourcesAndReferences(object) {
1080
- function countResource(map, resource) {
1081
- if (!map.has(resource)) {
1082
- map.set(resource, 1);
1083
- }
1084
- else {
1085
- map.set(resource, map.get(resource) + 1);
1086
- }
1087
- }
1101
+ const countResource = (map, resource) => {
1102
+ var _a;
1103
+ const currentCount = (_a = map.get(resource)) !== null && _a !== void 0 ? _a : 0;
1104
+ map.set(resource, currentCount + 1);
1105
+ };
1088
1106
  const resources = {
1089
1107
  geometries: new Map(),
1090
1108
  materials: new Map(),
1091
1109
  textures: new Map()
1092
1110
  };
1093
1111
  object.traverse((child) => {
1094
- if (child.geometry && child.geometry instanceof BufferGeometry) {
1095
- countResource(resources.geometries, child.geometry);
1112
+ const meshChild = child;
1113
+ if (meshChild.geometry instanceof BufferGeometry) {
1114
+ countResource(resources.geometries, meshChild.geometry);
1096
1115
  }
1097
- if (child.material) {
1098
- const mats = Array.isArray(child.material) ? child.material : [child.material];
1116
+ if (meshChild.material) {
1117
+ const mats = Array.isArray(meshChild.material) ? meshChild.material : [meshChild.material];
1099
1118
  mats.forEach((mat) => {
1100
1119
  if (mat) {
1101
1120
  countResource(resources.materials, mat);
1102
- Object.entries(mat).forEach(([key, value]) => {
1121
+ Object.values(mat).forEach((value) => {
1103
1122
  if (value instanceof Texture) {
1104
1123
  countResource(resources.textures, value);
1105
1124
  }
@@ -1108,49 +1127,36 @@ class AssetManager {
1108
1127
  });
1109
1128
  }
1110
1129
  });
1111
- function createPointer(manager, map) {
1112
- map.forEach((value, key) => {
1113
- manager.addAsset(key, value);
1114
- });
1115
- }
1116
- createPointer(this, resources.geometries);
1117
- createPointer(this, resources.materials);
1118
- createPointer(this, resources.textures);
1119
- // console.log('Geometries:', Array.from(resources.geometries.entries()));
1120
- // console.log('Materials:', Array.from(resources.materials.entries()));
1121
- // console.log('Textures:', Array.from(resources.textures.entries()));
1122
- // console.log('assetPointer:', this.assetPointer);
1130
+ resources.geometries.forEach((count, geometry) => this.addAsset(geometry, count));
1131
+ resources.materials.forEach((count, material) => this.addAsset(material, count));
1132
+ resources.textures.forEach((count, texture) => this.addAsset(texture, count));
1123
1133
  }
1124
1134
  checkMeshResource(mesh) {
1125
- if (mesh.geometry) {
1126
- if (!mesh.geometry.userData["assetPointer"]) {
1127
- this.addAsset(mesh.geometry);
1128
- }
1135
+ if (mesh.geometry && !mesh.geometry.userData["assetPointer"]) {
1136
+ this.addAsset(mesh.geometry);
1129
1137
  }
1130
1138
  if (mesh.material) {
1131
1139
  const mats = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
1132
1140
  mats.forEach((material) => {
1133
- if (material) {
1134
- if (!material.userData["assetPointer"]) {
1135
- this.addAsset(material);
1136
- }
1137
- Object.entries(material).forEach(([key, value]) => {
1138
- if (value instanceof Texture) {
1139
- if (!(value.userData["assetPointer"])) {
1140
- this.addAsset(value);
1141
- }
1142
- }
1143
- });
1141
+ if (!material)
1142
+ return;
1143
+ if (!material.userData["assetPointer"]) {
1144
+ this.addAsset(material);
1144
1145
  }
1146
+ Object.values(material).forEach((value) => {
1147
+ if (value instanceof Texture && !value.userData["assetPointer"]) {
1148
+ this.addAsset(value);
1149
+ }
1150
+ });
1145
1151
  });
1146
1152
  }
1147
1153
  }
1148
1154
  async loadGltfFromPathAsync(path) {
1149
1155
  this.setupDracoLoader("/SceneResource/draco/");
1150
- let res = await this.gltfLoader.loadAsync(path);
1151
- return res;
1156
+ return await this.gltfLoader.loadAsync(path);
1152
1157
  }
1153
1158
  loadGltfFromPath(path, onLoadFinished) {
1159
+ this.setupDracoLoader("/SceneResource/draco/");
1154
1160
  this.gltfLoader.load(path, onLoadFinished);
1155
1161
  }
1156
1162
  loadGltfFromBuffer(data, path, onLoadFinished) {
@@ -1159,33 +1165,30 @@ class AssetManager {
1159
1165
  }
1160
1166
  loadFile(filepath = '', onLoadFinished) {
1161
1167
  const loader = new FileLoader();
1162
- loader.load(filepath, (data) => {
1163
- onLoadFinished(data);
1164
- });
1168
+ loader.load(filepath, onLoadFinished);
1165
1169
  }
1166
1170
  addAsset(asset, referenceCount = 0) {
1167
1171
  if (asset instanceof BufferGeometry) {
1168
1172
  return this.addGeometryAsset(asset, referenceCount);
1169
1173
  }
1170
- else if (asset instanceof Material) {
1174
+ if (asset instanceof Material) {
1171
1175
  return this.addMaterialAsset(asset, referenceCount);
1172
1176
  }
1173
- else if (asset instanceof Texture) {
1177
+ if (asset instanceof Texture) {
1174
1178
  return this.addTextureAsset(asset, referenceCount);
1175
1179
  }
1176
1180
  return undefined;
1177
1181
  }
1178
1182
  addMaterialAsset(asset, referenceCount = 0) {
1179
- let pointer = (asset.userData["assetPointer"]);
1183
+ let pointer = asset.userData["assetPointer"];
1180
1184
  if (!pointer) {
1181
- let textureMap = new Map();
1182
- for (let k in asset) {
1183
- const value = asset[k];
1185
+ const textureMap = new Map();
1186
+ Object.entries(asset).forEach(([key, value]) => {
1184
1187
  if (value instanceof Texture) {
1185
- let ptr = this.addTextureAsset(value, 1);
1186
- textureMap.set(k, ptr);
1188
+ const texturePointer = this.addTextureAsset(value, 1);
1189
+ textureMap.set(key, texturePointer);
1187
1190
  }
1188
- }
1191
+ });
1189
1192
  pointer = new MaterialAssetPointer(asset, textureMap, referenceCount);
1190
1193
  this.materialAssets.set(asset.uuid, pointer);
1191
1194
  }
@@ -1195,7 +1198,7 @@ class AssetManager {
1195
1198
  return pointer;
1196
1199
  }
1197
1200
  addTextureAsset(asset, referenceCount = 0) {
1198
- let pointer = (asset.userData["assetPointer"]);
1201
+ let pointer = asset.userData["assetPointer"];
1199
1202
  if (!pointer) {
1200
1203
  pointer = new TextureAssetPointer(asset, referenceCount);
1201
1204
  this.textureAssets.set(asset.uuid, pointer);
@@ -1206,7 +1209,7 @@ class AssetManager {
1206
1209
  return pointer;
1207
1210
  }
1208
1211
  addGeometryAsset(asset, referenceCount = 0) {
1209
- let pointer = (asset.userData["assetPointer"]);
1212
+ let pointer = asset.userData["assetPointer"];
1210
1213
  if (!pointer) {
1211
1214
  pointer = new GeometryAssetPointer(asset, referenceCount);
1212
1215
  this.geometryAssets.set(asset.uuid, pointer);
@@ -1217,37 +1220,72 @@ class AssetManager {
1217
1220
  return pointer;
1218
1221
  }
1219
1222
  releaseAsset(asset) {
1220
- // let uuid = asset.uuid
1221
- let p = asset.userData["assetPointer"];
1222
- if (p) {
1223
- p.release();
1223
+ const pointer = asset.userData["assetPointer"];
1224
+ if (pointer) {
1225
+ pointer.release();
1224
1226
  }
1225
1227
  else {
1226
1228
  asset.dispose();
1227
1229
  }
1228
1230
  }
1229
1231
  clearAssets() {
1230
- this.geometryAssets.forEach((p) => {
1231
- p.forceRelease();
1232
- });
1232
+ this.geometryAssets.forEach((pointer) => pointer.forceRelease());
1233
1233
  this.geometryAssets.clear();
1234
- this.materialAssets.forEach((p) => {
1235
- p.forceRelease();
1236
- });
1234
+ this.materialAssets.forEach((pointer) => pointer.forceRelease());
1237
1235
  this.materialAssets.clear();
1238
- this.textureAssets.forEach((p) => {
1239
- p.forceRelease();
1240
- });
1236
+ this.textureAssets.forEach((pointer) => pointer.forceRelease());
1241
1237
  this.textureAssets.clear();
1242
- // let pointers = Array.from(this.assetPointer.values());
1243
- // pointers.forEach((p) =>
1244
- // {
1245
- // p.forceRelease();
1246
- // });
1247
- // this.assetPointer.clear();
1248
1238
  }
1249
1239
  }
1250
1240
 
1241
+ /**
1242
+ * 资产类别 - 用于底层资产管理
1243
+ */
1244
+ var AssetCategory;
1245
+ (function (AssetCategory) {
1246
+ AssetCategory["Geometry"] = "geometry";
1247
+ AssetCategory["Material"] = "material";
1248
+ AssetCategory["Texture"] = "texture";
1249
+ AssetCategory["Actor"] = "actor";
1250
+ AssetCategory["ActorManager"] = "actorManager";
1251
+ AssetCategory["Level"] = "level";
1252
+ AssetCategory["HTML"] = "html";
1253
+ AssetCategory["Code"] = "code";
1254
+ AssetCategory["Undefined"] = "undefined";
1255
+ })(AssetCategory || (AssetCategory = {}));
1256
+ /**
1257
+ * 资产加载状态
1258
+ */
1259
+ var AssetLoadState;
1260
+ (function (AssetLoadState) {
1261
+ AssetLoadState["Unloaded"] = "unloaded";
1262
+ AssetLoadState["Loading"] = "loading";
1263
+ AssetLoadState["Loaded"] = "loaded";
1264
+ AssetLoadState["Error"] = "error";
1265
+ })(AssetLoadState || (AssetLoadState = {}));
1266
+ /**
1267
+ * 引用者类型
1268
+ */
1269
+ var ReferenceType;
1270
+ (function (ReferenceType) {
1271
+ ReferenceType["Actor"] = "actor";
1272
+ ReferenceType["Component"] = "component";
1273
+ ReferenceType["Material"] = "material";
1274
+ ReferenceType["Level"] = "level";
1275
+ ReferenceType["AssetPointer"] = "assetPointer";
1276
+ ReferenceType["External"] = "external";
1277
+ })(ReferenceType || (ReferenceType = {}));
1278
+ /**
1279
+ * @deprecated 使用 AssetCategory 替代
1280
+ */
1281
+ var AssetType;
1282
+ (function (AssetType) {
1283
+ AssetType[AssetType["geometry"] = 1] = "geometry";
1284
+ AssetType[AssetType["material"] = 2] = "material";
1285
+ AssetType[AssetType["texture"] = 3] = "texture";
1286
+ AssetType[AssetType["undefined"] = -1] = "undefined";
1287
+ })(AssetType || (AssetType = {}));
1288
+
1251
1289
  class Delegate {
1252
1290
  constructor() {
1253
1291
  this.functions = [];
@@ -1507,6 +1545,142 @@ class WebGPUPostProcessFactory {
1507
1545
  }
1508
1546
  }
1509
1547
 
1548
+ class PostProcessManager {
1549
+ constructor(renderer, scene, camera, postProcessParam, onDirtyCallback) {
1550
+ this.postProcessing = null;
1551
+ this.outlineObjects = [];
1552
+ this.onDirtyCallback = null;
1553
+ this.renderer = renderer;
1554
+ this.scene = scene;
1555
+ this.camera = camera;
1556
+ this.postProcessParam = Object.assign({}, postProcessParam);
1557
+ this.onDirtyCallback = onDirtyCallback !== null && onDirtyCallback !== void 0 ? onDirtyCallback : null;
1558
+ }
1559
+ get processing() {
1560
+ return this.postProcessing;
1561
+ }
1562
+ updateCamera(camera) {
1563
+ this.camera = camera;
1564
+ }
1565
+ setup() {
1566
+ if (this.postProcessParam.steps.length === 0) {
1567
+ this.destroy();
1568
+ this.markDirty();
1569
+ return;
1570
+ }
1571
+ if (!this.postProcessing) {
1572
+ this.postProcessing = new PostProcessing(this.renderer);
1573
+ }
1574
+ const scenePass = WebGPUPostProcessFactory.constructScenePass(this.scene, this.camera);
1575
+ let finalNode = scenePass.getTextureNode('output');
1576
+ this.postProcessParam.steps.forEach((step) => {
1577
+ switch (step.type) {
1578
+ case PostProcessStepType.Bloom:
1579
+ {
1580
+ const bloomPass = WebGPUPostProcessFactory.constructBloomPass(scenePass, step);
1581
+ finalNode = finalNode.add(bloomPass);
1582
+ break;
1583
+ }
1584
+ case PostProcessStepType.DepthOfField:
1585
+ {
1586
+ const dofPass = WebGPUPostProcessFactory.constructDOFPass(scenePass, step);
1587
+ finalNode = finalNode.add(dofPass);
1588
+ break;
1589
+ }
1590
+ case PostProcessStepType.ScreenSpaceReflection:
1591
+ {
1592
+ console.warn("[PostProcess] SSR 目前存在技术问题,暂不支持。");
1593
+ break;
1594
+ }
1595
+ case PostProcessStepType.GroundTruthAmbientOcclusion:
1596
+ {
1597
+ console.warn("[PostProcess] AO 目前存在技术问题,暂不支持。");
1598
+ break;
1599
+ }
1600
+ case PostProcessStepType.Outline:
1601
+ {
1602
+ const outlineParam = step;
1603
+ const outlinePass = WebGPUPostProcessFactory.constructOutlinePass(this.scene, scenePass.camera, this.outlineObjects, outlineParam);
1604
+ const { visibleEdge, hiddenEdge } = outlinePass;
1605
+ const pulsePeriod = uniform(outlineParam.pulsePeriod);
1606
+ const period = time.div(pulsePeriod).mul(2);
1607
+ const osc = oscSine(period).mul(.5).add(.5);
1608
+ const outlineColor = visibleEdge
1609
+ .mul(uniform(new Color(outlineParam.visibleEdgeColor)))
1610
+ .add(hiddenEdge.mul(uniform(new Color(outlineParam.hiddenEdgeColor))))
1611
+ .mul(outlineParam.edgeStrength);
1612
+ const outlinePulse = pulsePeriod.greaterThan(0).select(outlineColor.mul(osc), outlineColor);
1613
+ finalNode = outlinePulse.add(finalNode);
1614
+ break;
1615
+ }
1616
+ case PostProcessStepType.Antialiasing:
1617
+ {
1618
+ const aaParam = step;
1619
+ if (aaParam.method === "fxaa") {
1620
+ finalNode = WebGPUPostProcessFactory.constructFXAAPass(finalNode);
1621
+ }
1622
+ if (aaParam.method === "smaa") {
1623
+ finalNode = WebGPUPostProcessFactory.constructSMAAPass(finalNode);
1624
+ }
1625
+ break;
1626
+ }
1627
+ }
1628
+ });
1629
+ this.postProcessing.outputNode = finalNode;
1630
+ this.postProcessing.needsUpdate = true;
1631
+ this.markDirty();
1632
+ }
1633
+ updateSteps(steps) {
1634
+ this.postProcessParam.steps = steps;
1635
+ this.setup();
1636
+ }
1637
+ addOutlineObject(obj) {
1638
+ if (!this.outlineObjects.includes(obj)) {
1639
+ this.outlineObjects.push(obj);
1640
+ }
1641
+ this.markDirty();
1642
+ }
1643
+ setOutlineObjects(objects) {
1644
+ this.outlineObjects.length = 0;
1645
+ this.outlineObjects.push(...objects);
1646
+ this.markDirty();
1647
+ }
1648
+ removeOutlineObject(obj) {
1649
+ const index = this.outlineObjects.indexOf(obj);
1650
+ if (index > -1) {
1651
+ this.outlineObjects.splice(index, 1);
1652
+ }
1653
+ this.markDirty();
1654
+ }
1655
+ render() {
1656
+ if (this.postProcessing) {
1657
+ this.postProcessing.render();
1658
+ return true;
1659
+ }
1660
+ console.log("render false");
1661
+ return false;
1662
+ }
1663
+ async renderAsync() {
1664
+ if (this.postProcessing) {
1665
+ await this.postProcessing.renderAsync();
1666
+ return true;
1667
+ }
1668
+ return false;
1669
+ }
1670
+ destroy() {
1671
+ this.outlineObjects = [];
1672
+ if (this.postProcessing) {
1673
+ this.postProcessing.dispose();
1674
+ this.postProcessing = null;
1675
+ }
1676
+ }
1677
+ markDirty() {
1678
+ if (this.onDirtyCallback) {
1679
+ this.onDirtyCallback();
1680
+ }
1681
+ }
1682
+ }
1683
+
1510
1684
  class Viewport {
1511
1685
  get uiDom() {
1512
1686
  return this._uiDom;
@@ -1538,8 +1712,7 @@ class Viewport {
1538
1712
  this._outerContainer = null;
1539
1713
  this._canvasContainer = null;
1540
1714
  this.isRenderStateDirty = true;
1541
- this.postProcessing = null;
1542
- this.outlineObjects = [];
1715
+ this.postProcessManager = null;
1543
1716
  this.postProcessParam = Object.assign({}, postProcessParam);
1544
1717
  this._app = app;
1545
1718
  if (viewportParam.elementId) {
@@ -1563,7 +1736,10 @@ class Viewport {
1563
1736
  this.resizeObserver.observe(this._outerContainer);
1564
1737
  }
1565
1738
  this.app.onCameraChangedDelegate.add(() => {
1566
- this.setupPostProcess();
1739
+ if (this.postProcessManager) {
1740
+ this.postProcessManager.updateCamera(this.app.camera);
1741
+ this.postProcessManager.setup();
1742
+ }
1567
1743
  });
1568
1744
  }
1569
1745
  createRenderer(rendererParam) {
@@ -1648,159 +1824,39 @@ class Viewport {
1648
1824
  this.setupPostProcess();
1649
1825
  }
1650
1826
  setupPostProcess() {
1651
- if (this.postProcessParam.steps.length === 0) {
1652
- this.destroyPostProcess();
1653
- this.markRenderStateDirty();
1654
- return;
1827
+ if (!this.postProcessManager) {
1828
+ this.postProcessManager = new PostProcessManager(this.renderer, this.app.world.scene, this.app.camera, this.postProcessParam, () => this.markRenderStateDirty());
1655
1829
  }
1656
- if (!this.postProcessing) {
1657
- this.postProcessing = new PostProcessing(this.renderer);
1658
- }
1659
- const scenePass = WebGPUPostProcessFactory.constructScenePass(this.app.world.scene, this.app.camera);
1660
- let finalNode = scenePass.getTextureNode('output');
1661
- this.postProcessParam.steps.forEach((step) => {
1662
- switch (step.type) {
1663
- case PostProcessStepType.Bloom:
1664
- {
1665
- const bloomPass = WebGPUPostProcessFactory.constructBloomPass(scenePass, step);
1666
- //console.log("[PostProcess] BloomPass 构建完成");
1667
- finalNode = finalNode.add(bloomPass);
1668
- break;
1669
- }
1670
- case PostProcessStepType.DepthOfField:
1671
- {
1672
- const dofPass = WebGPUPostProcessFactory.constructDOFPass(scenePass, step);
1673
- //console.log("[PostProcess] DOFPass 构建完成");
1674
- finalNode = finalNode.add(dofPass);
1675
- break;
1676
- }
1677
- case PostProcessStepType.ScreenSpaceReflection:
1678
- {
1679
- console.warn("[PostProcess] SSR 目前存在技术问题,暂不支持。");
1680
- // const ssrPass = WebGPUPostProcessFactory.constructSSRPass(scenePass, step as SSRParam);
1681
- // console.log("[PostProcess] SSRPass 构建完成");
1682
- //finalNode = blendColor(finalNode, ssrPass);
1683
- break;
1684
- }
1685
- case PostProcessStepType.GroundTruthAmbientOcclusion:
1686
- {
1687
- console.warn("[PostProcess] AO 目前存在技术问题,暂不支持。");
1688
- // const stepParam = step as GTAOParam
1689
- // const GTAOPass = WebGPUPostProcessFactory.constructGTAOPass(scenePass, stepParam);
1690
- // console.log("[PostProcess] GTAOPass 构建完成");
1691
- // if (stepParam.denoised)
1692
- // {
1693
- // const denoiseGTAOPass = WebGPUPostProcessFactory.constructGTAODenoisePass(scenePass, GTAOPass, stepParam);
1694
- // console.log("[PostProcess] GTAODenoisePass 构建完成");
1695
- // finalNode = denoiseGTAOPass.mul(finalNode);
1696
- // }
1697
- // else
1698
- // {
1699
- // finalNode = GTAOPass.getTextureNode().mul(finalNode);
1700
- // }
1701
- break;
1702
- }
1703
- case PostProcessStepType.Outline:
1704
- {
1705
- const outlineParam = step;
1706
- const outlinePass = WebGPUPostProcessFactory.constructOutlinePass(this.app.world.scene, scenePass.camera, this.outlineObjects, outlineParam);
1707
- const { visibleEdge, hiddenEdge } = outlinePass;
1708
- const pulsePeriod = uniform(outlineParam.pulsePeriod);
1709
- const period = time.div(pulsePeriod).mul(2);
1710
- const osc = oscSine(period).mul(.5).add(.5);
1711
- const outlineColor = visibleEdge.mul(uniform(new Color(outlineParam.visibleEdgeColor))).add(hiddenEdge.mul(uniform(new Color(outlineParam.hiddenEdgeColor)))).mul(outlineParam.edgeStrength);
1712
- const outlinePulse = pulsePeriod.greaterThan(0).select(outlineColor.mul(osc), outlineColor);
1713
- // if(!this.denoiseOutlinePass)
1714
- // {
1715
- // this.denoiseOutlinePass = WebGPUPostProcessFactory.constructDenoisePass(this.scenePass, outlinePulse, DefaultDenoiseParam);
1716
- // }
1717
- // outlinePulse = this.denoiseOutlinePass.mul(outlinePulse)
1718
- // finalNode = this.denoiseOutlinePass.mul(outlinePulse).add(finalNode);
1719
- finalNode = outlinePulse.add(finalNode);
1720
- //console.log("[PostProcess] OutlinePass 构建完成");
1721
- break;
1722
- }
1723
- case PostProcessStepType.Antialiasing:
1724
- {
1725
- const aaParam = step;
1726
- if (aaParam.method === "fxaa") {
1727
- finalNode = WebGPUPostProcessFactory.constructFXAAPass(finalNode);
1728
- //console.log("[PostProcess] FXAAPass 构建完成");
1729
- }
1730
- if (aaParam.method === "smaa") {
1731
- finalNode = WebGPUPostProcessFactory.constructSMAAPass(finalNode);
1732
- //console.log("[PostProcess] SMAAPass 构建完成");
1733
- }
1734
- break;
1735
- }
1736
- }
1737
- });
1738
- this.postProcessing.outputNode = finalNode;
1739
- this.postProcessing.needsUpdate = true;
1740
- //console.log("[PostProcess] setup complete", this.postProcessParam.steps);
1741
- this.markRenderStateDirty();
1830
+ this.postProcessManager.setup();
1742
1831
  }
1743
1832
  updatePostProcess(steps) {
1744
- this.postProcessParam.steps = steps;
1745
- this.setupPostProcess();
1833
+ if (this.postProcessManager) {
1834
+ this.postProcessManager.updateSteps(steps);
1835
+ }
1746
1836
  }
1747
1837
  updateRendererSettings(data) {
1748
1838
  this.createRenderer(data);
1749
1839
  this.markRenderStateDirty();
1750
1840
  }
1751
- // updateBloomPass(params: BloomParam)
1752
- // {
1753
- // this.postProcessParam.bloom = { ...params };
1754
- // this.setupPostProcess();
1755
- // }
1756
- // updateGTAOParam(params: GTAOParam)
1757
- // {
1758
- // this.postProcessParam.gtao = { ...params };
1759
- // this.setupPostProcess();
1760
- // }
1761
- // updateDOFParam(params: DOFParam)
1762
- // {
1763
- // this.postProcessParam.dof = { ...params };
1764
- // this.setupPostProcess();
1765
- // }
1766
- // updateSSRParam(params: SSRParam)
1767
- // {
1768
- // this.postProcessParam.ssr = { ...params };
1769
- // this.setupPostProcess();
1770
- // }
1771
- // updateOutlineParam(params: OutlineParams)
1772
- // {
1773
- // this.postProcessParam.outline = { ...params }
1774
- // this.setupPostProcess();
1775
- // }
1776
- // updateAAParam(params: AAParams)
1777
- // {
1778
- // this.postProcessParam.aa = { ...params };
1779
- // this.setupPostProcess();
1780
- // }
1781
1841
  addOutlineObject(obj) {
1782
- if (!this.outlineObjects.includes(obj)) {
1783
- this.outlineObjects.push(obj);
1842
+ if (this.postProcessManager) {
1843
+ this.postProcessManager.addOutlineObject(obj);
1784
1844
  }
1785
- this.markRenderStateDirty();
1786
1845
  }
1787
1846
  setOutlineObjects(objects) {
1788
- this.outlineObjects.length = 0;
1789
- this.outlineObjects.push(...objects);
1790
- this.markRenderStateDirty();
1847
+ if (this.postProcessManager) {
1848
+ this.postProcessManager.setOutlineObjects(objects);
1849
+ }
1791
1850
  }
1792
1851
  removeOutlineObject(obj) {
1793
- const index = this.outlineObjects.indexOf(obj);
1794
- if (index > -1) {
1795
- this.outlineObjects.splice(index, 1);
1852
+ if (this.postProcessManager) {
1853
+ this.postProcessManager.removeOutlineObject(obj);
1796
1854
  }
1797
- this.markRenderStateDirty();
1798
1855
  }
1799
1856
  destroyPostProcess() {
1800
- this.outlineObjects = [];
1801
- if (this.postProcessing) {
1802
- this.postProcessing.dispose();
1803
- this.postProcessing = null;
1857
+ if (this.postProcessManager) {
1858
+ this.postProcessManager.destroy();
1859
+ this.postProcessManager = null;
1804
1860
  }
1805
1861
  }
1806
1862
  onWindowResize() {
@@ -1820,11 +1876,10 @@ class Viewport {
1820
1876
  }
1821
1877
  render() {
1822
1878
  if (!this.isRenderStateDirty) {
1879
+ console.log("render clean retrn");
1823
1880
  return;
1824
1881
  }
1825
- if (this.postProcessing) {
1826
- this.postProcessing.render();
1827
- }
1882
+ if (this.postProcessManager && this.postProcessManager.render()) ;
1828
1883
  else {
1829
1884
  this.renderer.render(this.app.world.scene, this.app.camera);
1830
1885
  }
@@ -1834,42 +1889,40 @@ class Viewport {
1834
1889
  this.isRenderStateDirty = false;
1835
1890
  }
1836
1891
  async renderAsImage(width = 1024, height = 1024) {
1837
- return new Promise(async (resolve, reject) => {
1838
- try {
1839
- if (this.postProcessing) {
1840
- await this.postProcessing.renderAsync();
1841
- }
1842
- else {
1843
- await this.renderer.renderAsync(this.app.world.scene, this.app.camera);
1844
- }
1845
- // 检查 renderer.domElement 的尺寸
1846
- const sourceWidth = this.renderer.domElement.width;
1847
- const sourceHeight = this.renderer.domElement.height;
1848
- // 如果源尺寸为0,则使用容器尺寸
1849
- let actualWidth = sourceWidth || width;
1850
- let actualHeight = sourceHeight || height;
1851
- if (actualWidth <= 0 || actualHeight <= 0) {
1852
- // 如果仍然无效,则使用默认值
1853
- actualWidth = width;
1854
- actualHeight = height;
1855
- }
1856
- const offscreenCanvas = document.createElement('canvas');
1857
- offscreenCanvas.width = width;
1858
- offscreenCanvas.height = height;
1859
- const context = offscreenCanvas.getContext('2d');
1860
- if (!context) {
1861
- throw Error("Can not create context");
1862
- }
1863
- // 使用实际尺寸进行绘制
1864
- context.drawImage(this.renderer.domElement, 0, 0, actualWidth, actualHeight, 0, 0, width, height);
1865
- const ret = offscreenCanvas.toDataURL('image/jpeg');
1866
- offscreenCanvas.remove();
1867
- resolve(ret);
1892
+ try {
1893
+ if (this.postProcessManager && await this.postProcessManager.renderAsync()) {
1894
+ // Post processing rendered
1868
1895
  }
1869
- catch (error) {
1870
- reject(error);
1896
+ else {
1897
+ await this.renderer.renderAsync(this.app.world.scene, this.app.camera);
1871
1898
  }
1872
- });
1899
+ // 检查 renderer.domElement 的尺寸
1900
+ const sourceWidth = this.renderer.domElement.width;
1901
+ const sourceHeight = this.renderer.domElement.height;
1902
+ // 如果源尺寸为0,则使用容器尺寸
1903
+ let actualWidth = sourceWidth || width;
1904
+ let actualHeight = sourceHeight || height;
1905
+ if (actualWidth <= 0 || actualHeight <= 0) {
1906
+ // 如果仍然无效,则使用默认值
1907
+ actualWidth = width;
1908
+ actualHeight = height;
1909
+ }
1910
+ const offscreenCanvas = document.createElement('canvas');
1911
+ offscreenCanvas.width = width;
1912
+ offscreenCanvas.height = height;
1913
+ const context = offscreenCanvas.getContext('2d');
1914
+ if (!context) {
1915
+ throw Error("Can not create context");
1916
+ }
1917
+ // 使用实际尺寸进行绘制
1918
+ context.drawImage(this.renderer.domElement, 0, 0, actualWidth, actualHeight, 0, 0, width, height);
1919
+ const ret = offscreenCanvas.toDataURL('image/jpeg');
1920
+ offscreenCanvas.remove();
1921
+ return ret;
1922
+ }
1923
+ catch (error) {
1924
+ return "";
1925
+ }
1873
1926
  }
1874
1927
  setAlpha(alpha) {
1875
1928
  if (!this._renderer) {
@@ -1920,7 +1973,6 @@ class Viewport {
1920
1973
  this._renderer.stencil = stencil;
1921
1974
  }
1922
1975
  destroy() {
1923
- var _a;
1924
1976
  this.destroyPostProcess();
1925
1977
  this.renderer.setAnimationLoop(null);
1926
1978
  if (this.resizeObserver) {
@@ -1936,11 +1988,8 @@ class Viewport {
1936
1988
  this._renderer.dispose();
1937
1989
  this._renderer = null;
1938
1990
  }
1939
- (_a = this.postProcessing) === null || _a === void 0 ? void 0 : _a.dispose();
1940
1991
  this._outerContainer = null;
1941
1992
  this._app = null;
1942
- this._renderer = null;
1943
- this.outlineObjects = [];
1944
1993
  }
1945
1994
  }
1946
1995
 
@@ -2098,195 +2147,248 @@ class Orbital extends Pawn {
2098
2147
  }
2099
2148
 
2100
2149
  class Controller {
2101
- get camera() {
2102
- return this._app.camera;
2103
- }
2104
- get world() {
2105
- return this._app.world;
2106
- }
2107
- get viewPort() {
2108
- return this._app.viewport;
2109
- }
2150
+ // ==================== Getters ====================
2151
+ get camera() { return this._app.camera; }
2152
+ get world() { return this._app.world; }
2153
+ get viewPort() { return this._app.viewport; }
2154
+ get app() { return this._app; }
2155
+ get onClickNothingDelegate() { return this._onClickNothingDelegate; }
2156
+ get onComponentClickDelegate() { return this._onComponentClickDelegate; }
2157
+ get onComponentDoubleClickDelegate() { return this._onComponentDoubleClickDelegate; }
2158
+ get onComponentHoverBeginDelegate() { return this._onComponentHoverBeginDelegate; }
2159
+ get onComponentHoverEndDelegate() { return this._onComponentHoverEndDelegate; }
2160
+ get onComponentPointerDownDelegate() { return this._onComponentPointerDownDelegate; }
2110
2161
  get pawn() {
2111
- if (!this._pawn) {
2162
+ if (!this._pawn)
2112
2163
  throw Error("pawn is null");
2113
- }
2114
2164
  return this._pawn;
2115
2165
  }
2116
- get app() {
2117
- return this._app;
2118
- }
2119
- get onClickNothingDelegate() {
2120
- return this._onClickNothingDelegate;
2121
- }
2122
2166
  constructor(app) {
2123
- this.prepareClickComponent = null;
2124
2167
  this._pawn = null;
2125
- this.onPointerMove = (event) => { this.onPointerMoveEvent(event); };
2126
- this.onPointerEnter = (event) => { this.onPointerEnterEvent(event); };
2127
- this.onPointerLeave = (event) => { this.onPointerLeaveEvent(event); };
2128
- this.onPointerUp = (event) => { this.onPointerUpEvent(event); };
2129
- this.onPointerDown = (event) => { this.onPointerDownEvent(event); };
2130
- this.pointerPosition = new Vector2();
2131
- this.doubleClickDelay = 250; // 双击判定时间间隔(毫秒)
2132
- this.leftClickTimer = null;
2133
- this.pointerLeftDownPosition = new Vector2();
2168
+ this.prepareClickComponent = null;
2169
+ this.prepareClickHit = null;
2134
2170
  this.hoveringComponent = null;
2135
2171
  this._pointButtonIsDown = new Set();
2136
2172
  this._onClickNothingDelegate = new Delegate();
2173
+ this._onComponentClickDelegate = new Delegate();
2174
+ this._onComponentDoubleClickDelegate = new Delegate();
2175
+ this._onComponentHoverBeginDelegate = new Delegate();
2176
+ this._onComponentHoverEndDelegate = new Delegate();
2177
+ this._onComponentPointerDownDelegate = new Delegate();
2178
+ // Pointer state
2179
+ this.pointerPosition = new Vector2();
2180
+ this.pointerLeftDownPosition = new Vector2();
2181
+ // Reusable objects to avoid GC pressure
2182
+ this._tempVec2 = new Vector2();
2183
+ this._raycastVec2 = new Vector2();
2184
+ // Double click detection
2185
+ this.doubleClickDelay = 250;
2186
+ this.leftClickTimer = null;
2187
+ // Event handlers (bound)
2188
+ this.onPointerMove = (e) => this.onPointerMoveEvent(e);
2189
+ this.onPointerEnter = (e) => this.onPointerEnterEvent(e);
2190
+ this.onPointerLeave = (e) => this.onPointerLeaveEvent(e);
2191
+ this.onPointerUp = (e) => this.onPointerUpEvent(e);
2192
+ this.onPointerDown = (e) => this.onPointerDownEvent(e);
2137
2193
  this._app = app;
2138
2194
  this._pawn = new Orbital(this);
2139
2195
  this.pawn.possess();
2140
2196
  this.raycaster = new Raycaster();
2141
2197
  }
2198
+ init() {
2199
+ const canvas = this.viewPort.canvas;
2200
+ if (canvas) {
2201
+ canvas.addEventListener("pointerenter", this.onPointerEnter);
2202
+ canvas.addEventListener("pointerleave", this.onPointerLeave);
2203
+ this.addCorePointerListeners();
2204
+ }
2205
+ }
2142
2206
  updateCamera() {
2143
2207
  var _a, _b;
2144
- let isPawnEnabled = this.pawn.enabled;
2208
+ const isPawnEnabled = this.pawn.enabled;
2145
2209
  (_a = this._pawn) === null || _a === void 0 ? void 0 : _a.unpossess();
2146
2210
  (_b = this._pawn) === null || _b === void 0 ? void 0 : _b.destroy();
2147
2211
  this._pawn = new Orbital(this);
2148
2212
  this.pawn.possess();
2149
2213
  this.pawn.enabled = isPawnEnabled;
2150
2214
  }
2151
- init() {
2152
- if (this.viewPort.canvas) {
2153
- this.viewPort.canvas.addEventListener("pointermove", this.onPointerMove);
2154
- this.viewPort.canvas.addEventListener("pointerenter", this.onPointerEnter);
2155
- this.viewPort.canvas.addEventListener("pointerleave", this.onPointerLeave);
2156
- this.viewPort.canvas.addEventListener("pointerup", this.onPointerUp);
2157
- this.viewPort.canvas.addEventListener("pointerdown", this.onPointerDown);
2158
- }
2159
- }
2160
2215
  tick(deltaTime) {
2161
2216
  this.pawn.tick(deltaTime);
2162
2217
  }
2163
2218
  destroy() {
2164
- if (this.leftClickTimer) {
2165
- clearTimeout(this.leftClickTimer);
2166
- this.leftClickTimer = null;
2167
- }
2168
- if (this.viewPort.canvas) {
2169
- this.viewPort.canvas.removeEventListener("pointermove", this.onPointerMove);
2170
- this.viewPort.canvas.removeEventListener("pointerenter", this.onPointerEnter);
2171
- this.viewPort.canvas.removeEventListener("pointerleave", this.onPointerLeave);
2172
- this.viewPort.canvas.removeEventListener("pointerup", this.onPointerUp);
2173
- this.viewPort.canvas.removeEventListener("pointerdown", this.onPointerDown);
2219
+ this.clearClickTimer();
2220
+ this.clearHoveringComponent();
2221
+ const canvas = this.viewPort.canvas;
2222
+ if (canvas) {
2223
+ canvas.removeEventListener("pointerenter", this.onPointerEnter);
2224
+ canvas.removeEventListener("pointerleave", this.onPointerLeave);
2225
+ this.removeCorePointerListeners();
2174
2226
  }
2175
2227
  this.pawn.unpossess();
2176
2228
  this.pawn.destroy();
2177
2229
  this._pawn = null;
2178
2230
  }
2179
2231
  onPointerMoveEvent(event) {
2180
- var _a, _b;
2181
- if (!this.viewPort.canvas) {
2232
+ const canvas = this.viewPort.canvas;
2233
+ if (!canvas)
2182
2234
  throw Error("canvas is null");
2183
- }
2184
- const canvasRect = this.viewPort.canvas.getBoundingClientRect();
2185
- const offsetX = canvasRect.left;
2186
- const offsetY = canvasRect.top;
2187
- const pointer = new Vector2(((event.clientX - offsetX) / this.viewPort.canvas.clientWidth) * 2 - 1, 1 - ((event.clientY - offsetY) / this.viewPort.canvas.clientHeight) * 2);
2188
- this.pointerPosition = pointer;
2189
- if (this._pointButtonIsDown.size > 0) {
2235
+ const canvasRect = canvas.getBoundingClientRect();
2236
+ this.pointerPosition.set(((event.clientX - canvasRect.left) / canvas.clientWidth) * 2 - 1, 1 - ((event.clientY - canvasRect.top) / canvas.clientHeight) * 2);
2237
+ if (this._pointButtonIsDown.size > 0)
2190
2238
  return;
2191
- }
2192
2239
  const hits = this.getHitResultUnderCursor();
2193
- if (hits) {
2194
- let component = hits.object.userData["LYObject"];
2195
- if (component != this.hoveringComponent) {
2196
- (_a = this.hoveringComponent) === null || _a === void 0 ? void 0 : _a.onHorveringEnd();
2197
- this.hoveringComponent = null;
2198
- if (component instanceof SceneComponent && component.isHoverEnabled) {
2199
- component.onHorveringBegin();
2200
- this.hoveringComponent = component;
2201
- }
2240
+ const component = hits === null || hits === void 0 ? void 0 : hits.object.userData["LYObject"];
2241
+ if (component !== this.hoveringComponent) {
2242
+ this.clearHoveringComponent();
2243
+ if (component instanceof SceneComponent && component.isHoverEnabled && hits) {
2244
+ this.fireHoverEvent(component, hits, true);
2245
+ }
2246
+ }
2247
+ }
2248
+ clearHoveringComponent() {
2249
+ if (this.hoveringComponent) {
2250
+ this.fireHoverEvent(this.hoveringComponent, null, false);
2251
+ }
2252
+ }
2253
+ fireHoverEvent(component, hit, isBegin) {
2254
+ const event = { component, hit, handled: false };
2255
+ if (isBegin) {
2256
+ this._onComponentHoverBeginDelegate.broadcast(event);
2257
+ if (!event.handled) {
2258
+ component.onHorveringBegin();
2202
2259
  }
2260
+ this.hoveringComponent = component;
2203
2261
  }
2204
2262
  else {
2205
- (_b = this.hoveringComponent) === null || _b === void 0 ? void 0 : _b.onHorveringEnd();
2263
+ this._onComponentHoverEndDelegate.broadcast(event);
2264
+ if (!event.handled) {
2265
+ component.onHorveringEnd();
2266
+ }
2206
2267
  this.hoveringComponent = null;
2207
2268
  }
2208
2269
  }
2209
2270
  onPointerUpEvent(event) {
2210
2271
  this._pointButtonIsDown.delete(event.button);
2211
- if (event.button === 0) {
2212
- const pointerOffset = new Vector2().subVectors(this.pointerLeftDownPosition, this.pointerPosition).length();
2213
- if (pointerOffset > 0.005) {
2214
- if (this.leftClickTimer) {
2215
- window.clearTimeout(this.leftClickTimer);
2216
- this.leftClickTimer = null;
2217
- }
2218
- return;
2219
- }
2220
- if (!this.leftClickTimer) {
2221
- const hit = this.getHitResultUnderCursor();
2222
- let component = hit ? hit.object.userData["LYObject"] : null;
2223
- if (component && component instanceof SceneComponent && component.isClickEnabled) {
2224
- this.prepareClickComponent = component;
2225
- this.leftClickTimer = window.setTimeout(() => {
2226
- this.leftClickTimer = null;
2227
- if (this.prepareClickComponent) {
2228
- this.prepareClickComponent.onClicked();
2229
- this.prepareClickComponent = null;
2230
- }
2231
- }, this.doubleClickDelay);
2232
- }
2233
- else {
2234
- this._onClickNothingDelegate.broadcast();
2235
- }
2236
- }
2237
- else {
2238
- window.clearTimeout(this.leftClickTimer);
2272
+ if (event.button !== 0)
2273
+ return;
2274
+ // Check if pointer moved too much (drag instead of click)
2275
+ const pointerOffset = this._tempVec2.subVectors(this.pointerLeftDownPosition, this.pointerPosition).length();
2276
+ if (pointerOffset > 0.005) {
2277
+ this.clearClickTimer();
2278
+ return;
2279
+ }
2280
+ if (!this.leftClickTimer) {
2281
+ this.handleFirstClick();
2282
+ }
2283
+ else {
2284
+ this.handleDoubleClick();
2285
+ }
2286
+ }
2287
+ handleFirstClick() {
2288
+ const hit = this.getHitResultUnderCursor();
2289
+ const component = hit === null || hit === void 0 ? void 0 : hit.object.userData["LYObject"];
2290
+ if (component instanceof SceneComponent && component.isClickEnabled && hit) {
2291
+ this.prepareClickComponent = component;
2292
+ this.prepareClickHit = hit;
2293
+ this.leftClickTimer = window.setTimeout(() => {
2239
2294
  this.leftClickTimer = null;
2240
- if (this.prepareClickComponent) {
2241
- this.prepareClickComponent.onDoubleClicked();
2242
- }
2243
- else {
2244
- this._onClickNothingDelegate.broadcast();
2295
+ if (this.prepareClickComponent && this.prepareClickHit) {
2296
+ this.fireClickEvent(this.prepareClickComponent, this.prepareClickHit, false);
2297
+ this.prepareClickComponent = null;
2298
+ this.prepareClickHit = null;
2245
2299
  }
2246
- this.prepareClickComponent = null;
2300
+ }, this.doubleClickDelay);
2301
+ }
2302
+ else {
2303
+ this._onClickNothingDelegate.broadcast();
2304
+ }
2305
+ }
2306
+ handleDoubleClick() {
2307
+ this.clearClickTimer();
2308
+ if (this.prepareClickComponent && this.prepareClickHit) {
2309
+ this.fireClickEvent(this.prepareClickComponent, this.prepareClickHit, true);
2310
+ }
2311
+ else {
2312
+ this._onClickNothingDelegate.broadcast();
2313
+ }
2314
+ this.prepareClickComponent = null;
2315
+ this.prepareClickHit = null;
2316
+ }
2317
+ fireClickEvent(component, hit, isDoubleClick) {
2318
+ const event = { component, hit, handled: false };
2319
+ if (isDoubleClick) {
2320
+ this._onComponentDoubleClickDelegate.broadcast(event);
2321
+ if (!event.handled) {
2322
+ component.onDoubleClicked();
2323
+ }
2324
+ }
2325
+ else {
2326
+ this._onComponentClickDelegate.broadcast(event);
2327
+ if (!event.handled) {
2328
+ component.onClicked();
2247
2329
  }
2248
2330
  }
2249
2331
  }
2332
+ clearClickTimer() {
2333
+ if (this.leftClickTimer) {
2334
+ window.clearTimeout(this.leftClickTimer);
2335
+ this.leftClickTimer = null;
2336
+ }
2337
+ }
2250
2338
  onPointerDownEvent(event) {
2251
2339
  this._pointButtonIsDown.add(event.button);
2252
2340
  if (event.button === 0) {
2253
- this.pointerLeftDownPosition = this.pointerPosition.clone();
2341
+ this.pointerLeftDownPosition.copy(this.pointerPosition);
2342
+ }
2343
+ // 广播组件按下事件
2344
+ const hit = this.getHitResultUnderCursor();
2345
+ const component = hit === null || hit === void 0 ? void 0 : hit.object.userData["LYObject"];
2346
+ if (component instanceof SceneComponent && hit) {
2347
+ this.firePointerDownEvent(component, hit, event.button);
2254
2348
  }
2255
2349
  }
2350
+ firePointerDownEvent(component, hit, button) {
2351
+ const event = { component, hit, button, handled: false };
2352
+ this._onComponentPointerDownDelegate.broadcast(event);
2353
+ }
2256
2354
  onPointerEnterEvent(event) {
2257
- if (!this.viewPort.canvas) {
2258
- throw Error("canvas is null");
2259
- }
2260
- this.viewPort.canvas.addEventListener("pointermove", this.onPointerMove);
2261
- this.viewPort.canvas.addEventListener("pointerup", this.onPointerUp);
2262
- this.viewPort.canvas.addEventListener("pointerdown", this.onPointerDown);
2355
+ this.addCorePointerListeners();
2263
2356
  }
2264
2357
  onPointerLeaveEvent(event) {
2265
- if (!this.viewPort.canvas) {
2266
- throw Error("canvas is null");
2267
- }
2268
- this.viewPort.canvas.removeEventListener("pointermove", this.onPointerMove);
2269
- this.viewPort.canvas.removeEventListener("pointerup", this.onPointerUp);
2270
- this.viewPort.canvas.removeEventListener("pointerdown", this.onPointerDown);
2358
+ this.removeCorePointerListeners();
2359
+ }
2360
+ addCorePointerListeners() {
2361
+ const canvas = this.viewPort.canvas;
2362
+ if (!canvas)
2363
+ return;
2364
+ canvas.addEventListener("pointermove", this.onPointerMove);
2365
+ canvas.addEventListener("pointerup", this.onPointerUp);
2366
+ canvas.addEventListener("pointerdown", this.onPointerDown);
2367
+ }
2368
+ removeCorePointerListeners() {
2369
+ const canvas = this.viewPort.canvas;
2370
+ if (!canvas)
2371
+ return;
2372
+ canvas.removeEventListener("pointermove", this.onPointerMove);
2373
+ canvas.removeEventListener("pointerup", this.onPointerUp);
2374
+ canvas.removeEventListener("pointerdown", this.onPointerDown);
2271
2375
  }
2272
2376
  getHitResultUnderCursor() {
2273
2377
  return this.getHitResultFromScreenPoint(this.pointerPosition.x, this.pointerPosition.y);
2274
2378
  }
2275
2379
  getHitResultFromScreenPoint(x, y) {
2276
- this.raycaster.setFromCamera(new Vector2(x, y), this.camera);
2277
- let out = this.raycaster.intersectObjects(this.world.scene.children, true);
2278
- for (let i = 0; i < out.length; i++) {
2279
- if (out[i].object.userData["rayIgnored"]) {
2380
+ this._raycastVec2.set(x, y);
2381
+ this.raycaster.setFromCamera(this._raycastVec2, this.camera);
2382
+ const out = this.raycaster.intersectObjects(this.world.scene.children, true);
2383
+ for (const hit of out) {
2384
+ if (hit.object.userData["rayIgnored"])
2280
2385
  continue;
2281
- }
2282
- let component = out[i].object.userData["LYObject"];
2283
- if (!component) {
2386
+ const component = hit.object.userData["LYObject"];
2387
+ if (!component)
2284
2388
  continue;
2285
- }
2286
- if (!component.isHoverEnabled && !component.isClickEnabled) {
2389
+ if (!component.isHoverEnabled && !component.isClickEnabled)
2287
2390
  continue;
2288
- }
2289
- return out[i];
2391
+ return hit;
2290
2392
  }
2291
2393
  return null;
2292
2394
  }
@@ -3600,4 +3702,4 @@ class TransformGizmo extends Pawn {
3600
3702
  }
3601
3703
  }
3602
3704
 
3603
- export { Actor, AmbientLightActor, AmbientLightComponent, AssetManager, AttachmentRules, BoxActor, BoxComponent, Controller, DefaultAAParams, DefaultAppParam, DefaultBloomParam, DefaultCameraParam, DefaultDOFParam, DefaultDenoiseParam, DefaultGTAOParam, DefaultOrthographicCameraParam, DefaultOutlineParams, DefaultPerspectiveCameraParam, DefaultPostProcessParam, DefaultRendererParameters, DefaultSSRParam, DefaultSkyParam, DefaultViewportParam, DefaultWorldParam, Delegate, DirectionalLightActor, DirectionalLightComponent, FirstPerson, GeometryAssetPointer, LabelComponent, LevelActor, LevelComponent, MaterialAssetPointer, MeshComponent, Orbital, PlaneActor, PlaneComponent, PostProcessStepType, SceneComponent, SkyActor, SkyComponent, SphereComponent, TAssetPointer, TSmartPointer, TextureAssetPointer, ThreeJsApp, ThreeObjectLibrary, TransformGizmo, Viewport, WebGPUPostProcessFactory, World };
3705
+ export { ASSET_POINTER_KEY, Actor, AmbientLightActor, AmbientLightComponent, AssetCategory, AssetLoadState, AssetManager, AssetType, AttachmentRules, BoxActor, BoxComponent, Controller, DefaultAAParams, DefaultAppParam, DefaultBloomParam, DefaultCameraParam, DefaultDOFParam, DefaultDenoiseParam, DefaultGTAOParam, DefaultOrthographicCameraParam, DefaultOutlineParams, DefaultPerspectiveCameraParam, DefaultPostProcessParam, DefaultRendererParameters, DefaultSSRParam, DefaultSkyParam, DefaultViewportParam, DefaultWorldParam, Delegate, DirectionalLightActor, DirectionalLightComponent, EDITOR_ASSET_ID_KEY, FirstPerson, GeometryAssetPointer, LabelComponent, LevelActor, LevelComponent, MaterialAssetPointer, MeshComponent, Orbital, PlaneActor, PlaneComponent, PostProcessStepType, ReferenceType, SceneComponent, SkyActor, SkyComponent, SphereComponent, TAssetPointer, TSmartPointer, TextureAssetPointer, ThreeJsApp, ThreeObjectLibrary, TransformGizmo, Viewport, WebGPUPostProcessFactory, World };