@realsee/dnalogel 4.0.0-webgpu.3 → 4.0.0-webgpu.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/floorplan.js +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +270 -35
  5. package/dist/index.js.map +1 -0
  6. package/dist/internal/{BasePlugin-CT5K8m36.js → BasePlugin-DC5m72La.js} +3 -3
  7. package/dist/internal/{BasePlugin-CT5K8m36.js.map → BasePlugin-DC5m72La.js.map} +1 -1
  8. package/dist/internal/BasePluginWithData-D_0W46_q.js +7 -0
  9. package/dist/internal/{BasePluginWithData-9z4tpAT4.js.map → BasePluginWithData-D_0W46_q.js.map} +1 -1
  10. package/dist/internal/{BetterTween-BX0aTvP1.js → BetterTween-DmptqE8m.js} +2 -2
  11. package/dist/internal/{BetterTween-BX0aTvP1.js.map → BetterTween-DmptqE8m.js.map} +1 -1
  12. package/dist/internal/{CSS3DRenderPlugin-ccSpcvwd.js → CSS3DRenderPlugin-CEatgl0m.js} +3 -3
  13. package/dist/internal/CSS3DRenderPlugin-CEatgl0m.js.map +1 -0
  14. package/dist/internal/{Controller-Csut_kcH.js → Controller-D6o4OGWJ.js} +8 -8
  15. package/dist/internal/{Controller-Csut_kcH.js.map → Controller-D6o4OGWJ.js.map} +1 -1
  16. package/dist/internal/{FiveDomEvents-3H9NvDOz.js → FiveDomEvents-BUBLFzti.js} +2 -2
  17. package/dist/internal/{FiveDomEvents-3H9NvDOz.js.map → FiveDomEvents-BUBLFzti.js.map} +1 -1
  18. package/dist/internal/FivePuppet-C6QmVY70.js +67 -0
  19. package/dist/internal/FivePuppet-C6QmVY70.js.map +1 -0
  20. package/dist/internal/{PointHelper-D565h9b_.js → PointHelper-DIhgdjY2.js} +48 -48
  21. package/dist/internal/{PointHelper-D565h9b_.js.map → PointHelper-DIhgdjY2.js.map} +1 -1
  22. package/dist/internal/{Polygon-CBGvYUfJ.js → Polygon-D3xIL1Pl.js} +30 -30
  23. package/dist/internal/{Polygon-CBGvYUfJ.js.map → Polygon-D3xIL1Pl.js.map} +1 -1
  24. package/dist/internal/{Prism-Dm5ESkgg.js → Prism-CJlyAEAU.js} +13 -13
  25. package/dist/internal/{Prism-Dm5ESkgg.js.map → Prism-CJlyAEAU.js.map} +1 -1
  26. package/dist/internal/{Rectangle-D-zkDycu.js → Rectangle-BpL9lNKU.js} +118 -129
  27. package/dist/internal/Rectangle-BpL9lNKU.js.map +1 -0
  28. package/dist/internal/{Work-DF8j5GnL.js → Work-BE4AgdwH.js} +9 -9
  29. package/dist/internal/{Work-DF8j5GnL.js.map → Work-BE4AgdwH.js.map} +1 -1
  30. package/dist/internal/{animationFrame-XGKHIeQK.js → animationFrame-CacKXN8l.js} +14 -3
  31. package/dist/internal/animationFrame-CacKXN8l.js.map +1 -0
  32. package/dist/internal/{area-maker-Bd9l2pIp.js → area-maker-Bnhx4SkH.js} +4 -4
  33. package/dist/internal/{area-maker-Bd9l2pIp.js.map → area-maker-Bnhx4SkH.js.map} +1 -1
  34. package/dist/internal/{boundingBox-DvCor5Hd.js → boundingBox-CIqXgNXW.js} +2 -2
  35. package/dist/internal/{boundingBox-DvCor5Hd.js.map → boundingBox-CIqXgNXW.js.map} +1 -1
  36. package/dist/internal/{camera-movement-CwI7UqUk.js → camera-movement-C1pwfMk_.js} +2 -2
  37. package/dist/internal/camera-movement-C1pwfMk_.js.map +1 -0
  38. package/dist/internal/{changeMode-BVGYCoqu.js → changeMode-D_I2AOjH.js} +2 -2
  39. package/dist/internal/{changeMode-BVGYCoqu.js.map → changeMode-D_I2AOjH.js.map} +1 -1
  40. package/dist/internal/{controller-BWkZT0l1.js → controller-DIDtFrBE.js} +1991 -2050
  41. package/dist/internal/controller-DIDtFrBE.js.map +1 -0
  42. package/dist/internal/{cruise-C3F0eNQ-.js → cruise-B50Tcq66.js} +2 -2
  43. package/dist/internal/{cruise-C3F0eNQ-.js.map → cruise-B50Tcq66.js.map} +1 -1
  44. package/dist/internal/{current-pano-image-DKUWluR-.js → current-pano-image-BCFr6njt.js} +4 -4
  45. package/dist/internal/{current-pano-image-DKUWluR-.js.map → current-pano-image-BCFr6njt.js.map} +1 -1
  46. package/dist/internal/{defaultUrls-CjKkS9k9.js → defaultUrls-CfMtGzqM.js} +14 -3
  47. package/dist/internal/defaultUrls-CfMtGzqM.js.map +1 -0
  48. package/dist/internal/{fire-scene-CczaBz2_.js → fire-scene-BzZGvyh_.js} +9 -4
  49. package/dist/internal/fire-scene-BzZGvyh_.js.map +1 -0
  50. package/dist/internal/{fiveModelLoad-mg-TnpnM.js → fiveModelLoad-BUIBYxzp.js} +2 -2
  51. package/dist/internal/{fiveModelLoad-mg-TnpnM.js.map → fiveModelLoad-BUIBYxzp.js.map} +1 -1
  52. package/dist/internal/{floorplan-KWlIsTvO.js → floorplan-C8BGw87S.js} +5 -5
  53. package/dist/internal/{floorplan-KWlIsTvO.js.map → floorplan-C8BGw87S.js.map} +1 -1
  54. package/dist/internal/{generatePolygonGeometry-B_5JFq8y.js → generatePolygonGeometry-BOnzdCaG.js} +181 -178
  55. package/dist/internal/generatePolygonGeometry-BOnzdCaG.js.map +1 -0
  56. package/dist/internal/{lookObject-wesf8xt6.js → lookObject-DuRab5wf.js} +2 -2
  57. package/dist/internal/{lookObject-wesf8xt6.js.map → lookObject-DuRab5wf.js.map} +1 -1
  58. package/dist/internal/{measure-BX6boAC7.js → measure-B4jFwdQ6.js} +5 -5
  59. package/dist/internal/{measure-BX6boAC7.js.map → measure-B4jFwdQ6.js.map} +1 -1
  60. package/dist/internal/{model-chassis-compass-InVNmOAQ.js → model-chassis-compass-C6NTVMLo.js} +2 -2
  61. package/dist/internal/{model-chassis-compass-InVNmOAQ.js.map → model-chassis-compass-C6NTVMLo.js.map} +1 -1
  62. package/dist/internal/{model-entry-door-guide-wZbyY77a.js → model-entry-door-guide-DnGTLY2s.js} +2 -2
  63. package/dist/internal/{model-entry-door-guide-wZbyY77a.js.map → model-entry-door-guide-DnGTLY2s.js.map} +1 -1
  64. package/dist/internal/{model-maker-uO8xlTuO.js → model-maker-B1mnDdKY.js} +15 -15
  65. package/dist/internal/{model-maker-uO8xlTuO.js.map → model-maker-B1mnDdKY.js.map} +1 -1
  66. package/dist/internal/{model-tv-video-DzXb2JRf.js → model-tv-video-BP-7HoDC.js} +2 -2
  67. package/dist/internal/{model-tv-video-DzXb2JRf.js.map → model-tv-video-BP-7HoDC.js.map} +1 -1
  68. package/dist/internal/{model-view-CBeeMM98.js → model-view-BWUU0-uq.js} +2 -2
  69. package/dist/internal/{model-view-CBeeMM98.js.map → model-view-BWUU0-uq.js.map} +1 -1
  70. package/dist/internal/object3d-helper-CbRRhnLV.js +7 -0
  71. package/dist/internal/{object3d-helper-DDYsVPN6.js.map → object3d-helper-CbRRhnLV.js.map} +1 -1
  72. package/dist/internal/{pano-compass-jSr629BP.js → pano-compass-BRTM0dCc.js} +7 -7
  73. package/dist/internal/{pano-compass-jSr629BP.js.map → pano-compass-BRTM0dCc.js.map} +1 -1
  74. package/dist/internal/{pano-door-label-DKoYIKLa.js → pano-door-label-BLjYGZrr.js} +3 -3
  75. package/dist/internal/{pano-door-label-DKoYIKLa.js.map → pano-door-label-BLjYGZrr.js.map} +1 -1
  76. package/dist/internal/{pano-measure-DW9mdx1O.js → pano-measure-BIgCWkVJ.js} +14 -14
  77. package/dist/internal/{pano-measure-DW9mdx1O.js.map → pano-measure-BIgCWkVJ.js.map} +1 -1
  78. package/dist/internal/{pano-ruler-pro-D7q0Ob21.js → pano-ruler-pro-D9yTbHJz.js} +2 -2
  79. package/dist/internal/{pano-ruler-pro-D7q0Ob21.js.map → pano-ruler-pro-D9yTbHJz.js.map} +1 -1
  80. package/dist/internal/{pano-spatial-tag-D0qn-__S.js → pano-spatial-tag-B7Gxn3BS.js} +3 -3
  81. package/dist/internal/{pano-spatial-tag-D0qn-__S.js.map → pano-spatial-tag-B7Gxn3BS.js.map} +1 -1
  82. package/dist/internal/{pano-tag-BW5MXXws.js → pano-tag-Bchz-jED.js} +2 -2
  83. package/dist/internal/{pano-tag-BW5MXXws.js.map → pano-tag-Bchz-jED.js.map} +1 -1
  84. package/dist/internal/{pano-video-Bmud_CAn.js → pano-video-BufYQMqo.js} +3 -3
  85. package/dist/internal/{pano-video-Bmud_CAn.js.map → pano-video-BufYQMqo.js.map} +1 -1
  86. package/dist/internal/{pipeline-DDqgb1gw.js → pipeline-t_3IMXKB.js} +4 -4
  87. package/dist/internal/{pipeline-DDqgb1gw.js.map → pipeline-t_3IMXKB.js.map} +1 -1
  88. package/dist/internal/{sculpt-BNkLJR6p.js → sculpt-BCK4PMwL.js} +64 -63
  89. package/dist/internal/{sculpt-BNkLJR6p.js.map → sculpt-BCK4PMwL.js.map} +1 -1
  90. package/dist/internal/tagPosition-DA9YguT8.js +176 -0
  91. package/dist/internal/tagPosition-DA9YguT8.js.map +1 -0
  92. package/dist/internal/withResolvers-DVr4bnnk.js +15 -0
  93. package/dist/internal/withResolvers-DVr4bnnk.js.map +1 -0
  94. package/dist/plugins/area-maker.js +1 -1
  95. package/dist/plugins/camera-movement.js +1 -1
  96. package/dist/plugins/cruise.js +2 -2
  97. package/dist/plugins/css3d-render.js +1 -1
  98. package/dist/plugins/current-pano-image.js +1 -1
  99. package/dist/plugins/digital-performance.d.ts +1 -1
  100. package/dist/plugins/digital-performance.js +1 -1
  101. package/dist/plugins/fire-scene.d.ts +1 -1
  102. package/dist/plugins/fire-scene.js +1 -1
  103. package/dist/plugins/guide-line.js +1 -1
  104. package/dist/plugins/measure.js +1 -1
  105. package/dist/plugins/model-chassis-compass.js +1 -1
  106. package/dist/plugins/model-entry-door-guide.js +1 -1
  107. package/dist/plugins/model-maker.d.ts +1 -1
  108. package/dist/plugins/model-maker.js +1 -1
  109. package/dist/plugins/model-tv-video.js +1 -1
  110. package/dist/plugins/model-view.js +1 -1
  111. package/dist/plugins/object3d-helper.d.ts +1 -1
  112. package/dist/plugins/object3d-helper.js +3 -1
  113. package/dist/plugins/pano-compass.js +1 -1
  114. package/dist/plugins/pano-door-label.js +1 -1
  115. package/dist/plugins/pano-measure.js +1 -1
  116. package/dist/plugins/pano-ruler-pro.js +1 -1
  117. package/dist/plugins/pano-spatial-tag.js +1 -1
  118. package/dist/plugins/pano-tag.d.ts +1 -1
  119. package/dist/plugins/pano-tag.js +4 -1
  120. package/dist/plugins/pano-video.js +1 -1
  121. package/dist/plugins/pipeline.js +1 -1
  122. package/dist/plugins/sculpt.d.ts +1 -1
  123. package/dist/plugins/sculpt.js +7 -1
  124. package/dist/types/public/index.d.ts +2 -0
  125. package/dist/types/public/plugins/digital-performance.d.ts +1 -0
  126. package/dist/types/public/plugins/fire-scene.d.ts +1 -0
  127. package/dist/types/public/plugins/model-maker.d.ts +1 -0
  128. package/dist/types/public/plugins/object3d-helper.d.ts +1 -0
  129. package/dist/types/public/plugins/pano-tag.d.ts +2 -0
  130. package/dist/types/public/plugins/sculpt.d.ts +8 -0
  131. package/dist/types/public/utils.d.ts +5 -0
  132. package/dist/utils.d.ts +1 -1
  133. package/dist/utils.js +16 -50
  134. package/package.json +1 -1
  135. package/dist/internal/BasePluginWithData-9z4tpAT4.js +0 -7
  136. package/dist/internal/CSS3DRenderPlugin-ccSpcvwd.js.map +0 -1
  137. package/dist/internal/Rectangle-D-zkDycu.js.map +0 -1
  138. package/dist/internal/animationFrame-XGKHIeQK.js.map +0 -1
  139. package/dist/internal/blink-DD_0mH-m.js +0 -113
  140. package/dist/internal/blink-DD_0mH-m.js.map +0 -1
  141. package/dist/internal/camera-movement-CwI7UqUk.js.map +0 -1
  142. package/dist/internal/controller-BWkZT0l1.js.map +0 -1
  143. package/dist/internal/defaultUrls-CjKkS9k9.js.map +0 -1
  144. package/dist/internal/fire-scene-CczaBz2_.js.map +0 -1
  145. package/dist/internal/generatePolygonGeometry-B_5JFq8y.js.map +0 -1
  146. package/dist/internal/object3d-helper-DDYsVPN6.js +0 -7
  147. package/dist/utils.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"defaultUrls-CjKkS9k9.js","names":["DEFAULT_STATIC_PREFIX","GUIDELINE_DEFAULT_ARROW_TEXTURE","GUIDELINE_WHITE_ARROW_TEXTURE","PANO_SPATIAL_TAG_BLUR_IMAGE","PANO_TAG_DEFAULT_LINK_ICON","MODEL_CHASSIS_COMPASS_DEFAULT_MODEL","CURRENT_PANO_IMAGE_DEFAULT_IMAGE","MODEL_ENTRY_DOOR_GUIDE_PLUGIN_DEFAULT_MODEL","FLOORPLAN_DEFAULT_IMAGE","PANO_COMPASS_DEFAULT_IMAGE","ENTRY_DOOR_DEFAULT_IMAGE"],"sources":["../../src/shared-utils/url/defaultUrls.ts"],"sourcesContent":["/**\n * 默认资源URL配置\n * 集中管理所有插件使用的默认资源链接\n */\n\n/** 默认的静态资源前缀 */\nexport const DEFAULT_STATIC_PREFIX = '//vr-image-4.realsee-cdn.cn'\n\n/** GuideLinePlugin 默认箭头贴图 */\nexport const GUIDELINE_DEFAULT_ARROW_TEXTURE = `//vr-image-4.realsee-cdn.cn/release/web/arrow1.ebe7d0ff.png`\n\n/** GuideLinePlugin 白色箭头贴图(用于配置) */\nexport const GUIDELINE_WHITE_ARROW_TEXTURE = `//vr-image-4.realsee-cdn.cn/release/web/arrow-white.5c2c79a5.png`\n\n/** PanoSpatialTagPlugin 模糊图片 */\nexport const PANO_SPATIAL_TAG_BLUR_IMAGE = `//vr-image-4.realsee-cdn.cn/release/web/PanoSpatialTagPlugin__blur.png`\n\n/** PanoTagPlugin 默认链接图标 */\nexport const PANO_TAG_DEFAULT_LINK_ICON = `//vr-image-4.realsee-cdn.cn/release/web/test.09dee741.png`\n\n/** ModelChassisCompassPlugin 默认模型 */\nexport const MODEL_CHASSIS_COMPASS_DEFAULT_MODEL = `//vr-image-4.realsee-cdn.cn/release/web/dipan2.f38a21cc.FBX`\n\n/** CurrentPanoImagePlugin 默认图片 */\nexport const CURRENT_PANO_IMAGE_DEFAULT_IMAGE = `//vr-image-4.realsee-cdn.cn/release/web/logo.7febb17f.png`\n\n/** ModelEntryDoorGuidePlugin 默认模型 */\nexport const MODEL_ENTRY_DOOR_GUIDE_PLUGIN_DEFAULT_MODEL = `//vr-public.realsee-cdn.cn/release/web/entryDoorMini/Anim_Door1.fbx`\n\n/** MapviewFloorplanPlugin 默认图片 */\nexport const FLOORPLAN_DEFAULT_IMAGE = `//vr-image-4.realsee-cdn.cn/release/web/saas/missing-floorplan.e274c596.png`\n\n/** PanoCompassPlugin 默认图片 */\nexport const PANO_COMPASS_DEFAULT_IMAGE = `//vr-image-4.realsee-cdn.cn/release/web/v3/north-point-circle.96498e69.png`\n\n/** PanoCompassPlugin 默认图片 */\nexport const ENTRY_DOOR_DEFAULT_IMAGE = `//vr-image-4.realsee-cdn.cn/release/web/enterDoor.831b8208.png`\n\n/**\n * 默认资源URL列表, 用于提供给应用读取默认资源, 并进行转换\n */\nexport const DNALOGEL_DEFAULT_ASSETS = [\n GUIDELINE_DEFAULT_ARROW_TEXTURE,\n GUIDELINE_WHITE_ARROW_TEXTURE,\n PANO_SPATIAL_TAG_BLUR_IMAGE,\n PANO_TAG_DEFAULT_LINK_ICON,\n MODEL_CHASSIS_COMPASS_DEFAULT_MODEL,\n CURRENT_PANO_IMAGE_DEFAULT_IMAGE,\n MODEL_ENTRY_DOOR_GUIDE_PLUGIN_DEFAULT_MODEL,\n FLOORPLAN_DEFAULT_IMAGE,\n PANO_COMPASS_DEFAULT_IMAGE,\n ENTRY_DOOR_DEFAULT_IMAGE,\n]\n"],"mappings":";AAMA,IAAaA,IAAwB,+BAGxBC,IAAkC,+DAGlCC,IAAgC,oEAGhCC,IAA8B,0EAG9BC,IAA6B,6DAG7BC,IAAsC,+DAGtCC,IAAmC,6DAGnCC,IAA8C,uEAG9CC,IAA0B,+EAG1BC,IAA6B,8EAG7BC,IAA2B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fire-scene-CczaBz2_.js","names":["loadTexture","transformPosition","WorkUtil","lookObject","THREE","FIRE_ACTION_DURATION_MS","SPREAD_COVERAGE_TARGET","MODEL_SCALE_RANGE","random","base","spread","randomVector","tweenNumber","last","tween","time","index","progress","tweenVector","target","Particle","fallbackTexture","mapNode","texture","options","material","uv","vec4","attribute","geometry","camera","value","timeMilliseconds","emitterAge","particleCount","instance","delay","birthTime","position","z","theta","radius","velocity","positionOffset","age","ageSquared","required","capacity","colorAttribute","opacityAttribute","offset","size","measureSpreadBounds","minX","minY","minZ","maxX","maxY","maxZ","bounds","width","height","depth","speedToGrowth","speedMultiplier","spreadSpeed","DEFAULT_FIRE_GROWTH_CONFIG","buildFireGrowthConfig","maxFires","volume","fireSizeFactor","fireSize","fireSizeMultiplier","interval","diagonal","RadialSpread","stepLength","cx0","cz0","currentRing","maxNew","cells","ix","iz","cx","cz","key","ring","phase","growthLevel","density","rand2","jitterRange","jx","jz","s","hashString","seed","x","h","i","str","disposeParticle","particle","FireManager","scene","particleTexture","finalConfig","config","fireData","positions","id","scale","name","firesReached","coverageReached","radiusReached","newFire","scaleJitter","level","totalTime","extinguishTime","totalSteps","extinguishRate","extinguishStartTime","extinguishTimer","currentRate","particleToRemove","timeElapsed","onComplete","fadeInTime","step","newConfig","oldBase","delta","newBasePosition","opacity","NormalSmokeManager","source","intensity","fadeInMs","steps","durationMs","targetIntensity","smokePosition","spreadFactor","SmokeManager","previous","state","derivedId","coverage","derived","spreadState","SMOKE_SPREAD_FADE_IN_MS","buildSmokeSpreadConfig","maxSources","intensityFactor","getTextureLoader","cache","url","texturePromise","ParticleTexture","listener","SMOKE_RENDER_CONFIG","clampModelScale","FireControl","five","entry","workCode","nextWaterGun","nextParticle","resolver","check","kind","worldPosition","worldBounds","nextSize","spreadBounds","visible","floorIndex","smokeManager","sourceIds","startIntensities","sourceId","startIntensity","token","result","loadGLTF","rotation","spray","firefighter","fire","smoke","entitySize","boxSize","placeholder","pending","corners","y","box","firefighterId","UNIT_BOX_VERTICES","getAreaVertices","matrix4","matrix","vertex","getAreaBox3","FireScenePlayer","fireControl","absoluteMs","endMs","startsAt","timer","model","executed","item","area","duration","error"],"sources":["../../src/FireScenePlugin/constants.ts","../../src/shared-utils/rendering/Particle.ts","../../src/FireScenePlugin/utils/spread.ts","../../src/FireScenePlugin/fire/config.ts","../../src/FireScenePlugin/utils/radialSpread.ts","../../src/FireScenePlugin/utils/particle.ts","../../src/FireScenePlugin/fire/managers/FireManager.ts","../../src/FireScenePlugin/smoke/managers/NormalSmokeManager.ts","../../src/FireScenePlugin/smoke/managers/SmokeManager.ts","../../src/FireScenePlugin/smoke/config.ts","../../src/shared-utils/three/getTextureLoader.ts","../../src/FireScenePlugin/utils/particleTexture.ts","../../src/FireScenePlugin/FireControl.ts","../../src/FireScenePlugin/utils/areaBounds.ts","../../src/FireScenePlugin/SequencePlayer.ts"],"sourcesContent":["import type { FireModelType, FireSequenceKind } from './typing'\n\n/**\n * 各动作的播放时长(毫秒)。\n */\nexport const FIRE_ACTION_DURATION_MS: Record<FireSequenceKind, Partial<Record<FireModelType, number>>> = {\n /** 起火序列 */\n ignite: {\n /** 火焰淡入时间 */\n fire: 2000,\n /** 烟雾淡入时间 */\n smoke: 2000,\n },\n /** 灭火序列 */\n extinguish: {\n /** 消防员出现,立刻出现,无淡入效果 */\n firefighter: 0,\n /** 火焰淡出时间 */\n fire: 2000,\n /** 烟雾淡出时间 */\n smoke: 2000,\n },\n}\n\n/**\n * 起火点的蔓延速度:值越大,火势铺开越快。\n */\nexport const FIRE_SPREAD_SPEED = 2.0\n\n/**\n * 浓度渐变的分步间隔(毫秒)。\n */\nexport const FADE_STEP_MS = 100\n\n/**\n * 蔓延的目标覆盖率:铺开的面积占比达到它就停止蔓延。\n */\nexport const SPREAD_COVERAGE_TARGET = 0.85\n\n/**\n * 单次蔓延步进最多新增的网格数。\n */\nexport const MAX_SPREAD_CELLS_PER_STEP = 320\n\n/**\n * 模型的尺寸范围(相对原始尺寸的倍率)。\n */\nexport const MODEL_SCALE_RANGE = { min: 0.1, max: 5 } as const\n","import * as THREE from 'three/webgpu'\nimport { attribute, texture, uv, vec4 } from 'three/tsl'\n\nexport type ParticleType = 'CUBE' | 'SPHERE'\n\nexport interface ParticleTween<T> {\n times: number[]\n values: T[]\n}\n\nexport interface ParticleOptions {\n positionBase: THREE.Vector3\n positionStyle: ParticleType\n positionCubeSpread: THREE.Vector3\n positionSphereSpread: number\n velocityStyle: ParticleType\n velocityCubeBase: THREE.Vector3\n velocityCubeSpread: THREE.Vector3\n velocitySphereBase: number\n velocitySphereSpread: number\n accelerationBase: THREE.Vector3\n accelerationSpread: THREE.Vector3\n angleBase: number\n angleSpread: number\n angleVelocityBase: number\n angleVelocitySpread: number\n angleAccelerationBase: number\n angleAccelerationSpread: number\n sizeBase: number\n sizeSpread: number\n sizeTween: ParticleTween<number> | null\n colorBase: THREE.Vector3\n colorSpread: THREE.Vector3\n colorTween: ParticleTween<THREE.Vector3> | null\n opacityBase: number\n opacitySpread: number\n opacityTween: ParticleTween<number> | null\n texture: THREE.Texture\n blending: THREE.Blending\n particlesPerSecond: number\n particleDeathAge: number\n}\n\ninterface ParticleInstance {\n birthTime: number\n position: THREE.Vector3\n velocity: THREE.Vector3\n acceleration: THREE.Vector3\n angle: number\n angleVelocity: number\n angleAcceleration: number\n color: THREE.Vector3\n size: number\n opacity: number\n}\n\nfunction random(base: number, spread: number): number {\n return base + spread * (Math.random() - 0.5)\n}\n\nfunction randomVector(base: THREE.Vector3, spread: THREE.Vector3): THREE.Vector3 {\n return new THREE.Vector3(random(base.x, spread.x), random(base.y, spread.y), random(base.z, spread.z))\n}\n\nfunction tweenNumber(tween: ParticleTween<number>, time: number): number {\n const last = tween.times.length - 1\n if (last < 0) return 0\n if (time <= tween.times[0]) return tween.values[0]\n if (time >= tween.times[last]) return tween.values[last]\n\n let index = 1\n while (time > tween.times[index]) index += 1\n const progress = (time - tween.times[index - 1]) / (tween.times[index] - tween.times[index - 1])\n return THREE.MathUtils.lerp(tween.values[index - 1], tween.values[index], progress)\n}\n\nfunction tweenVector(tween: ParticleTween<THREE.Vector3>, time: number, target: THREE.Vector3): THREE.Vector3 {\n const last = tween.times.length - 1\n if (last < 0) return target.set(0, 0, 0)\n if (time <= tween.times[0]) return target.copy(tween.values[0])\n if (time >= tween.times[last]) return target.copy(tween.values[last])\n\n let index = 1\n while (time > tween.times[index]) index += 1\n const progress = (time - tween.times[index - 1]) / (tween.times[index] - tween.times[index - 1])\n return target.copy(tween.values[index - 1]).lerp(tween.values[index], progress)\n}\n\nexport class Particle extends THREE.InstancedMesh<THREE.PlaneGeometry, THREE.MeshBasicNodeMaterial> {\n public needsRender = true\n public paused = false\n\n public positionBase: THREE.Vector3\n public positionStyle: ParticleType\n public positionCubeSpread: THREE.Vector3\n public positionSphereSpread: number\n public velocityStyle: ParticleType\n public velocityCubeBase: THREE.Vector3\n public velocityCubeSpread: THREE.Vector3\n public velocitySphereBase: number\n public velocitySphereSpread: number\n public accelerationBase: THREE.Vector3\n public accelerationSpread: THREE.Vector3\n public angleBase: number\n public angleSpread: number\n public angleVelocityBase: number\n public angleVelocitySpread: number\n public angleAccelerationBase: number\n public angleAccelerationSpread: number\n public sizeBase: number\n public sizeSpread: number\n public sizeTween: ParticleTween<number> | null\n public colorBase: THREE.Vector3\n public colorSpread: THREE.Vector3\n public colorTween: ParticleTween<THREE.Vector3> | null\n public opacityBase: number\n public opacitySpread: number\n public opacityTween: ParticleTween<number> | null\n public particlesPerSecond: number\n public particleDeathAge: number\n\n private disposed = false\n private emissionStartTime: number | null = null\n private capacity = 1\n private instances: Array<ParticleInstance | undefined> = []\n private colors = new Float32Array(3)\n private opacities = new Float32Array(1)\n private sizes = new Float32Array(1)\n private angles = new Float32Array(1)\n private positions = new Float32Array(3)\n private readonly mapNode\n private readonly fallbackTexture: THREE.DataTexture\n private readonly localCameraQuaternion = new THREE.Quaternion()\n private readonly worldQuaternion = new THREE.Quaternion()\n private readonly angleQuaternion = new THREE.Quaternion()\n private readonly instanceTransform = new THREE.Matrix4()\n private readonly scaleVector = new THREE.Vector3()\n private readonly color = new THREE.Color()\n private readonly hsl = new THREE.Vector3()\n private readonly zAxis = new THREE.Vector3(0, 0, 1)\n\n public constructor(options: Partial<ParticleOptions>) {\n const fallbackTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1)\n fallbackTexture.needsUpdate = true\n const mapNode = texture(options.texture ?? fallbackTexture)\n const material = new THREE.MeshBasicNodeMaterial({\n transparent: true,\n depthWrite: false,\n blending: options.blending ?? THREE.NormalBlending,\n side: THREE.DoubleSide,\n })\n material.colorNode = mapNode\n .sample(uv())\n .mul(vec4(attribute<'vec3'>('particleColor', 'vec3'), attribute<'float'>('particleOpacity', 'float')))\n material.alphaTest = 0.001\n\n const geometry = new THREE.PlaneGeometry(1, 1)\n geometry.setAttribute('particleColor', new THREE.InstancedBufferAttribute(new Float32Array(3), 3))\n geometry.setAttribute('particleOpacity', new THREE.InstancedBufferAttribute(new Float32Array(1), 1))\n super(geometry, material, 1)\n this.colors = geometry.getAttribute('particleColor').array as Float32Array<ArrayBuffer>\n this.opacities = geometry.getAttribute('particleOpacity').array as Float32Array<ArrayBuffer>\n\n this.fallbackTexture = fallbackTexture\n this.mapNode = mapNode\n this.count = 0\n this.frustumCulled = false\n\n this.positionBase = options.positionBase?.clone() ?? new THREE.Vector3()\n this.positionStyle = options.positionStyle ?? 'CUBE'\n this.positionCubeSpread = options.positionCubeSpread?.clone() ?? new THREE.Vector3()\n this.positionSphereSpread = options.positionSphereSpread ?? 0\n this.velocityStyle = options.velocityStyle ?? 'CUBE'\n this.velocityCubeBase = options.velocityCubeBase?.clone() ?? new THREE.Vector3()\n this.velocityCubeSpread = options.velocityCubeSpread?.clone() ?? new THREE.Vector3()\n this.velocitySphereBase = options.velocitySphereBase ?? 0\n this.velocitySphereSpread = options.velocitySphereSpread ?? 0\n this.accelerationBase = options.accelerationBase?.clone() ?? new THREE.Vector3()\n this.accelerationSpread = options.accelerationSpread?.clone() ?? new THREE.Vector3()\n this.angleBase = options.angleBase ?? 0\n this.angleSpread = options.angleSpread ?? 0\n this.angleVelocityBase = options.angleVelocityBase ?? 0\n this.angleVelocitySpread = options.angleVelocitySpread ?? 0\n this.angleAccelerationBase = options.angleAccelerationBase ?? 0\n this.angleAccelerationSpread = options.angleAccelerationSpread ?? 0\n this.sizeBase = options.sizeBase ?? 0.1\n this.sizeSpread = options.sizeSpread ?? 0\n this.sizeTween = options.sizeTween ?? null\n this.colorBase = options.colorBase?.clone() ?? new THREE.Vector3()\n this.colorSpread = options.colorSpread?.clone() ?? new THREE.Vector3()\n this.colorTween = options.colorTween ?? null\n this.opacityBase = options.opacityBase ?? (options.opacityTween ? 0 : 1)\n this.opacitySpread = options.opacitySpread ?? 0\n this.opacityTween = options.opacityTween ?? null\n this.particlesPerSecond = options.particlesPerSecond ?? 60\n this.particleDeathAge = options.particleDeathAge ?? 1\n\n this.onBeforeRender = (_renderer, _scene, camera) => {\n this.worldQuaternion.setFromRotationMatrix(this.matrixWorld).invert()\n this.localCameraQuaternion.copy(this.worldQuaternion).multiply(camera.quaternion)\n this.updateMatrices()\n }\n }\n\n public get texture(): THREE.Texture | null {\n return this.mapNode.value === this.fallbackTexture ? null : this.mapNode.value\n }\n\n public set texture(value: THREE.Texture | null) {\n this.mapNode.value = value ?? this.fallbackTexture\n this.material.needsUpdate = true\n }\n\n public get blending(): THREE.Blending {\n return this.material.blending\n }\n\n public set blending(value: THREE.Blending) {\n this.material.blending = value\n this.material.needsUpdate = true\n }\n\n public pause(): void {\n if (this.paused) return\n this.paused = true\n this.emissionStartTime = null\n }\n\n public play(): void {\n if (!this.paused) return\n this.paused = false\n this.emissionStartTime = null\n }\n\n public setTime(timeMilliseconds: number): void {\n if (this.disposed) return\n const time = timeMilliseconds / 1000\n this.emissionStartTime ??= time\n const emitterAge = time - this.emissionStartTime\n const particleCount = Math.max(0, Math.ceil(this.particlesPerSecond * this.particleDeathAge))\n this.ensureCapacity(particleCount)\n this.count = particleCount\n this.instances.length = particleCount\n\n for (let index = 0; index < particleCount; index += 1) {\n let instance = this.instances[index]\n if (!this.paused && (!instance || time - instance.birthTime >= this.particleDeathAge)) {\n const delay = particleCount > 0 ? (this.particleDeathAge / particleCount) * index : 0\n if (emitterAge > delay) {\n const birthTime = time - ((emitterAge - delay) % this.particleDeathAge)\n instance = this.createInstance(birthTime)\n this.instances[index] = instance\n }\n }\n this.updateInstance(index, instance, time)\n }\n\n this.updateAttributes()\n this.updateMatrices()\n this.needsRender = true\n }\n\n public dispose(): this {\n if (this.disposed) return this\n this.disposed = true\n this.geometry.dispose()\n this.material.dispose()\n this.fallbackTexture.dispose()\n this.instances = []\n return this\n }\n\n private createInstance(birthTime: number): ParticleInstance {\n let position: THREE.Vector3\n if (this.positionStyle === 'SPHERE') {\n const z = 2 * Math.random() - 1\n const theta = Math.PI * 2 * Math.random()\n const radius = Math.sqrt(1 - z * z)\n position = new THREE.Vector3(radius * Math.cos(theta), radius * Math.sin(theta), z)\n .multiplyScalar(this.positionSphereSpread)\n .add(this.positionBase)\n } else {\n position = randomVector(this.positionBase, this.positionCubeSpread)\n }\n\n let velocity: THREE.Vector3\n if (this.velocityStyle === 'SPHERE') {\n velocity = position\n .clone()\n .sub(this.positionBase)\n .normalize()\n .multiplyScalar(random(this.velocitySphereBase, this.velocitySphereSpread))\n } else {\n velocity = randomVector(this.velocityCubeBase, this.velocityCubeSpread)\n }\n\n return {\n birthTime,\n position,\n velocity,\n acceleration: randomVector(this.accelerationBase, this.accelerationSpread),\n angle: random(this.angleBase, this.angleSpread),\n angleVelocity: random(this.angleVelocityBase, this.angleVelocitySpread),\n angleAcceleration: random(this.angleAccelerationBase, this.angleAccelerationSpread),\n color: randomVector(this.colorBase, this.colorSpread),\n size: random(this.sizeBase, this.sizeSpread),\n opacity: random(this.opacityBase, this.opacitySpread),\n }\n }\n\n private updateInstance(index: number, instance: ParticleInstance | undefined, time: number): void {\n const positionOffset = index * 3\n if (!instance) {\n this.positions.fill(0, positionOffset, positionOffset + 3)\n this.colors.fill(0, positionOffset, positionOffset + 3)\n this.opacities[index] = 0\n this.sizes[index] = 0\n this.angles[index] = 0\n return\n }\n\n const age = Math.min(this.particleDeathAge, Math.max(0, time - instance.birthTime))\n const ageSquared = age * age * 0.5\n this.positions[positionOffset] =\n instance.position.x + instance.velocity.x * age + instance.acceleration.x * ageSquared\n this.positions[positionOffset + 1] =\n instance.position.y + instance.velocity.y * age + instance.acceleration.y * ageSquared\n this.positions[positionOffset + 2] =\n instance.position.z + instance.velocity.z * age + instance.acceleration.z * ageSquared\n this.angles[index] = instance.angle + instance.angleVelocity * age + instance.angleAcceleration * ageSquared\n this.sizes[index] = instance.size + (this.sizeTween ? tweenNumber(this.sizeTween, age) : 0)\n this.opacities[index] = instance.opacity + (this.opacityTween ? tweenNumber(this.opacityTween, age) : 0)\n\n this.hsl.copy(instance.color)\n if (this.colorTween) this.hsl.add(tweenVector(this.colorTween, age, new THREE.Vector3()))\n this.color.setHSL(this.hsl.x, this.hsl.y, this.hsl.z)\n this.colors[positionOffset] = this.color.r\n this.colors[positionOffset + 1] = this.color.g\n this.colors[positionOffset + 2] = this.color.b\n }\n\n private ensureCapacity(required: number): void {\n if (required <= this.capacity) return\n let capacity = this.capacity\n while (capacity < required) capacity *= 2\n this.capacity = capacity\n\n this.positions = new Float32Array(capacity * 3)\n this.colors = new Float32Array(capacity * 3)\n this.opacities = new Float32Array(capacity)\n this.sizes = new Float32Array(capacity)\n this.angles = new Float32Array(capacity)\n this.instanceMatrix = new THREE.InstancedBufferAttribute(new Float32Array(capacity * 16), 16)\n this.geometry.setAttribute('particleColor', new THREE.InstancedBufferAttribute(this.colors, 3))\n this.geometry.setAttribute('particleOpacity', new THREE.InstancedBufferAttribute(this.opacities, 1))\n }\n\n private updateAttributes(): void {\n const colorAttribute = this.geometry.getAttribute('particleColor')\n const opacityAttribute = this.geometry.getAttribute('particleOpacity')\n colorAttribute.needsUpdate = true\n opacityAttribute.needsUpdate = true\n }\n\n private updateMatrices(): void {\n for (let index = 0; index < this.count; index += 1) {\n const offset = index * 3\n const size = Math.max(0, this.sizes[index])\n this.angleQuaternion.setFromAxisAngle(this.zAxis, this.angles[index])\n this.worldQuaternion.copy(this.localCameraQuaternion).multiply(this.angleQuaternion)\n this.scaleVector.set(size, size, size)\n this.instanceTransform.compose(\n new THREE.Vector3(this.positions[offset], this.positions[offset + 1], this.positions[offset + 2]),\n this.worldQuaternion,\n this.scaleVector,\n )\n this.setMatrixAt(index, this.instanceTransform)\n }\n this.instanceMatrix.needsUpdate = true\n }\n}\n","import type { FireSpreadBounds } from '../typing'\n\n/** 蔓延边界的尺寸信息 */\nexport interface SpreadSize {\n volume: number\n /** 水平面对角线长度 */\n diagonal: number\n}\n\n/** 由蔓延边界算尺寸:火与烟共用 */\nexport const measureSpreadBounds = (bounds: FireSpreadBounds): SpreadSize => {\n const [minX, minY, minZ, maxX, maxY, maxZ] = bounds\n const width = Math.abs(maxX - minX)\n const height = Math.abs(maxY - minY)\n const depth = Math.abs(maxZ - minZ)\n\n return {\n volume: width * height * depth,\n diagonal: Math.sqrt(width * width + depth * depth),\n }\n}\n\n/**\n * 蔓延速度 → 步进间隔与增长率。\n * 速度越快,间隔越短、每次增长越多;火与烟用同一套手感。\n */\nexport const speedToGrowth = (spreadSpeed: number) => {\n const speedMultiplier = Math.max(0.1, Math.min(2.0, spreadSpeed))\n\n return {\n interval: Math.max(200, 1000 / speedMultiplier),\n growthRate: Math.max(0.1, Math.min(0.8, speedMultiplier * 0.3)),\n }\n}\n","import type { FireSpreadBounds } from '../typing'\nimport { SPREAD_COVERAGE_TARGET } from '../constants'\nimport { measureSpreadBounds, speedToGrowth } from '../utils/spread'\nimport type { FireGrowthConfig } from './type'\n\n/**\n * 默认火焰增长配置\n */\nexport const DEFAULT_FIRE_GROWTH_CONFIG: FireGrowthConfig = {\n growthInterval: 2000,\n growthRate: 0.3,\n maxAdditionalFires: 3,\n spreadRange: 2,\n}\n\n/**\n * 由起火区域算火焰蔓延参数。\n */\nexport const buildFireGrowthConfig = (\n bounds: FireSpreadBounds,\n fireSize: number,\n spreadSpeed: number,\n): FireGrowthConfig => {\n const { volume, diagonal } = measureSpreadBounds(bounds)\n const { interval, growthRate } = speedToGrowth(spreadSpeed)\n\n const maxFires = Math.max(12, Math.min(100, Math.round(volume * 1.2)))\n const fireSizeFactor = Math.max(0.3, Math.min(2.0, fireSize))\n const fireSizeMultiplier = Math.max(0.8, Math.min(1.5, fireSize))\n\n return {\n growthInterval: interval,\n growthRate,\n maxAdditionalFires: Math.round(maxFires / fireSizeFactor),\n spreadRange: diagonal * 0.7 * fireSizeMultiplier,\n bounds,\n coverageTarget: SPREAD_COVERAGE_TARGET,\n }\n}\n\n","import * as THREE from 'three/webgpu'\nimport type { FireSpreadBounds } from '../typing'\nimport { MAX_SPREAD_CELLS_PER_STEP } from '../constants'\n\nexport interface RadialSpreadOptions {\n /** 区域包围盒(世界坐标):[minX, minY, minZ, maxX, maxY, maxZ] */\n bounds: FireSpreadBounds\n /** 扩散中心(世界坐标) */\n origin: THREE.Vector3\n /** 噪声种子。同一个 seed 得到同一套布局,火焰用火焰 id,烟雾用烟雾源 id */\n seed: string\n /** 扩散半径上限 */\n spreadRange: number\n /** 增长率,影响每一步的半径推进距离 */\n growthRate: number\n /** 网格边长(米),不传按 1 米 */\n cell?: number\n}\n\nexport interface RadialSpreadCell {\n /** 新铺开的位置,已做抖动,不会排成规则阵列 */\n position: THREE.Vector3\n /** 尺寸抖动系数(0.9~1.1),调用方按需用在实体大小上 */\n scaleJitter: number\n}\n\nexport interface RadialSpreadStepResult {\n /** 这一步新铺开的位置 */\n cells: RadialSpreadCell[]\n /** 当前扩散半径 */\n radius: number\n /** 当前覆盖率(0~1) */\n coverage: number\n}\n\n/**\n * 径向扩散:以某个点为中心、按网格扫描包围盒,每一步只取当前半径环带内的格子。\n */\nexport class RadialSpread {\n private readonly bounds: FireSpreadBounds\n private readonly origin: THREE.Vector3\n private readonly seed: string\n private readonly cell: number\n private readonly spreadRange: number\n private readonly growthRate: number\n\n private readonly coveredCells = new Set<string>()\n private readonly totalCells: number\n private readonly nx: number\n private readonly nz: number\n private currentRadius = 0\n private maxRing = 0\n\n constructor(options: RadialSpreadOptions) {\n this.bounds = options.bounds\n this.origin = options.origin\n this.seed = options.seed\n this.spreadRange = options.spreadRange\n this.growthRate = options.growthRate\n this.cell = Math.max(0.08, options.cell ?? 1)\n\n const [minX, , minZ, maxX, , maxZ] = this.bounds\n this.nx = Math.max(1, Math.ceil((maxX - minX) / this.cell))\n this.nz = Math.max(1, Math.ceil((maxZ - minZ) / this.cell))\n this.totalCells = this.nx * this.nz\n }\n\n /** 当前扩散半径 */\n get radius(): number {\n return this.currentRadius\n }\n\n /** 当前覆盖率(0~1) */\n get coverage(): number {\n return Math.min(1, this.coveredCells.size / Math.max(1, this.totalCells))\n }\n\n step(growthLevel: number, maxNew: number): RadialSpreadStepResult {\n const [minX, , minZ, maxX, , maxZ] = this.bounds\n const base = this.origin\n\n // 半径递增(与增长率相关)\n const stepLength = Math.max(this.cell * 0.35, (this.spreadRange / 28) * Math.max(0.2, this.growthRate))\n this.currentRadius = Math.min(this.spreadRange, this.currentRadius + stepLength)\n\n const cx0 = (base.x - minX) / this.cell - 0.5\n const cz0 = (base.z - minZ) / this.cell - 0.5\n const currentRing = Math.max(0, Math.floor(this.currentRadius / this.cell))\n\n const capacity = Math.max(1, Math.min(MAX_SPREAD_CELLS_PER_STEP, maxNew))\n const cells: RadialSpreadCell[] = []\n\n for (let ix = 0; ix < this.nx; ix++) {\n for (let iz = 0; iz < this.nz; iz++) {\n if (cells.length >= capacity) break\n\n const cx = minX + ix * this.cell + this.cell / 2\n const cz = minZ + iz * this.cell + this.cell / 2\n const key = `${ix}_${iz}`\n\n if (this.coveredCells.has(key)) continue\n\n const ring = Math.max(Math.abs(ix - Math.round(cx0)), Math.abs(iz - Math.round(cz0)))\n if (ring > currentRing || ring < this.maxRing) continue\n\n // 基于噪声的密度控制,避免排布过于规则\n const theta = Math.atan2(cz - base.z, cx - base.x)\n const phase = growthLevel * 0.3\n const density = 0.75 + 0.2 * Math.sin(theta * 3 + phase)\n const noise = rand2(ix, iz, this.seed)\n\n // 邻居已铺开时放宽阈值,保证连续\n const neighborsCovered =\n this.isCovered(ix - 1, iz) ||\n this.isCovered(ix + 1, iz) ||\n this.isCovered(ix, iz - 1) ||\n this.isCovered(ix, iz + 1)\n const threshold = neighborsCovered ? density : Math.max(0.55, density - 0.15)\n if (noise > threshold) continue\n\n // 抖动位置,打破网格对齐\n const jitterRange = this.cell * 0.35\n const jx = (rand2(ix + 13, iz + 7, this.seed) - 0.5) * 2 * jitterRange\n const jz = (rand2(ix + 29, iz + 3, this.seed) - 0.5) * 2 * jitterRange\n\n cells.push({\n position: new THREE.Vector3(cx + jx, base.y, cz + jz),\n scaleJitter: 0.9 + 0.2 * rand2(ix + 5, iz + 11, this.seed),\n })\n this.coveredCells.add(key)\n }\n\n if (cells.length >= capacity) break\n }\n\n if (cells.length < capacity * 0.25) {\n this.maxRing = Math.min(currentRing, this.maxRing + 1)\n }\n\n return { cells, radius: this.currentRadius, coverage: this.coverage }\n }\n\n private isCovered(ix: number, iz: number): boolean {\n return this.coveredCells.has(`${ix}_${iz}`)\n }\n}\n\nfunction rand2(ix: number, iz: number, seed: string): number {\n const s = hashString(seed)\n const x = Math.sin(ix * 12.9898 + iz * 78.233 + s * 0.0001) * 43758.5453\n return x - Math.floor(x)\n}\n\nfunction hashString(str: string): number {\n let h = 2166136261 >>> 0\n for (let i = 0; i < str.length; i++) {\n h ^= str.charCodeAt(i)\n h = Math.imul(h, 16777619)\n }\n return h >>> 0\n}\n","import type { Particle } from '../../shared-utils/rendering/Particle'\n\n/**\n * 释放粒子占用的显存。\n */\nexport const disposeParticle = (particle: Particle): void => {\n particle.parent?.remove(particle)\n particle.dispose()\n}\n","import * as THREE from 'three/webgpu'\nimport { Particle } from '../../../shared-utils/rendering/Particle'\nimport type { FireGrowthConfig, FireData } from '../type'\nimport { DEFAULT_FIRE_GROWTH_CONFIG } from '../config'\nimport { RadialSpread } from '../../utils/radialSpread'\nimport { FADE_STEP_MS, MAX_SPREAD_CELLS_PER_STEP, SPREAD_COVERAGE_TARGET } from '../../constants'\nimport type { ParticleTexture } from '../../utils/particleTexture'\nimport { disposeParticle } from '../../utils/particle'\n\n/**\n * 扩展的火焰配置接口,包含火苗大小\n */\ninterface ExtendedFireConfig extends Partial<FireGrowthConfig> {\n fireSize?: number\n}\n\n/**\n * 火焰管理器\n */\nexport class FireManager {\n private fires: Map<string, FireData> = new Map()\n private scene: THREE.Scene\n private particleTexture: ParticleTexture\n private unsubscribeTexture: () => void\n\n constructor(scene: THREE.Scene, particleTexture: ParticleTexture) {\n this.scene = scene\n this.particleTexture = particleTexture\n this.unsubscribeTexture = particleTexture.onChange((texture) => {\n this.fires.forEach((fireData) => {\n fireData.particles.forEach((particle) => {\n particle.texture = texture\n })\n })\n })\n }\n\n /**\n * 添加火焰\n */\n addFire(id: string, positions: THREE.Vector3[], config?: ExtendedFireConfig) {\n const finalConfig = { ...DEFAULT_FIRE_GROWTH_CONFIG, ...config }\n const fireSize = config?.fireSize || 1\n\n const fireData: FireData = {\n id,\n positions,\n config: finalConfig,\n particles: [],\n growthLevel: 1,\n fireSize,\n }\n\n // 创建初始火焰粒子\n positions.forEach((position, index) => {\n const particle = this.createFireParticle(position, `${id}-${index}`, fireSize)\n fireData.particles.push(particle)\n })\n\n this.fires.set(id, fireData)\n }\n\n /**\n * 创建火焰粒子\n */\n private createFireParticle(position: THREE.Vector3, name: string, scale: number): Particle {\n const particle = new Particle({\n positionBase: new THREE.Vector3(0, 0.01, 0),\n positionStyle: 'SPHERE',\n positionSphereSpread: 0.25 * scale,\n velocityStyle: 'CUBE',\n velocityCubeBase: new THREE.Vector3(0, 0.5 * scale, 0), // 降低向上速度\n velocityCubeSpread: new THREE.Vector3(0.2 * scale, 0.3 * scale, 0.2 * scale), // 减少Y轴随机范围\n texture: this.particleTexture.current,\n sizeTween: {\n times: [0, 0.3, 1.2],\n values: [0.2 * scale, 1.5 * scale, 1 * scale],\n },\n opacityTween: {\n times: [0.9, 1.5],\n values: [1, 0],\n },\n colorTween: {\n times: [0.5, 1.0],\n values: [new THREE.Vector3(0.02, 1, 0.2), new THREE.Vector3(0.05, 1, 0)],\n },\n blending: THREE.AdditiveBlending,\n particlesPerSecond: 30 * scale,\n particleDeathAge: 1.0,\n })\n particle.name = name\n particle.position.copy(position)\n this.scene.add(particle)\n return particle\n }\n\n /**\n * 开始增长\n */\n private startGrowth(fireData: FireData) {\n const { config } = fireData\n\n fireData.growthTimer = setInterval(() => {\n fireData.growthLevel += config.growthRate\n\n // 更新现有火焰参数\n this.refreshFireParams(fireData)\n\n // 火势蔓延\n this.radialExpand(fireData)\n\n // 停止条件:火点数达上限、覆盖率达标、或半径铺到顶\n const firesReached = fireData.particles.length >= config.maxAdditionalFires + fireData.positions.length\n const coverageReached = (fireData.spread?.coverage ?? 0) >= (config.coverageTarget ?? SPREAD_COVERAGE_TARGET)\n const radiusReached = (fireData.spread?.radius ?? 0) >= config.spreadRange\n\n if (firesReached || coverageReached || radiusReached) {\n clearInterval(fireData.growthTimer)\n fireData.growthTimer = null\n }\n }, config.growthInterval)\n }\n\n /**\n * 以起火点为中心,按半径批量扩散\n */\n private radialExpand(fireData: FireData) {\n const { config } = fireData\n if (!config.bounds) return\n\n if (!fireData.spread) {\n fireData.spread = new RadialSpread({\n bounds: config.bounds,\n origin: fireData.positions[0],\n seed: fireData.id,\n spreadRange: config.spreadRange,\n growthRate: config.growthRate,\n cell: Math.max(0.08, fireData.fireSize * 0.7),\n })\n }\n\n const maxNew = Math.max(16, Math.min(MAX_SPREAD_CELLS_PER_STEP, config.maxAdditionalFires))\n const { cells } = fireData.spread.step(fireData.growthLevel, maxNew)\n\n for (const { position, scaleJitter } of cells) {\n const newFire = this.createFireParticle(\n position,\n `${fireData.id}-extra-${fireData.particles.length}`,\n Math.min(1.5, fireData.growthLevel * (fireData.fadeIn ?? 1) * 0.5) * scaleJitter,\n )\n fireData.particles.push(newFire)\n\n // 达到上限则退出\n if (fireData.particles.length >= config.maxAdditionalFires + fireData.positions.length) break\n }\n }\n\n /**\n * 更新火焰参数\n */\n private updateFireParams(particle: Particle, level: number, fireSize: number) {\n const scale = Math.min(3, level) * fireSize\n\n // 调整火焰大小\n if (particle.sizeTween) {\n particle.sizeTween.values[1] = 1.5 * scale\n particle.sizeTween.values[2] = 1 * scale\n }\n\n // 调整粒子产生速率\n particle.particlesPerSecond = Math.min(100, 30 * scale)\n\n // 调整速度 (降低火焰高度)\n particle.velocityCubeBase.y = Math.min(1.5, 0.5 * scale) // 降低最大Y轴速度\n particle.velocityCubeSpread.x = Math.min(0.5, 0.2 * scale)\n particle.velocityCubeSpread.y = Math.min(0.3, 0.3 * scale) // 限制Y轴速度随机范围\n particle.velocityCubeSpread.z = Math.min(0.5, 0.2 * scale)\n }\n\n /** 按当前火势与淡入进度刷新该起火点的所有粒子 */\n private refreshFireParams(fireData: FireData) {\n const level = fireData.growthLevel * (fireData.fadeIn ?? 1)\n fireData.particles.forEach((particle) => this.updateFireParams(particle, level, fireData.fireSize))\n }\n\n /**\n * 移除火焰\n */\n removeFire(id: string) {\n const fireData = this.fires.get(id)\n if (!fireData) return\n\n // 停止增长\n if (fireData.growthTimer) {\n clearInterval(fireData.growthTimer)\n }\n\n // 停止灭火\n if (fireData.extinguishTimer) {\n clearInterval(fireData.extinguishTimer)\n }\n\n // 停止点燃淡入\n if (fireData.fadeInTimer) {\n clearInterval(fireData.fadeInTimer)\n }\n\n // 移除粒子\n fireData.particles.forEach((particle) => {\n disposeParticle(particle)\n })\n\n this.fires.delete(id)\n }\n\n /**\n * 销毁管理器\n */\n destroy() {\n const fireIds = Array.from(this.fires.keys())\n fireIds.forEach((id) => this.removeFire(id))\n\n this.unsubscribeTexture()\n }\n\n /**\n * 开始灭火过程\n */\n startExtinguish(id: string, onComplete?: () => void, extinguishTime = 5000): void {\n const fireData = this.fires.get(id)\n if (!fireData) return\n\n if (fireData.extinguishTimer) {\n clearInterval(fireData.extinguishTimer)\n fireData.extinguishTimer = null\n }\n\n // 停止火焰增长\n if (fireData.growthTimer) {\n clearInterval(fireData.growthTimer)\n fireData.growthTimer = null\n }\n\n // 熄灭优先于淡入\n if (fireData.fadeInTimer) {\n clearInterval(fireData.fadeInTimer)\n fireData.fadeInTimer = null\n }\n fireData.fadeIn = undefined\n\n // 设置灭火参数\n const totalTime = Math.max(1000, Math.min(30000, extinguishTime)) // 限制在1-30秒之间\n const totalSteps = totalTime / FADE_STEP_MS // 总步数\n const extinguishRate = fireData.growthLevel / totalSteps // 每步减少的量\n const extinguishStartTime = Date.now() // 记录开始时间\n\n // 开始灭火定时器\n const extinguishTimer = setInterval(() => {\n // 减少增长级别\n fireData.growthLevel = Math.max(0, fireData.growthLevel - extinguishRate)\n\n // 更新现有火焰参数\n this.refreshFireParams(fireData)\n\n // 逐渐减少粒子产生速率\n fireData.particles.forEach((particle) => {\n const currentRate = particle.particlesPerSecond\n particle.particlesPerSecond = Math.max(0, currentRate - extinguishRate * 10)\n })\n\n // 当增长级别很低时,开始移除火焰粒子\n if (fireData.growthLevel < 0.5 && fireData.particles.length > 0) {\n // 每次移除一个火焰粒子\n const particleToRemove = fireData.particles.pop()\n if (particleToRemove) {\n disposeParticle(particleToRemove)\n }\n }\n\n // 检查是否完全灭火 - 只在真正必要时提前结束,否则按设定时间执行\n const timeElapsed = Date.now() - extinguishStartTime\n const shouldComplete =\n (fireData.growthLevel <= 0.01 && fireData.particles.length === 0) || // 只有完全熄灭才提前结束\n timeElapsed >= totalTime // 或者到达设定时间\n\n if (shouldComplete) {\n clearInterval(extinguishTimer)\n\n // 调用完成回调\n if (onComplete) {\n onComplete()\n }\n }\n }, FADE_STEP_MS)\n\n // 保存灭火定时器引用,以便后续清理\n fireData.extinguishTimer = extinguishTimer\n }\n\n /**\n * 点燃淡入\n */\n startFadeIn(id: string, fadeInTime = 0): void {\n const fireData = this.fires.get(id)\n if (!fireData) return\n\n if (fireData.fadeInTimer) {\n clearInterval(fireData.fadeInTimer)\n fireData.fadeInTimer = null\n }\n\n const totalTime = Math.max(0, fadeInTime)\n if (totalTime === 0) return\n\n const totalSteps = Math.max(1, Math.round(totalTime / FADE_STEP_MS))\n let step = 0\n\n fireData.fadeIn = 0\n this.refreshFireParams(fireData)\n\n fireData.fadeInTimer = setInterval(() => {\n step += 1\n\n if (step >= totalSteps) {\n clearInterval(fireData.fadeInTimer)\n fireData.fadeInTimer = null\n fireData.fadeIn = undefined\n this.refreshFireParams(fireData)\n return\n }\n\n fireData.fadeIn = step / totalSteps\n this.refreshFireParams(fireData)\n }, FADE_STEP_MS)\n }\n\n /**\n * 停止灭火过程\n */\n stopExtinguish(id: string): void {\n const fireData = this.fires.get(id)\n if (!fireData || !fireData.extinguishTimer) return\n\n // 停止灭火定时器\n clearInterval(fireData.extinguishTimer)\n fireData.extinguishTimer = null\n }\n\n /**\n * 合并配置并重启增长定时器\n */\n updateFireConfig(id: string, newConfig: ExtendedFireConfig) {\n const fireData = this.fires.get(id)\n if (!fireData) return\n\n // 更新配置\n fireData.config = { ...fireData.config, ...newConfig }\n\n // 重新开始增长:重复调用时先收掉上一次的定时器\n if (fireData.growthTimer) {\n clearInterval(fireData.growthTimer)\n fireData.growthTimer = null\n }\n this.startGrowth(fireData)\n }\n\n /**\n * 移动单个火焰的基础位置\n */\n moveFire(id: string, newBasePosition: THREE.Vector3) {\n const fireData = this.fires.get(id)\n if (!fireData) return\n\n const oldBase = fireData.positions[0]\n if (!oldBase) return\n\n const delta = new THREE.Vector3().subVectors(newBasePosition, oldBase)\n\n // 更新基础位置\n fireData.positions[0].copy(newBasePosition)\n\n // 平移所有粒子\n fireData.particles.forEach((particle) => {\n particle.position.add(delta)\n })\n }\n\n /**\n * 设置指定火焰的透明度\n * @param id 火焰ID\n * @param opacity 透明度 (0-1)\n */\n setFireOpacity(id: string, opacity: number): void {\n const fireData = this.fires.get(id)\n if (!fireData) return\n\n // 遍历该火焰的所有粒子,通过修改 opacityTween 来控制透明度\n fireData.particles.forEach((particle) => {\n if (particle.opacityTween) {\n // 修改 opacityTween 的 values,将最大透明度设为目标值\n // 原始值通常是 [1, 0],修改后变为 [opacity, 0]\n particle.opacityTween.values = [opacity, 0]\n }\n })\n }\n}\n","import * as THREE from 'three/webgpu'\nimport { Particle } from '../../../shared-utils/rendering/Particle'\nimport type { SmokeConfig } from './SmokeManager'\nimport type { ParticleTexture } from '../../utils/particleTexture'\nimport { disposeParticle } from '../../utils/particle'\nimport { FADE_STEP_MS } from '../../constants'\n\n/**\n * 烟雾源信息\n */\ninterface SmokeSource {\n id: string\n particle: Particle\n /** 渐显定时器 */\n fadeInTimer?: ReturnType<typeof setInterval>\n}\n\n/**\n * 普通烟雾管理器\n * 管理传统的向上飘散烟雾效果\n */\nexport class NormalSmokeManager {\n private scene: THREE.Scene\n private config: SmokeConfig\n private sources: Map<string, SmokeSource> = new Map()\n private particleTexture: ParticleTexture\n private unsubscribeTexture: () => void\n\n constructor(scene: THREE.Scene, config: SmokeConfig, particleTexture: ParticleTexture) {\n this.scene = scene\n this.config = config\n this.particleTexture = particleTexture\n this.unsubscribeTexture = particleTexture.onChange((texture) => {\n this.sources.forEach((source) => {\n source.particle.texture = texture\n })\n })\n }\n\n /**\n * 添加烟雾源\n */\n addSource(id: string, position: THREE.Vector3, intensity: number, fadeInMs = 0) {\n const particle = this.createNormalSmoke(position, id, intensity)\n const source: SmokeSource = { id, particle }\n this.sources.set(id, source)\n\n if (fadeInMs > 0) this.fadeInSource(source, intensity, fadeInMs)\n }\n\n /** 渐显:在 durationMs 内把浓度从 0 涨到目标值 */\n private fadeInSource(source: SmokeSource, targetIntensity: number, durationMs: number) {\n const steps = Math.max(1, Math.round(durationMs / FADE_STEP_MS))\n let step = 0\n\n this.updateSourceIntensity(source.id, 0)\n source.fadeInTimer = setInterval(() => {\n step += 1\n\n if (step >= steps) {\n clearInterval(source.fadeInTimer)\n source.fadeInTimer = undefined\n this.updateSourceIntensity(source.id, targetIntensity)\n return\n }\n\n this.updateSourceIntensity(source.id, targetIntensity * (step / steps))\n }, FADE_STEP_MS)\n }\n\n /**\n * 平移某个烟雾源的粒子\n */\n moveSource(id: string, delta: THREE.Vector3) {\n this.sources.get(id)?.particle.position.add(delta)\n }\n\n /**\n * 更新烟雾源强度\n */\n updateSourceIntensity(id: string, intensity: number) {\n const source = this.sources.get(id)\n if (!source) return\n\n this.updateNormalSmokeParams(source.particle, intensity)\n }\n\n /**\n * 移除烟雾源\n */\n removeSource(id: string) {\n const source = this.sources.get(id)\n if (!source) return\n\n // 清理渐显定时器和粒子\n if (source.fadeInTimer) clearInterval(source.fadeInTimer)\n disposeParticle(source.particle)\n this.sources.delete(id)\n }\n\n /**\n * 创建普通烟雾粒子\n */\n private createNormalSmoke(position: THREE.Vector3, id: string, intensity: number): Particle {\n const scale = intensity * this.config.densityMultiplier\n const smokePosition = position.clone()\n // 确保烟雾在火焰上方,增加基础偏移让烟雾在更高位置产生\n smokePosition.y += 0.3 + this.config.heightOffset * intensity\n\n const particle = new Particle({\n positionBase: new THREE.Vector3(0, 0.05, 0), // 减少基础高度偏移,让烟雾更贴近火焰\n positionCubeSpread: new THREE.Vector3(\n 0.5 * scale * this.config.spreadMultiplier,\n 0.05 * scale,\n 0.5 * scale * this.config.spreadMultiplier,\n ),\n\n velocityStyle: 'CUBE',\n velocityCubeBase: new THREE.Vector3(0, 0.4 * scale * Math.max(Math.random(), 0.6), 0.05),\n velocityCubeSpread: new THREE.Vector3(\n 0.8 * scale * this.config.spreadMultiplier,\n 0.2 * scale * this.config.spreadMultiplier * Math.max(Math.random(), 0.4),\n 0.8 * scale * this.config.spreadMultiplier,\n ),\n accelerationBase: new THREE.Vector3(0, 0.1, 0.02), // 恢复向上加速度,让烟雾向上升腾\n\n texture: this.particleTexture.current,\n blending: THREE.NormalBlending, // 使用正常混合模式,避免颜色异常\n\n angleBase: 0,\n angleSpread: (720 / 180) * Math.PI,\n angleVelocityBase: 0,\n angleVelocitySpread: (360 / 180) * Math.PI,\n\n sizeTween: {\n times: [0, 1, 2, 3, 4, 6],\n // 尺寸随浓度等比缩放\n values: [0.4, 1.0, 1.6, 2.0, 1.6, 0.8].map((value) => value * intensity),\n },\n opacityTween: {\n times: [0, 1, 2, 3, 4, 6],\n // 峰值透明度 0.45\n values: [0.15, 0.3, 0.45, 0.3, 0.15, 0],\n },\n colorTween: {\n // 黑色浓烟\n times: [0.3, 1.5],\n values: [new THREE.Vector3(0.2, 0.2, 0.2), new THREE.Vector3(0.05, 0.05, 0.05)],\n },\n // 速率与浓度等比,基准 30/秒(创建与更新同一基准)\n particlesPerSecond: 30 * intensity,\n particleDeathAge: 6,\n })\n\n particle.name = id\n particle.position.copy(smokePosition)\n this.scene.add(particle)\n return particle\n }\n\n /**\n * 更新普通烟雾参数\n */\n private updateNormalSmokeParams(particle: Particle, intensity: number) {\n const scale = intensity * this.config.densityMultiplier\n\n // 按浓度等比缩放密度\n particle.particlesPerSecond = Math.floor(30 * intensity)\n\n // 动态调整烟雾上升速度\n particle.velocityCubeBase.y = Math.min(2.0, 0.6 * scale)\n\n // 动态调整烟雾扩散范围\n const spreadFactor = Math.min(3, scale * this.config.spreadMultiplier)\n particle.velocityCubeSpread.x = 0.8 * spreadFactor\n particle.velocityCubeSpread.z = 0.8 * spreadFactor\n\n // 动态调整烟雾初始扩散位置\n particle.positionCubeSpread.x = 0.3 * spreadFactor\n particle.positionCubeSpread.z = 0.3 * spreadFactor\n }\n\n /**\n * 清理所有烟雾\n */\n clearAll() {\n const sourceIds = Array.from(this.sources.keys())\n sourceIds.forEach((id) => this.removeSource(id))\n }\n\n /**\n * 销毁管理器\n */\n destroy() {\n this.clearAll()\n this.unsubscribeTexture()\n }\n}\n","import * as THREE from 'three/webgpu'\nimport type { FireSpreadBounds } from '../../typing'\nimport { RadialSpread } from '../../utils/radialSpread'\nimport type { ParticleTexture } from '../../utils/particleTexture'\nimport { SPREAD_COVERAGE_TARGET } from '../../constants'\nimport { NormalSmokeManager } from './NormalSmokeManager'\n\n/**\n * 烟雾配置接口\n */\nexport interface SmokeConfig {\n /** 密度倍数 */\n densityMultiplier: number\n /** 高度偏移 */\n heightOffset: number\n /** 扩散倍数 */\n spreadMultiplier: number\n}\n\n/**\n * 烟雾源信息\n */\ninterface SmokeSource {\n id: string\n position: THREE.Vector3\n intensity: number\n}\n\n/**\n * 烟雾扩散参数\n */\nexport interface SmokeSpreadOptions {\n /** 扩散边界(世界坐标):`[minX, minY, minZ, maxX, maxY, maxZ]` */\n bounds: FireSpreadBounds\n /** 扩散半径上限 */\n spreadRange: number\n /** 每次步进的强度增长,决定半径推进的快慢 */\n growthRate: number\n /** 步进间隔(毫秒) */\n interval: number\n /** 扩散源数量上限(不含主源) */\n maxAdditional: number\n /** 扩散源的浓度 */\n intensity: number\n /** 扩散源的渐显时长(毫秒) */\n fadeInMs?: number\n /** 网格边长(米),不传按 1 米 */\n cell?: number\n}\n\n/** 扩散过程中的运行时状态 */\ninterface SmokeSpreadState {\n spread: RadialSpread\n timer: ReturnType<typeof setInterval>\n /** 已生成的扩散源 id,按生成顺序 */\n derivedIds: string[]\n options: SmokeSpreadOptions\n growthLevel: number\n}\n\n/**\n * 烟雾管理器\n *\n * 维护「有哪些烟源」的记录,具体粒子交给 {@link NormalSmokeManager}。\n */\nexport class SmokeManager {\n private sources: Map<string, SmokeSource> = new Map()\n /** 正在扩散的烟雾源,key = 主源 id */\n private spreads: Map<string, SmokeSpreadState> = new Map()\n private normalSmoke: NormalSmokeManager\n\n constructor(scene: THREE.Scene, config: SmokeConfig, particleTexture: ParticleTexture) {\n this.normalSmoke = new NormalSmokeManager(scene, config, particleTexture)\n }\n\n /**\n * 添加烟雾源\n */\n addSource(id: string, position: THREE.Vector3, intensity: number = 1, fadeInMs = 0) {\n const source: SmokeSource = { id, position, intensity }\n this.sources.set(id, source)\n this.normalSmoke.addSource(id, position, intensity, fadeInMs)\n }\n\n /**\n * 让某个烟雾源在给定区域内扩散。\n */\n spreadSmoke(id: string, options: SmokeSpreadOptions) {\n const previous = this.spreads.get(id)\n this.stopSmokeSpread(id)\n\n const source = this.sources.get(id)\n if (!source) return\n\n const spread = new RadialSpread({\n bounds: options.bounds,\n origin: source.position,\n seed: id,\n spreadRange: options.spreadRange,\n growthRate: options.growthRate,\n cell: options.cell,\n })\n\n this.spreads.set(id, {\n spread,\n timer: setInterval(() => this.stepSpread(id), options.interval),\n // 重复扩散时接着上次的编号,避免和已存在的扩散源撞 id\n derivedIds: previous?.derivedIds ?? [],\n options,\n growthLevel: 1,\n })\n }\n\n /** 停止扩散(已经生成的扩散源保留) */\n stopSmokeSpread(id: string) {\n const state = this.spreads.get(id)\n if (!state) return\n\n clearInterval(state.timer)\n }\n\n /** 扩散产生的烟雾源 id */\n getSpreadSourceIds(id: string): string[] {\n return this.spreads.get(id)?.derivedIds ?? []\n }\n\n /** 走一步扩散:在区域内新铺开若干个烟雾源 */\n private stepSpread(id: string) {\n const state = this.spreads.get(id)\n if (!state) return\n\n const { options } = state\n state.growthLevel += options.growthRate\n\n const { cells, coverage } = state.spread.step(state.growthLevel, options.maxAdditional)\n\n for (const { position, scaleJitter } of cells) {\n if (state.derivedIds.length >= options.maxAdditional) break\n\n const derivedId = `${id}-spread-${state.derivedIds.length}`\n this.addSource(derivedId, position, options.intensity * scaleJitter, options.fadeInMs ?? 0)\n state.derivedIds.push(derivedId)\n }\n\n if (state.derivedIds.length >= options.maxAdditional || coverage >= SPREAD_COVERAGE_TARGET) {\n this.stopSmokeSpread(id)\n }\n }\n\n /**\n * 平移某个烟雾源。\n */\n moveSource(id: string, position: THREE.Vector3) {\n const source = this.sources.get(id)\n if (!source) return\n\n const delta = new THREE.Vector3().subVectors(position, source.position)\n source.position.copy(position)\n this.normalSmoke.moveSource(id, delta)\n\n this.spreads.get(id)?.derivedIds.forEach((derivedId) => {\n const derived = this.sources.get(derivedId)\n if (!derived) return\n derived.position.add(delta)\n this.normalSmoke.moveSource(derivedId, delta)\n })\n }\n\n /**\n * 更新烟雾源强度\n */\n updateSourceIntensity(id: string, intensity: number) {\n const source = this.sources.get(id)\n if (!source) return\n\n source.intensity = intensity\n this.normalSmoke.updateSourceIntensity(id, intensity)\n }\n\n /**\n * 移除烟雾源\n */\n removeSource(id: string) {\n const source = this.sources.get(id)\n if (!source) return\n\n // 移除的是主源时,连带清掉它扩散出来的源和定时器\n const spreadState = this.spreads.get(id)\n if (spreadState) {\n this.stopSmokeSpread(id)\n this.spreads.delete(id)\n spreadState.derivedIds.forEach((derivedId) => this.removeSource(derivedId))\n }\n\n this.normalSmoke.removeSource(id)\n this.sources.delete(id)\n }\n\n /**\n * 清理所有烟雾\n */\n clearAll() {\n // 扩散定时器先停掉,否则清空之后还会继续往场景里加源\n this.spreads.forEach((state) => clearInterval(state.timer))\n this.spreads.clear()\n\n this.normalSmoke.clearAll()\n this.sources.clear()\n }\n\n /**\n * 销毁管理器\n */\n destroy() {\n this.clearAll()\n this.normalSmoke.destroy()\n }\n\n /**\n * 获取某个烟雾源的当前浓度\n */\n getSourceIntensity(id: string): number {\n return this.sources.get(id)?.intensity ?? 0\n }\n\n /**\n * 获取烟雾源数量\n */\n getSourceCount(): number {\n return this.sources.size\n }\n}\n","import type { FireSpreadBounds } from '../typing'\nimport type { SmokeSpreadOptions } from './managers/SmokeManager'\nimport { measureSpreadBounds, speedToGrowth } from '../utils/spread'\n\n/** 扩散出来的烟雾源的渐显时长(毫秒) */\nexport const SMOKE_SPREAD_FADE_IN_MS = 1000\n\n/**\n * 由起火区域算烟雾蔓延参数。\n */\nexport const buildSmokeSpreadConfig = (\n bounds: FireSpreadBounds,\n intensity: number,\n spreadSpeed: number,\n): SmokeSpreadOptions => {\n const { volume, diagonal } = measureSpreadBounds(bounds)\n const { interval, growthRate } = speedToGrowth(spreadSpeed)\n\n const maxSources = Math.max(4, Math.min(24, Math.round(volume * 0.35)))\n const intensityFactor = Math.max(0.5, Math.min(2.0, intensity))\n\n return {\n bounds,\n interval,\n growthRate,\n spreadRange: diagonal * 0.7,\n maxAdditional: Math.round(maxSources / intensityFactor),\n intensity,\n fadeInMs: SMOKE_SPREAD_FADE_IN_MS,\n cell: Math.max(0.5, diagonal / 8),\n }\n}\n","import type * as THREE from 'three/webgpu'\nimport { loadTexture } from './loadTexture'\n\n/** 贴图加载器,用于满足资源共用 */\nexport function getTextureLoader() {\n const cache = new Map<string, Promise<THREE.Texture>>()\n\n const load = function (url: string): Promise<THREE.Texture> {\n if (cache.has(url)) return cache.get(url)!\n const texturePromise = loadTexture(url)\n cache.set(url, texturePromise)\n return texturePromise\n }\n\n const dispose = function () {\n cache.forEach((texturePromise) => texturePromise.then((texture) => texture.dispose()))\n cache.clear()\n }\n\n return { load, dispose }\n}\n","import type * as THREE from 'three/webgpu'\nimport { getTextureLoader } from '../../shared-utils/three/getTextureLoader'\n\ntype TextureListener = (texture: THREE.Texture | null) => void\n\n/**\n * 火焰、烟雾、喷水共用的粒子贴图。\n */\nexport class ParticleTexture {\n private loader = getTextureLoader()\n private url = ''\n private texture: THREE.Texture | null = null\n private listeners = new Set<TextureListener>()\n\n /** 当前贴图。加载完成前为 null */\n public get current(): THREE.Texture | null {\n return this.texture\n }\n\n public setUrl(url: string): void {\n if (url === this.url) return\n\n this.url = url\n this.texture = null\n this.emit()\n\n if (!url) return\n void this.loader.load(url).then((texture) => {\n // 加载期间 URL 又变了,这次结果作废\n if (url !== this.url) return\n this.texture = texture\n this.emit()\n })\n }\n\n /**\n * 订阅贴图变化(含清空),返回取消订阅的函数。\n */\n public onChange(listener: TextureListener): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n public dispose(): void {\n this.listeners.clear()\n this.texture = null\n this.url = ''\n this.loader.dispose()\n }\n\n private emit(): void {\n this.listeners.forEach((listener) => listener(this.texture))\n }\n}\n","import type { Five } from '@realsee/five-webgpu'\nimport * as THREE from 'three/webgpu'\nimport { FireManager } from './fire'\nimport { buildFireGrowthConfig } from './fire/config'\nimport type { SmokeConfig } from './smoke'\nimport { SmokeManager } from './smoke'\nimport { buildSmokeSpreadConfig } from './smoke/config'\nimport type { FireSpreadBounds } from './typing'\nimport { FADE_STEP_MS, MODEL_SCALE_RANGE } from './constants'\nimport { Particle } from '../shared-utils/rendering/Particle'\nimport { disposeParticle } from './utils/particle'\nimport { ParticleTexture } from './utils/particleTexture'\nimport loadGLTF from '../shared-utils/three/GLTFLoader'\nimport { transformPosition } from '../shared-utils/five/transformPosition'\nimport { lookObject } from '../shared-utils/five/lookObject'\nimport { WorkUtil } from '../shared-utils/Utils/WorkUtil'\n\n/**\n * 烟雾的渲染参数。\n */\nconst SMOKE_RENDER_CONFIG: SmokeConfig = {\n densityMultiplier: 0.2,\n heightOffset: 0.2,\n spreadMultiplier: 4.5,\n}\n\n/** 把模型尺寸限制在允许范围 */\nconst clampModelScale = (value: number) => THREE.MathUtils.clamp(value, MODEL_SCALE_RANGE.min, MODEL_SCALE_RANGE.max)\n\ninterface FireEntry {\n /** 世界坐标 */\n position: THREE.Vector3\n /** 火苗大小 */\n size: number\n /** 所属楼层,用于按楼层控制可见性 */\n floorIndex?: number\n /** 蔓延边界。已点燃(开始蔓延)时才有值 */\n spreadBounds?: FireSpreadBounds\n /** 蔓延速度 */\n spreadSpeed?: number\n}\n\ninterface SmokeEntry {\n /** 世界坐标 */\n position: THREE.Vector3\n /** 渐隐定时器 */\n dissipateTimer?: ReturnType<typeof setInterval>\n}\n\ninterface FirefighterEntry {\n scene: THREE.Object3D\n particle?: Particle | null\n dispose: () => void\n}\n\n/**\n * 消防演绎的三维实体控制器\n * 管理三类实体:火、烟、消防员\n */\nexport class FireControl {\n readonly five: Five\n\n private fireManager: FireManager | null = null\n private smokeManager: SmokeManager | null = null\n\n /** 已添加的起火点 */\n private fires: Map<string, FireEntry> = new Map()\n /** 已添加的烟雾*/\n private smokes: Map<string, SmokeEntry> = new Map()\n /** 已添加的消防员 */\n private firefighters: Map<string, FirefighterEntry> = new Map()\n /** 消防员加载代次,用于丢弃加载期间已经失效的结果 */\n private firefighterTokens: Map<string, number> = new Map()\n\n /** 粒子贴图 */\n private particleTexture = new ParticleTexture()\n private unsubscribeTexture: () => void\n\n private resourceConfig = {\n waterGunModelUrl: '',\n /** 粒子贴图。火焰、烟雾、喷水三种粒子共用同一张 */\n particleTextureUrl: '',\n }\n private resourceConfigResolvers: { check: () => boolean; resolve: () => void }[] = []\n\n private disposed = false\n private workUtil: WorkUtil\n\n constructor(five: Five) {\n this.five = five\n five.on('dispose', this.dispose)\n this.workUtil = new WorkUtil(five)\n this.unsubscribeTexture = this.particleTexture.onChange((texture) => {\n this.firefighters.forEach((entry) => {\n if (entry.particle) entry.particle.texture = texture\n })\n })\n }\n\n public set workCode(workCode: string) {\n this.workUtil.workCode = workCode\n }\n\n public get workCode() {\n return this.workUtil.workCode\n }\n\n /** 粒子贴图是否已配置 */\n public get hasParticleTexture(): boolean {\n return Boolean(this.resourceConfig.particleTextureUrl)\n }\n\n /** 消防员模型 URL 是否已配置 */\n public get hasWaterGunModel(): boolean {\n return Boolean(this.resourceConfig.waterGunModelUrl)\n }\n\n /** 更新资源配置 */\n public updateResourceConfig(config: { waterGunObj?: string; particleTexture?: string }): void {\n const nextWaterGun = config.waterGunObj?.trim()\n const nextParticle = config.particleTexture?.trim()\n\n if (nextWaterGun) {\n this.resourceConfig.waterGunModelUrl = nextWaterGun\n }\n\n if (nextParticle && nextParticle !== this.resourceConfig.particleTextureUrl) {\n this.resourceConfig.particleTextureUrl = nextParticle\n this.particleTexture.setUrl(nextParticle)\n }\n\n this.resourceConfigResolvers = this.resourceConfigResolvers.filter((resolver) => {\n if (!resolver.check()) return true\n resolver.resolve()\n return false\n })\n }\n\n /**\n * 等待某项资源配置就位\n */\n public waitForResourceConfig(kind: 'particle' | 'firefighter'): Promise<void> {\n const check = kind === 'particle' ? () => this.hasParticleTexture : () => this.hasWaterGunModel\n if (check()) return Promise.resolve()\n return new Promise((resolve) => this.resourceConfigResolvers.push({ check, resolve }))\n }\n\n /**\n * 添加一个起火点\n */\n public addFire(\n id: string,\n position: [number, number, number],\n options?: { size?: number; floorIndex?: number; fadeInMs?: number },\n ): void {\n const size = clampModelScale(options?.size ?? 1)\n const worldPosition = this.toWorld(new THREE.Vector3(position[0], position[1], position[2]))\n\n if (this.fires.has(id)) this.removeFire(id)\n\n this.ensureFireManager().addFire(id, [worldPosition], { fireSize: size })\n if (options?.fadeInMs) this.fireManager?.startFadeIn(id, options.fadeInMs)\n this.fires.set(id, { position: worldPosition, size, floorIndex: options?.floorIndex })\n this.five.needsRender = true\n }\n\n /**\n * 让指定起火点开始在给定区域内蔓延。\n */\n public igniteFire(id: string, bounds: FireSpreadBounds, options?: { spreadSpeed?: number }): void {\n const entry = this.fires.get(id)\n if (!entry || !this.fireManager) return\n\n const spreadSpeed = options?.spreadSpeed ?? 1.0\n const worldBounds = this.toWorldBounds(bounds)\n entry.spreadBounds = bounds\n entry.spreadSpeed = spreadSpeed\n\n this.fireManager.updateFireConfig(id, {\n ...buildFireGrowthConfig(worldBounds, entry.size, spreadSpeed),\n fireSize: entry.size,\n })\n this.five.needsRender = true\n }\n\n /** 熄灭:渐进减少火点直到完全消失 */\n public extinguishFire(id: string, options?: { duration?: number; onComplete?: () => void }): void {\n if (!this.fires.has(id) || !this.fireManager) return\n\n this.fireManager.startExtinguish(id, options?.onComplete, options?.duration ?? 5000)\n }\n\n /** 停止熄灭过程 */\n public stopExtinguishFire(id: string): void {\n if (!this.fires.has(id) || !this.fireManager) return\n\n this.fireManager.stopExtinguish(id)\n }\n\n /**\n * 移动起火点\n */\n public moveFire(id: string, position: [number, number, number]): void {\n const entry = this.fires.get(id)\n if (!entry || !this.fireManager) return\n\n const worldPosition = this.toWorld(new THREE.Vector3(position[0], position[1], position[2]))\n entry.position = worldPosition\n this.fireManager.moveFire(id, worldPosition)\n this.five.needsRender = true\n }\n\n /**\n * 缩放起火点\n */\n public scaleFire(id: string, size: number): void {\n const entry = this.fires.get(id)\n if (!entry) return\n\n const { position, floorIndex, spreadBounds, spreadSpeed } = entry\n const nextSize = clampModelScale(size)\n\n this.fireManager?.removeFire(id)\n this.ensureFireManager().addFire(id, [position], { fireSize: nextSize })\n this.fires.set(id, { position, size: nextSize, floorIndex, spreadBounds, spreadSpeed })\n\n if (spreadBounds) this.igniteFire(id, spreadBounds, { spreadSpeed })\n this.five.needsRender = true\n }\n\n /** 移除起火点 */\n public removeFire(id: string): void {\n if (!this.fires.has(id)) return\n\n this.fireManager?.removeFire(id)\n this.fires.delete(id)\n this.five.needsRender = true\n }\n\n /**\n * 按楼层控制起火点的可见性\n */\n public changeFireVisibleByFloorIndex(floorIndex: number | null): void {\n if (!this.fireManager) return\n\n this.fires.forEach((entry, id) => {\n const visible = floorIndex === null || entry.floorIndex === undefined || entry.floorIndex === floorIndex\n this.fireManager!.setFireOpacity(id, visible ? 1.0 : 0.1)\n })\n this.five.needsRender = true\n }\n\n\n /**\n * 添加烟雾。\n */\n public addSmoke(\n id: string,\n position: [number, number, number],\n options?: { intensity?: number; fadeInMs?: number },\n ): void {\n const smokeManager = this.ensureSmokeManager()\n\n const intensity = clampModelScale(options?.intensity ?? 1)\n const worldPosition = this.toWorld(new THREE.Vector3(position[0], position[1], position[2]))\n\n if (this.smokes.has(id)) this.removeSmoke(id)\n\n smokeManager.addSource(id, worldPosition, intensity, options?.fadeInMs ?? 0)\n this.smokes.set(id, { position: worldPosition })\n this.five.needsRender = true\n }\n\n /**\n * 让烟雾在所属区域内扩散\n */\n public spreadSmoke(id: string, bounds: FireSpreadBounds, options?: { spreadSpeed?: number }): void {\n const entry = this.smokes.get(id)\n const smokeManager = this.smokeManager\n if (!entry || !smokeManager) return\n\n const worldBounds = this.toWorldBounds(bounds)\n const intensity = smokeManager.getSourceIntensity(id)\n smokeManager.spreadSmoke(id, buildSmokeSpreadConfig(worldBounds, intensity, options?.spreadSpeed ?? 1.0))\n }\n\n /**\n * 移动烟雾。\n */\n public moveSmoke(id: string, position: [number, number, number]): void {\n const entry = this.smokes.get(id)\n const smokeManager = this.smokeManager\n if (!entry || !smokeManager) return\n\n const worldPosition = this.toWorld(new THREE.Vector3(position[0], position[1], position[2]))\n entry.position = worldPosition\n smokeManager.moveSource(id, worldPosition)\n this.five.needsRender = true\n }\n\n /**\n * 缩放烟雾\n */\n public scaleSmoke(id: string, size: number): void {\n const entry = this.smokes.get(id)\n const smokeManager = this.smokeManager\n if (!entry || !smokeManager) return\n\n smokeManager.updateSourceIntensity(id, clampModelScale(size))\n this.five.needsRender = true\n }\n\n /**\n * 烟雾渐隐并移除。\n */\n public dissipateSmoke(id: string, options?: { duration?: number; onComplete?: () => void }): void {\n const entry = this.smokes.get(id)\n const smokeManager = this.smokeManager\n if (!entry || !smokeManager) return\n\n if (entry.dissipateTimer) clearInterval(entry.dissipateTimer)\n\n // 停止扩散:已经进入消失阶段,再往外铺新源会让烟雾越灭越多\n smokeManager.stopSmokeSpread(id)\n\n const sourceIds = [id, ...smokeManager.getSpreadSourceIds(id)]\n const startIntensities = new Map(sourceIds.map((sourceId) => [sourceId, smokeManager.getSourceIntensity(sourceId)]))\n const steps = Math.max(1, Math.round((options?.duration ?? 3000) / FADE_STEP_MS))\n let step = 0\n\n entry.dissipateTimer = setInterval(() => {\n step += 1\n if (step >= steps) {\n this.removeSmoke(id)\n options?.onComplete?.()\n return\n }\n startIntensities.forEach((startIntensity, sourceId) => {\n smokeManager.updateSourceIntensity(sourceId, startIntensity * (1 - step / steps))\n })\n this.five.needsRender = true\n }, FADE_STEP_MS)\n }\n\n /**\n * 停止消散\n */\n public stopDissipateSmoke(id: string): void {\n const entry = this.smokes.get(id)\n if (!entry) return\n\n if (entry.dissipateTimer) {\n clearInterval(entry.dissipateTimer)\n entry.dissipateTimer = undefined\n this.five.needsRender = true\n }\n }\n\n /** 移除烟雾 */\n public removeSmoke(id: string): void {\n const entry = this.smokes.get(id)\n if (!entry) return\n\n if (entry.dissipateTimer) clearInterval(entry.dissipateTimer)\n this.smokeManager?.removeSource(id)\n this.smokes.delete(id)\n this.five.needsRender = true\n }\n\n\n /**\n * 添加消防员。\n */\n public async addFirefighter(options: {\n id: string\n position: [number, number, number]\n rotation: THREE.Euler\n /** 是否喷水 */\n spray?: boolean\n /** 等比缩放 */\n scale?: number\n }): Promise<void> {\n const { id, position, rotation, spray = false, scale = 1 } = options\n if (!this.resourceConfig.waterGunModelUrl) {\n throw new Error('消防员模型未配置,请先调用 updateResourceConfig 设置 waterGunObj')\n }\n\n if (this.firefighters.has(id)) this.removeFirefighter(id)\n this.invalidateFirefighter(id)\n const token = this.firefighterTokens.get(id)\n\n const worldPosition = this.toWorld(new THREE.Vector3(position[0], position[1], position[2]))\n const result = await loadGLTF(this.resourceConfig.waterGunModelUrl)\n if (this.firefighterTokens.get(id) !== token) {\n result.dispose()\n return\n }\n\n const scene = result.scene\n scene.scale.setScalar(clampModelScale(scale))\n scene.rotation.copy(rotation)\n scene.position.copy(worldPosition)\n scene.name = id\n this.five.scene.add(scene)\n\n let particle: Particle | null = null\n if (spray) {\n particle = this.createSprayParticle(id)\n scene.add(particle)\n }\n\n this.firefighters.set(id, { scene, particle, dispose: result.dispose })\n this.five.needsRender = true\n }\n\n private invalidateFirefighter(id: string): void {\n this.firefighterTokens.set(id, (this.firefighterTokens.get(id) ?? 0) + 1)\n }\n\n /**\n * 把相机移到某个实体上(以最佳视角观察它)。\n */\n public async focusEntity(id: string, options?: { scale?: number }): Promise<void> {\n const firefighter = this.firefighters.get(id)\n if (firefighter) {\n await lookObject(this.five, firefighter.scene, options)\n return\n }\n\n const fire = this.fires.get(id)\n const smoke = this.smokes.get(id)\n const position = fire?.position ?? smoke?.position\n if (!position) return\n\n const entitySize = fire?.size ?? (smoke ? this.smokeManager?.getSourceIntensity(id) ?? 1 : 1)\n const boxSize = Math.max(entitySize, 3)\n const placeholder = new THREE.Mesh(new THREE.BoxGeometry(boxSize, boxSize, boxSize))\n placeholder.visible = false\n placeholder.position.copy(position)\n this.five.scene.add(placeholder)\n try {\n await lookObject(this.five, placeholder, options)\n } finally {\n this.five.scene.remove(placeholder)\n placeholder.geometry.dispose()\n }\n }\n\n /** 移除消防员 */\n public removeFirefighter(id?: string): void {\n if (id === undefined) {\n Array.from(this.firefighterTokens.keys()).forEach((key) => this.invalidateFirefighter(key))\n Array.from(this.firefighters.keys()).forEach((key) => this.removeFirefighter(key))\n return\n }\n\n this.invalidateFirefighter(id)\n const entry = this.firefighters.get(id)\n if (!entry) return\n\n // 喷水粒子由引擎创建,先单独释放\n if (entry.particle) disposeParticle(entry.particle)\n this.five.scene.remove(entry.scene)\n entry.dispose()\n this.firefighters.delete(id)\n this.five.needsRender = true\n }\n\n /** 清空所有实体,保留管理器与资源配置 */\n public clearAll(): void {\n this.fires.forEach((_, id) => this.fireManager?.removeFire(id))\n this.fires.clear()\n\n this.smokes.forEach((entry) => entry.dissipateTimer && clearInterval(entry.dissipateTimer))\n this.smokes.clear()\n this.smokeManager?.clearAll()\n\n this.removeFirefighter()\n this.five.needsRender = true\n }\n\n /** 销毁控制器 */\n public dispose = (): void => {\n if (this.disposed) return\n this.disposed = true\n this.five.off('dispose', this.dispose)\n this.clearAll()\n\n this.fireManager?.destroy()\n this.fireManager = null\n\n this.smokeManager?.destroy()\n this.smokeManager = null\n\n this.unsubscribeTexture()\n this.particleTexture.dispose()\n this.firefighterTokens.clear()\n\n const pending = this.resourceConfigResolvers\n this.resourceConfigResolvers = []\n pending.forEach((resolver) => resolver.resolve())\n }\n\n /**\n * 创建火焰管理器。\n */\n private ensureFireManager(): FireManager {\n if (this.fireManager) return this.fireManager\n\n this.ensureParticleTexture()\n this.fireManager = new FireManager(this.five.scene, this.particleTexture)\n return this.fireManager\n }\n\n /**\n * 创建烟雾管理器。\n */\n private ensureSmokeManager(): SmokeManager {\n if (this.smokeManager) return this.smokeManager\n\n this.ensureParticleTexture()\n this.smokeManager = new SmokeManager(this.five.scene, SMOKE_RENDER_CONFIG, this.particleTexture)\n return this.smokeManager\n }\n\n private ensureParticleTexture(): void {\n if (!this.resourceConfig.particleTextureUrl) {\n throw new Error('粒子贴图未配置,请先调用 updateResourceConfig 设置 particleTexture')\n }\n }\n\n /** 把数据里的 work 局部坐标变换为场景世界坐标 */\n private toWorld(position: THREE.Vector3): THREE.Vector3 {\n return transformPosition(position, this.workUtil.transform)\n }\n\n /**\n * 把局部坐标的包围盒变换为世界坐标包围盒。\n */\n private toWorldBounds(bounds: FireSpreadBounds): FireSpreadBounds {\n const [minX, minY, minZ, maxX, maxY, maxZ] = bounds\n const corners = [\n [minX, minY, minZ],\n [maxX, minY, minZ],\n [minX, maxY, minZ],\n [maxX, maxY, minZ],\n [minX, minY, maxZ],\n [maxX, minY, maxZ],\n [minX, maxY, maxZ],\n [maxX, maxY, maxZ],\n ].map(([x, y, z]) => this.toWorld(new THREE.Vector3(x, y, z)))\n\n const box = new THREE.Box3().setFromPoints(corners)\n return [box.min.x, box.min.y, box.min.z, box.max.x, box.max.y, box.max.z]\n }\n\n /** 创建消防员的喷水粒子 */\n private createSprayParticle(firefighterId: string): Particle {\n const particle = new Particle({\n positionStyle: 'CUBE',\n positionBase: new THREE.Vector3(0, 0, 0),\n positionCubeSpread: new THREE.Vector3(0.05, 0.0, 0.05),\n velocityStyle: 'CUBE',\n velocityCubeBase: new THREE.Vector3(0, 1.0, -1.5),\n velocityCubeSpread: new THREE.Vector3(0.5, 0.5, 0.5),\n accelerationBase: new THREE.Vector3(0.3, -1.5, -2.5),\n texture: this.particleTexture.current,\n angleBase: 0,\n angleSpread: (90 / 180) * Math.PI,\n angleVelocityBase: 0,\n angleVelocitySpread: ((360 * 1) / 180) * Math.PI,\n sizeTween: { times: [0, 1], values: [0.005, 0.01] },\n opacityTween: { times: [1, 2], values: [1, 0] },\n colorTween: {\n times: [0.5, 2],\n values: [new THREE.Vector3(0, 0, 0.9), new THREE.Vector3(0, 0, 0.95)],\n },\n particlesPerSecond: 1000,\n particleDeathAge: 2,\n })\n particle.name = `${firefighterId}_water`\n particle.rotation.set(0, Math.PI * 1.05, 0)\n particle.position.set(0.05, 1.25, 1.5)\n return particle\n }\n}\n","import * as THREE from 'three/webgpu'\nimport type { FireArea, FireSceneConfig } from '../typing'\n\n/** 单位立方体的 8 个顶点,各轴 -0.5 ~ 0.5 */\nconst UNIT_BOX_VERTICES: [number, number, number][] = [\n [-0.5, -0.5, -0.5],\n [0.5, -0.5, -0.5],\n [0.5, -0.5, 0.5],\n [-0.5, -0.5, 0.5],\n [-0.5, 0.5, -0.5],\n [0.5, 0.5, -0.5],\n [0.5, 0.5, 0.5],\n [-0.5, 0.5, 0.5],\n]\n\n/**\n * 由起火区域的 matrix 求它的 8 个顶点。\n */\nexport function getAreaVertices(matrix: number[]): THREE.Vector3[] {\n const matrix4 = new THREE.Matrix4().fromArray(matrix)\n return UNIT_BOX_VERTICES.map((vertex) => new THREE.Vector3(...vertex).applyMatrix4(matrix4))\n}\n\n/**\n * 由起火区域的 matrix 求它的轴对齐包围盒。\n */\nexport function getAreaBox3(matrix: number[]): THREE.Box3 {\n return new THREE.Box3().setFromPoints(getAreaVertices(matrix))\n}\n\n/**\n * 求进场时应该观察的起火区域。\n */\nexport function getEntryArea(config: FireSceneConfig | undefined | null): FireArea | undefined {\n if (!config) return undefined\n const firstStep = config.ignite_sequences?.[0]\n const firstModel = firstStep && config.models?.find((model) => model.id === firstStep.model_id)\n const area = firstModel?.area_id && config.areas?.find((it) => it.id === firstModel.area_id)\n return area || config.areas?.[0]\n}\n","import * as THREE from 'three/webgpu'\nimport type { FireControl } from './FireControl'\nimport { FIRE_ACTION_DURATION_MS, FIRE_SPREAD_SPEED } from './constants'\nimport type { FireModel, FireSceneConfig, FireSequenceKind, FireSequenceStep, FireSpreadBounds } from './typing'\nimport { getAreaBox3 } from './utils/areaBounds'\n\n/** 播放器配置 */\nexport interface FireSequencePlayerOptions {\n /** 整条序列播完(最后一段动画也结束)后触发 */\n onSequenceEnd?: (kind: FireSequenceKind) => void\n}\n\n/**\n * 消防演绎时间轴播放器\n */\nexport class FireScenePlayer {\n private fireControl: FireControl\n private config: FireSceneConfig\n private options: FireSequencePlayerOptions\n\n private timers: ReturnType<typeof setTimeout>[] = []\n /** 当前正在播放的过程 */\n private playingKind: FireSequenceKind | null = null\n /** 已经触发过的动画段,停止时按它逐段去停 */\n private executedSteps: { kind: FireSequenceKind; model: FireModel }[] = []\n\n constructor(fireControl: FireControl, config: FireSceneConfig, options?: FireSequencePlayerOptions) {\n this.fireControl = fireControl\n this.config = config\n this.options = options ?? {}\n }\n\n /** 当前是否正在播放 */\n public get playing(): boolean {\n return this.playingKind !== null\n }\n\n /**\n * 播放一条序列。\n */\n public play(kind: FireSequenceKind): void {\n this.stop()\n this.playingKind = kind\n\n const steps = kind === 'ignite' ? this.config.ignite_sequences : this.config.extinguish_sequences\n if (steps.length === 0) {\n this.playingKind = null\n return\n }\n\n let absoluteMs = 0\n // 整条序列真正结束的时刻 = 各段「开始时刻 + 该段时长」的最大值\n let endMs = 0\n steps.forEach((step, index) => {\n absoluteMs += step.delay_ms\n const startsAt = absoluteMs\n const timer = setTimeout(() => {\n const model = this.runStep(kind, step)\n if (model) this.executedSteps.push({ kind, model })\n }, startsAt)\n this.timers.push(timer)\n\n endMs = Math.max(endMs, startsAt + (FIRE_ACTION_DURATION_MS[kind][this.findModel(step)?.type ?? 'fire'] ?? 0))\n })\n\n this.timers.push(\n setTimeout(() => {\n this.playingKind = null\n this.options.onSequenceEnd?.(kind)\n }, endMs),\n )\n }\n\n /**\n * 中断播放\n */\n public stop(): void {\n this.timers.forEach((timer) => clearTimeout(timer))\n this.timers = []\n this.playingKind = null\n\n const executed = this.executedSteps\n this.executedSteps = []\n executed.forEach(({ kind, model }) => this.stopStep(kind, model))\n }\n\n public dispose(): void {\n this.stop()\n }\n\n /** 停掉一段已经触发的动画 */\n private stopStep(kind: FireSequenceKind, model: FireModel): void {\n // 起火过程产生的实体由调用方 clearAll 统一清理,这里只回收灭火过程引入的动画\n if (kind === 'ignite') return\n\n if (model.type === 'firefighter') this.fireControl.removeFirefighter(model.id)\n else if (model.type === 'fire') this.fireControl.stopExtinguishFire(model.id)\n else this.fireControl.stopDissipateSmoke(model.id)\n }\n\n private findModel(step: FireSequenceStep): FireModel | undefined {\n return this.config.models.find((item) => item.id === step.model_id)\n }\n\n /**\n * 计算扩散范围\n */\n private getAreaBounds(model: FireModel): FireSpreadBounds | undefined {\n const area = this.config.areas.find((item) => item.id === model.area_id)\n if (!area) return undefined\n\n const box = getAreaBox3(area.matrix)\n return [box.min.x, box.min.y, box.min.z, box.max.x, box.max.y, box.max.z]\n }\n\n /** 执行一段动画 */\n private runStep(kind: FireSequenceKind, step: FireSequenceStep): FireModel | undefined {\n const model = this.findModel(step)\n if (!model) return\n\n if (!this.fireControl.hasParticleTexture) {\n console.warn('[FireScenePlugin] 粒子贴图未配置,跳过本段动画。请先调用 updateResourceConfig')\n return\n }\n\n const position: [number, number, number] = [model.position.x, model.position.y, model.position.z]\n const duration = FIRE_ACTION_DURATION_MS[kind][model.type]\n\n if (kind === 'ignite') {\n if (model.type === 'fire') {\n const bounds = this.getAreaBounds(model)\n this.fireControl.addFire(model.id, position, { size: model.scale, fadeInMs: duration })\n if (bounds) this.fireControl.igniteFire(model.id, bounds, { spreadSpeed: FIRE_SPREAD_SPEED })\n } else if (model.type === 'smoke') {\n const bounds = this.getAreaBounds(model)\n this.fireControl.addSmoke(model.id, position, { intensity: model.scale, fadeInMs: duration })\n if (bounds) this.fireControl.spreadSmoke(model.id, bounds, { spreadSpeed: FIRE_SPREAD_SPEED })\n }\n } else {\n if (model.type === 'firefighter') {\n if (!this.fireControl.hasWaterGunModel) {\n console.warn('[FireScenePlugin] 消防员模型未配置,跳过本段动画。请先调用 updateResourceConfig')\n return\n }\n void this.fireControl\n .addFirefighter({\n id: model.id,\n position,\n rotation: new THREE.Euler(model.rotation.x, model.rotation.y, model.rotation.z),\n scale: model.scale,\n spray: true,\n })\n .catch((error) => console.error('[FireScenePlugin] 消防员加载失败', error))\n } else if (model.type === 'fire') {\n this.fireControl.extinguishFire(model.id, { duration })\n } else if (model.type === 'smoke') {\n this.fireControl.dissipateSmoke(model.id, { duration })\n }\n }\n\n // 每段动画开始时都把镜头带到该段的实体\n void this.fireControl.focusEntity(model.id)\n\n return model\n }\n}\n"],"mappings":"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"}