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