lythreeframe 1.2.52 → 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;
946
+ value.userData[ASSET_POINTER_KEY] = this;
931
947
  }
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)
943
- }
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
 
@@ -1216,6 +1240,54 @@ class AssetManager {
1216
1240
  }
1217
1241
  }
1218
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
+
1219
1291
  class Delegate {
1220
1292
  constructor() {
1221
1293
  this.functions = [];
@@ -1475,6 +1547,142 @@ class WebGPUPostProcessFactory {
1475
1547
  }
1476
1548
  }
1477
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
+
1478
1686
  class Viewport {
1479
1687
  get uiDom() {
1480
1688
  return this._uiDom;
@@ -1506,8 +1714,7 @@ class Viewport {
1506
1714
  this._outerContainer = null;
1507
1715
  this._canvasContainer = null;
1508
1716
  this.isRenderStateDirty = true;
1509
- this.postProcessing = null;
1510
- this.outlineObjects = [];
1717
+ this.postProcessManager = null;
1511
1718
  this.postProcessParam = Object.assign({}, postProcessParam);
1512
1719
  this._app = app;
1513
1720
  if (viewportParam.elementId) {
@@ -1531,7 +1738,10 @@ class Viewport {
1531
1738
  this.resizeObserver.observe(this._outerContainer);
1532
1739
  }
1533
1740
  this.app.onCameraChangedDelegate.add(() => {
1534
- this.setupPostProcess();
1741
+ if (this.postProcessManager) {
1742
+ this.postProcessManager.updateCamera(this.app.camera);
1743
+ this.postProcessManager.setup();
1744
+ }
1535
1745
  });
1536
1746
  }
1537
1747
  createRenderer(rendererParam) {
@@ -1616,159 +1826,39 @@ class Viewport {
1616
1826
  this.setupPostProcess();
1617
1827
  }
1618
1828
  setupPostProcess() {
1619
- if (this.postProcessParam.steps.length === 0) {
1620
- this.destroyPostProcess();
1621
- this.markRenderStateDirty();
1622
- return;
1623
- }
1624
- if (!this.postProcessing) {
1625
- this.postProcessing = new webgpu.PostProcessing(this.renderer);
1829
+ if (!this.postProcessManager) {
1830
+ this.postProcessManager = new PostProcessManager(this.renderer, this.app.world.scene, this.app.camera, this.postProcessParam, () => this.markRenderStateDirty());
1626
1831
  }
1627
- const scenePass = WebGPUPostProcessFactory.constructScenePass(this.app.world.scene, this.app.camera);
1628
- let finalNode = scenePass.getTextureNode('output');
1629
- this.postProcessParam.steps.forEach((step) => {
1630
- switch (step.type) {
1631
- case exports.PostProcessStepType.Bloom:
1632
- {
1633
- const bloomPass = WebGPUPostProcessFactory.constructBloomPass(scenePass, step);
1634
- //console.log("[PostProcess] BloomPass 构建完成");
1635
- finalNode = finalNode.add(bloomPass);
1636
- break;
1637
- }
1638
- case exports.PostProcessStepType.DepthOfField:
1639
- {
1640
- const dofPass = WebGPUPostProcessFactory.constructDOFPass(scenePass, step);
1641
- //console.log("[PostProcess] DOFPass 构建完成");
1642
- finalNode = finalNode.add(dofPass);
1643
- break;
1644
- }
1645
- case exports.PostProcessStepType.ScreenSpaceReflection:
1646
- {
1647
- console.warn("[PostProcess] SSR 目前存在技术问题,暂不支持。");
1648
- // const ssrPass = WebGPUPostProcessFactory.constructSSRPass(scenePass, step as SSRParam);
1649
- // console.log("[PostProcess] SSRPass 构建完成");
1650
- //finalNode = blendColor(finalNode, ssrPass);
1651
- break;
1652
- }
1653
- case exports.PostProcessStepType.GroundTruthAmbientOcclusion:
1654
- {
1655
- console.warn("[PostProcess] AO 目前存在技术问题,暂不支持。");
1656
- // const stepParam = step as GTAOParam
1657
- // const GTAOPass = WebGPUPostProcessFactory.constructGTAOPass(scenePass, stepParam);
1658
- // console.log("[PostProcess] GTAOPass 构建完成");
1659
- // if (stepParam.denoised)
1660
- // {
1661
- // const denoiseGTAOPass = WebGPUPostProcessFactory.constructGTAODenoisePass(scenePass, GTAOPass, stepParam);
1662
- // console.log("[PostProcess] GTAODenoisePass 构建完成");
1663
- // finalNode = denoiseGTAOPass.mul(finalNode);
1664
- // }
1665
- // else
1666
- // {
1667
- // finalNode = GTAOPass.getTextureNode().mul(finalNode);
1668
- // }
1669
- break;
1670
- }
1671
- case exports.PostProcessStepType.Outline:
1672
- {
1673
- const outlineParam = step;
1674
- const outlinePass = WebGPUPostProcessFactory.constructOutlinePass(this.app.world.scene, scenePass.camera, this.outlineObjects, outlineParam);
1675
- const { visibleEdge, hiddenEdge } = outlinePass;
1676
- const pulsePeriod = tsl.uniform(outlineParam.pulsePeriod);
1677
- const period = tsl.time.div(pulsePeriod).mul(2);
1678
- const osc = tsl.oscSine(period).mul(.5).add(.5);
1679
- const outlineColor = visibleEdge.mul(tsl.uniform(new webgpu.Color(outlineParam.visibleEdgeColor))).add(hiddenEdge.mul(tsl.uniform(new webgpu.Color(outlineParam.hiddenEdgeColor)))).mul(outlineParam.edgeStrength);
1680
- const outlinePulse = pulsePeriod.greaterThan(0).select(outlineColor.mul(osc), outlineColor);
1681
- // if(!this.denoiseOutlinePass)
1682
- // {
1683
- // this.denoiseOutlinePass = WebGPUPostProcessFactory.constructDenoisePass(this.scenePass, outlinePulse, DefaultDenoiseParam);
1684
- // }
1685
- // outlinePulse = this.denoiseOutlinePass.mul(outlinePulse)
1686
- // finalNode = this.denoiseOutlinePass.mul(outlinePulse).add(finalNode);
1687
- finalNode = outlinePulse.add(finalNode);
1688
- //console.log("[PostProcess] OutlinePass 构建完成");
1689
- break;
1690
- }
1691
- case exports.PostProcessStepType.Antialiasing:
1692
- {
1693
- const aaParam = step;
1694
- if (aaParam.method === "fxaa") {
1695
- finalNode = WebGPUPostProcessFactory.constructFXAAPass(finalNode);
1696
- //console.log("[PostProcess] FXAAPass 构建完成");
1697
- }
1698
- if (aaParam.method === "smaa") {
1699
- finalNode = WebGPUPostProcessFactory.constructSMAAPass(finalNode);
1700
- //console.log("[PostProcess] SMAAPass 构建完成");
1701
- }
1702
- break;
1703
- }
1704
- }
1705
- });
1706
- this.postProcessing.outputNode = finalNode;
1707
- this.postProcessing.needsUpdate = true;
1708
- //console.log("[PostProcess] setup complete", this.postProcessParam.steps);
1709
- this.markRenderStateDirty();
1832
+ this.postProcessManager.setup();
1710
1833
  }
1711
1834
  updatePostProcess(steps) {
1712
- this.postProcessParam.steps = steps;
1713
- this.setupPostProcess();
1835
+ if (this.postProcessManager) {
1836
+ this.postProcessManager.updateSteps(steps);
1837
+ }
1714
1838
  }
1715
1839
  updateRendererSettings(data) {
1716
1840
  this.createRenderer(data);
1717
1841
  this.markRenderStateDirty();
1718
1842
  }
1719
- // updateBloomPass(params: BloomParam)
1720
- // {
1721
- // this.postProcessParam.bloom = { ...params };
1722
- // this.setupPostProcess();
1723
- // }
1724
- // updateGTAOParam(params: GTAOParam)
1725
- // {
1726
- // this.postProcessParam.gtao = { ...params };
1727
- // this.setupPostProcess();
1728
- // }
1729
- // updateDOFParam(params: DOFParam)
1730
- // {
1731
- // this.postProcessParam.dof = { ...params };
1732
- // this.setupPostProcess();
1733
- // }
1734
- // updateSSRParam(params: SSRParam)
1735
- // {
1736
- // this.postProcessParam.ssr = { ...params };
1737
- // this.setupPostProcess();
1738
- // }
1739
- // updateOutlineParam(params: OutlineParams)
1740
- // {
1741
- // this.postProcessParam.outline = { ...params }
1742
- // this.setupPostProcess();
1743
- // }
1744
- // updateAAParam(params: AAParams)
1745
- // {
1746
- // this.postProcessParam.aa = { ...params };
1747
- // this.setupPostProcess();
1748
- // }
1749
1843
  addOutlineObject(obj) {
1750
- if (!this.outlineObjects.includes(obj)) {
1751
- this.outlineObjects.push(obj);
1844
+ if (this.postProcessManager) {
1845
+ this.postProcessManager.addOutlineObject(obj);
1752
1846
  }
1753
- this.markRenderStateDirty();
1754
1847
  }
1755
1848
  setOutlineObjects(objects) {
1756
- this.outlineObjects.length = 0;
1757
- this.outlineObjects.push(...objects);
1758
- this.markRenderStateDirty();
1849
+ if (this.postProcessManager) {
1850
+ this.postProcessManager.setOutlineObjects(objects);
1851
+ }
1759
1852
  }
1760
1853
  removeOutlineObject(obj) {
1761
- const index = this.outlineObjects.indexOf(obj);
1762
- if (index > -1) {
1763
- this.outlineObjects.splice(index, 1);
1854
+ if (this.postProcessManager) {
1855
+ this.postProcessManager.removeOutlineObject(obj);
1764
1856
  }
1765
- this.markRenderStateDirty();
1766
1857
  }
1767
1858
  destroyPostProcess() {
1768
- this.outlineObjects = [];
1769
- if (this.postProcessing) {
1770
- this.postProcessing.dispose();
1771
- this.postProcessing = null;
1859
+ if (this.postProcessManager) {
1860
+ this.postProcessManager.destroy();
1861
+ this.postProcessManager = null;
1772
1862
  }
1773
1863
  }
1774
1864
  onWindowResize() {
@@ -1788,11 +1878,10 @@ class Viewport {
1788
1878
  }
1789
1879
  render() {
1790
1880
  if (!this.isRenderStateDirty) {
1881
+ console.log("render clean retrn");
1791
1882
  return;
1792
1883
  }
1793
- if (this.postProcessing) {
1794
- this.postProcessing.render();
1795
- }
1884
+ if (this.postProcessManager && this.postProcessManager.render()) ;
1796
1885
  else {
1797
1886
  this.renderer.render(this.app.world.scene, this.app.camera);
1798
1887
  }
@@ -1802,42 +1891,40 @@ class Viewport {
1802
1891
  this.isRenderStateDirty = false;
1803
1892
  }
1804
1893
  async renderAsImage(width = 1024, height = 1024) {
1805
- return new Promise(async (resolve, reject) => {
1806
- try {
1807
- if (this.postProcessing) {
1808
- await this.postProcessing.renderAsync();
1809
- }
1810
- else {
1811
- await this.renderer.renderAsync(this.app.world.scene, this.app.camera);
1812
- }
1813
- // 检查 renderer.domElement 的尺寸
1814
- const sourceWidth = this.renderer.domElement.width;
1815
- const sourceHeight = this.renderer.domElement.height;
1816
- // 如果源尺寸为0,则使用容器尺寸
1817
- let actualWidth = sourceWidth || width;
1818
- let actualHeight = sourceHeight || height;
1819
- if (actualWidth <= 0 || actualHeight <= 0) {
1820
- // 如果仍然无效,则使用默认值
1821
- actualWidth = width;
1822
- actualHeight = height;
1823
- }
1824
- const offscreenCanvas = document.createElement('canvas');
1825
- offscreenCanvas.width = width;
1826
- offscreenCanvas.height = height;
1827
- const context = offscreenCanvas.getContext('2d');
1828
- if (!context) {
1829
- throw Error("Can not create context");
1830
- }
1831
- // 使用实际尺寸进行绘制
1832
- context.drawImage(this.renderer.domElement, 0, 0, actualWidth, actualHeight, 0, 0, width, height);
1833
- const ret = offscreenCanvas.toDataURL('image/jpeg');
1834
- offscreenCanvas.remove();
1835
- resolve(ret);
1894
+ try {
1895
+ if (this.postProcessManager && await this.postProcessManager.renderAsync()) {
1896
+ // Post processing rendered
1836
1897
  }
1837
- catch (error) {
1838
- reject(error);
1898
+ else {
1899
+ await this.renderer.renderAsync(this.app.world.scene, this.app.camera);
1839
1900
  }
1840
- });
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
+ }
1841
1928
  }
1842
1929
  setAlpha(alpha) {
1843
1930
  if (!this._renderer) {
@@ -1888,7 +1975,6 @@ class Viewport {
1888
1975
  this._renderer.stencil = stencil;
1889
1976
  }
1890
1977
  destroy() {
1891
- var _a;
1892
1978
  this.destroyPostProcess();
1893
1979
  this.renderer.setAnimationLoop(null);
1894
1980
  if (this.resizeObserver) {
@@ -1904,11 +1990,8 @@ class Viewport {
1904
1990
  this._renderer.dispose();
1905
1991
  this._renderer = null;
1906
1992
  }
1907
- (_a = this.postProcessing) === null || _a === void 0 ? void 0 : _a.dispose();
1908
1993
  this._outerContainer = null;
1909
1994
  this._app = null;
1910
- this._renderer = null;
1911
- this.outlineObjects = [];
1912
1995
  }
1913
1996
  }
1914
1997
 
@@ -2066,195 +2149,248 @@ class Orbital extends Pawn {
2066
2149
  }
2067
2150
 
2068
2151
  class Controller {
2069
- get camera() {
2070
- return this._app.camera;
2071
- }
2072
- get world() {
2073
- return this._app.world;
2074
- }
2075
- get viewPort() {
2076
- return this._app.viewport;
2077
- }
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; }
2078
2163
  get pawn() {
2079
- if (!this._pawn) {
2164
+ if (!this._pawn)
2080
2165
  throw Error("pawn is null");
2081
- }
2082
2166
  return this._pawn;
2083
2167
  }
2084
- get app() {
2085
- return this._app;
2086
- }
2087
- get onClickNothingDelegate() {
2088
- return this._onClickNothingDelegate;
2089
- }
2090
2168
  constructor(app) {
2091
- this.prepareClickComponent = null;
2092
2169
  this._pawn = null;
2093
- this.onPointerMove = (event) => { this.onPointerMoveEvent(event); };
2094
- this.onPointerEnter = (event) => { this.onPointerEnterEvent(event); };
2095
- this.onPointerLeave = (event) => { this.onPointerLeaveEvent(event); };
2096
- this.onPointerUp = (event) => { this.onPointerUpEvent(event); };
2097
- this.onPointerDown = (event) => { this.onPointerDownEvent(event); };
2098
- this.pointerPosition = new webgpu.Vector2();
2099
- this.doubleClickDelay = 250; // 双击判定时间间隔(毫秒)
2100
- this.leftClickTimer = null;
2101
- this.pointerLeftDownPosition = new webgpu.Vector2();
2170
+ this.prepareClickComponent = null;
2171
+ this.prepareClickHit = null;
2102
2172
  this.hoveringComponent = null;
2103
2173
  this._pointButtonIsDown = new Set();
2104
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);
2105
2195
  this._app = app;
2106
2196
  this._pawn = new Orbital(this);
2107
2197
  this.pawn.possess();
2108
2198
  this.raycaster = new webgpu.Raycaster();
2109
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
+ }
2110
2208
  updateCamera() {
2111
2209
  var _a, _b;
2112
- let isPawnEnabled = this.pawn.enabled;
2210
+ const isPawnEnabled = this.pawn.enabled;
2113
2211
  (_a = this._pawn) === null || _a === void 0 ? void 0 : _a.unpossess();
2114
2212
  (_b = this._pawn) === null || _b === void 0 ? void 0 : _b.destroy();
2115
2213
  this._pawn = new Orbital(this);
2116
2214
  this.pawn.possess();
2117
2215
  this.pawn.enabled = isPawnEnabled;
2118
2216
  }
2119
- init() {
2120
- if (this.viewPort.canvas) {
2121
- this.viewPort.canvas.addEventListener("pointermove", this.onPointerMove);
2122
- this.viewPort.canvas.addEventListener("pointerenter", this.onPointerEnter);
2123
- this.viewPort.canvas.addEventListener("pointerleave", this.onPointerLeave);
2124
- this.viewPort.canvas.addEventListener("pointerup", this.onPointerUp);
2125
- this.viewPort.canvas.addEventListener("pointerdown", this.onPointerDown);
2126
- }
2127
- }
2128
2217
  tick(deltaTime) {
2129
2218
  this.pawn.tick(deltaTime);
2130
2219
  }
2131
2220
  destroy() {
2132
- if (this.leftClickTimer) {
2133
- clearTimeout(this.leftClickTimer);
2134
- this.leftClickTimer = null;
2135
- }
2136
- if (this.viewPort.canvas) {
2137
- this.viewPort.canvas.removeEventListener("pointermove", this.onPointerMove);
2138
- this.viewPort.canvas.removeEventListener("pointerenter", this.onPointerEnter);
2139
- this.viewPort.canvas.removeEventListener("pointerleave", this.onPointerLeave);
2140
- this.viewPort.canvas.removeEventListener("pointerup", this.onPointerUp);
2141
- 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();
2142
2228
  }
2143
2229
  this.pawn.unpossess();
2144
2230
  this.pawn.destroy();
2145
2231
  this._pawn = null;
2146
2232
  }
2147
2233
  onPointerMoveEvent(event) {
2148
- var _a, _b;
2149
- if (!this.viewPort.canvas) {
2234
+ const canvas = this.viewPort.canvas;
2235
+ if (!canvas)
2150
2236
  throw Error("canvas is null");
2151
- }
2152
- const canvasRect = this.viewPort.canvas.getBoundingClientRect();
2153
- const offsetX = canvasRect.left;
2154
- const offsetY = canvasRect.top;
2155
- const pointer = new webgpu.Vector2(((event.clientX - offsetX) / this.viewPort.canvas.clientWidth) * 2 - 1, 1 - ((event.clientY - offsetY) / this.viewPort.canvas.clientHeight) * 2);
2156
- this.pointerPosition = pointer;
2157
- 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)
2158
2240
  return;
2159
- }
2160
2241
  const hits = this.getHitResultUnderCursor();
2161
- if (hits) {
2162
- let component = hits.object.userData["LYObject"];
2163
- if (component != this.hoveringComponent) {
2164
- (_a = this.hoveringComponent) === null || _a === void 0 ? void 0 : _a.onHorveringEnd();
2165
- this.hoveringComponent = null;
2166
- if (component instanceof SceneComponent && component.isHoverEnabled) {
2167
- component.onHorveringBegin();
2168
- this.hoveringComponent = component;
2169
- }
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();
2170
2261
  }
2262
+ this.hoveringComponent = component;
2171
2263
  }
2172
2264
  else {
2173
- (_b = this.hoveringComponent) === null || _b === void 0 ? void 0 : _b.onHorveringEnd();
2265
+ this._onComponentHoverEndDelegate.broadcast(event);
2266
+ if (!event.handled) {
2267
+ component.onHorveringEnd();
2268
+ }
2174
2269
  this.hoveringComponent = null;
2175
2270
  }
2176
2271
  }
2177
2272
  onPointerUpEvent(event) {
2178
2273
  this._pointButtonIsDown.delete(event.button);
2179
- if (event.button === 0) {
2180
- const pointerOffset = new webgpu.Vector2().subVectors(this.pointerLeftDownPosition, this.pointerPosition).length();
2181
- if (pointerOffset > 0.005) {
2182
- if (this.leftClickTimer) {
2183
- window.clearTimeout(this.leftClickTimer);
2184
- this.leftClickTimer = null;
2185
- }
2186
- return;
2187
- }
2188
- if (!this.leftClickTimer) {
2189
- const hit = this.getHitResultUnderCursor();
2190
- let component = hit ? hit.object.userData["LYObject"] : null;
2191
- if (component && component instanceof SceneComponent && component.isClickEnabled) {
2192
- this.prepareClickComponent = component;
2193
- this.leftClickTimer = window.setTimeout(() => {
2194
- this.leftClickTimer = null;
2195
- if (this.prepareClickComponent) {
2196
- this.prepareClickComponent.onClicked();
2197
- this.prepareClickComponent = null;
2198
- }
2199
- }, this.doubleClickDelay);
2200
- }
2201
- else {
2202
- this._onClickNothingDelegate.broadcast();
2203
- }
2204
- }
2205
- else {
2206
- 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(() => {
2207
2296
  this.leftClickTimer = null;
2208
- if (this.prepareClickComponent) {
2209
- this.prepareClickComponent.onDoubleClicked();
2297
+ if (this.prepareClickComponent && this.prepareClickHit) {
2298
+ this.fireClickEvent(this.prepareClickComponent, this.prepareClickHit, false);
2299
+ this.prepareClickComponent = null;
2300
+ this.prepareClickHit = null;
2210
2301
  }
2211
- else {
2212
- this._onClickNothingDelegate.broadcast();
2213
- }
2214
- 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();
2215
2325
  }
2216
2326
  }
2327
+ else {
2328
+ this._onComponentClickDelegate.broadcast(event);
2329
+ if (!event.handled) {
2330
+ component.onClicked();
2331
+ }
2332
+ }
2333
+ }
2334
+ clearClickTimer() {
2335
+ if (this.leftClickTimer) {
2336
+ window.clearTimeout(this.leftClickTimer);
2337
+ this.leftClickTimer = null;
2338
+ }
2217
2339
  }
2218
2340
  onPointerDownEvent(event) {
2219
2341
  this._pointButtonIsDown.add(event.button);
2220
2342
  if (event.button === 0) {
2221
- 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);
2222
2350
  }
2223
2351
  }
2352
+ firePointerDownEvent(component, hit, button) {
2353
+ const event = { component, hit, button, handled: false };
2354
+ this._onComponentPointerDownDelegate.broadcast(event);
2355
+ }
2224
2356
  onPointerEnterEvent(event) {
2225
- if (!this.viewPort.canvas) {
2226
- throw Error("canvas is null");
2227
- }
2228
- this.viewPort.canvas.addEventListener("pointermove", this.onPointerMove);
2229
- this.viewPort.canvas.addEventListener("pointerup", this.onPointerUp);
2230
- this.viewPort.canvas.addEventListener("pointerdown", this.onPointerDown);
2357
+ this.addCorePointerListeners();
2231
2358
  }
2232
2359
  onPointerLeaveEvent(event) {
2233
- if (!this.viewPort.canvas) {
2234
- throw Error("canvas is null");
2235
- }
2236
- this.viewPort.canvas.removeEventListener("pointermove", this.onPointerMove);
2237
- this.viewPort.canvas.removeEventListener("pointerup", this.onPointerUp);
2238
- 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);
2239
2377
  }
2240
2378
  getHitResultUnderCursor() {
2241
2379
  return this.getHitResultFromScreenPoint(this.pointerPosition.x, this.pointerPosition.y);
2242
2380
  }
2243
2381
  getHitResultFromScreenPoint(x, y) {
2244
- this.raycaster.setFromCamera(new webgpu.Vector2(x, y), this.camera);
2245
- let out = this.raycaster.intersectObjects(this.world.scene.children, true);
2246
- for (let i = 0; i < out.length; i++) {
2247
- 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"])
2248
2387
  continue;
2249
- }
2250
- let component = out[i].object.userData["LYObject"];
2251
- if (!component) {
2388
+ const component = hit.object.userData["LYObject"];
2389
+ if (!component)
2252
2390
  continue;
2253
- }
2254
- if (!component.isHoverEnabled && !component.isClickEnabled) {
2391
+ if (!component.isHoverEnabled && !component.isClickEnabled)
2255
2392
  continue;
2256
- }
2257
- return out[i];
2393
+ return hit;
2258
2394
  }
2259
2395
  return null;
2260
2396
  }
@@ -3568,6 +3704,7 @@ class TransformGizmo extends Pawn {
3568
3704
  }
3569
3705
  }
3570
3706
 
3707
+ exports.ASSET_POINTER_KEY = ASSET_POINTER_KEY;
3571
3708
  exports.Actor = Actor;
3572
3709
  exports.AmbientLightActor = AmbientLightActor;
3573
3710
  exports.AmbientLightComponent = AmbientLightComponent;
@@ -3594,6 +3731,7 @@ exports.DefaultWorldParam = DefaultWorldParam;
3594
3731
  exports.Delegate = Delegate;
3595
3732
  exports.DirectionalLightActor = DirectionalLightActor;
3596
3733
  exports.DirectionalLightComponent = DirectionalLightComponent;
3734
+ exports.EDITOR_ASSET_ID_KEY = EDITOR_ASSET_ID_KEY;
3597
3735
  exports.FirstPerson = FirstPerson;
3598
3736
  exports.GeometryAssetPointer = GeometryAssetPointer;
3599
3737
  exports.LabelComponent = LabelComponent;