@fps-games/vfx 0.3.2 → 0.3.3

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 (231) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +5 -4
  3. package/tooling/vfx-cli.mjs +8 -1
  4. package/docs/AUTHORING_EFFECTS.md +0 -297
  5. package/docs/INTEGRATION.md +0 -194
  6. package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +0 -1580
  7. package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +0 -229
  8. package/docs/VFX_LIBRARY_PLAN.md +0 -546
  9. package/docs/hit-flash-red-method.md +0 -155
  10. package/docs/treasure_attention_fx_babylonjs_guide.md +0 -901
  11. package/docs/vfx-ab/RESULTS.md +0 -35
  12. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
  13. package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
  14. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
  15. package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
  16. package/docs/vfx-integration_chatgpt.md +0 -462
  17. package/docs/vfx-placement-design.md +0 -164
  18. package/docs/weapon-trail-visualization.html +0 -241
  19. package/packages/EffectPackageService.ts +0 -346
  20. package/packages/SceneVfxService.ts +0 -96
  21. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +0 -333
  22. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +0 -25
  23. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +0 -11
  24. package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
  25. package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +0 -927
  26. package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
  27. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
  28. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
  29. package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
  30. package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
  31. package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +0 -197
  32. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +0 -895
  33. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +0 -241
  34. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +0 -542
  35. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +0 -69
  36. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +0 -125
  37. package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +0 -44
  38. package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +0 -210
  39. package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
  40. package/packages/build.particle.golden_upgrade_starburst/effect.json +0 -880
  41. package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
  42. package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
  43. package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
  44. package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
  45. package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
  46. package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +0 -161
  47. package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +0 -762
  48. package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  49. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +0 -436
  50. package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +0 -40
  51. package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +0 -115
  52. package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +0 -40
  53. package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +0 -210
  54. package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
  55. package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +0 -887
  56. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
  57. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
  58. package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
  59. package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
  60. package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +0 -179
  61. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +0 -859
  62. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
  63. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +0 -478
  64. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +0 -40
  65. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +0 -114
  66. package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +0 -41
  67. package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +0 -210
  68. package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
  69. package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
  70. package/packages/build.particle.wood_chip_dust_burst/effect.json +0 -1400
  71. package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
  72. package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
  73. package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
  74. package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
  75. package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
  76. package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +0 -173
  77. package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +0 -1277
  78. package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +0 -329
  79. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +0 -749
  80. package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +0 -60
  81. package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +0 -146
  82. package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +0 -69
  83. package/packages/effects/building-upgrade/effect.json +0 -6
  84. package/packages/effects/building-upgrade/index.ts +0 -387
  85. package/packages/effects/character-entrance/effect.json +0 -6
  86. package/packages/effects/character-entrance/index.ts +0 -308
  87. package/packages/effects/coin-burst/index.ts +0 -48
  88. package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
  89. package/packages/effects/comet-trail-flame/index.ts +0 -107
  90. package/packages/effects/conveyor-upgrade/effect.json +0 -6
  91. package/packages/effects/conveyor-upgrade/index.ts +0 -401
  92. package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
  93. package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
  94. package/packages/effects/debris-smoke/index.ts +0 -102
  95. package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +0 -397
  96. package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +0 -498
  97. package/packages/effects/door_open_gold_flakes/index.ts +0 -11
  98. package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
  99. package/packages/effects/electric-arc/index.ts +0 -63
  100. package/packages/effects/energy-shield/effect.json +0 -7
  101. package/packages/effects/energy-shield/index.ts +0 -432
  102. package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
  103. package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
  104. package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
  105. package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
  106. package/packages/effects/explosion/index.ts +0 -115
  107. package/packages/effects/ground-tile-upgrade/effect.json +0 -6
  108. package/packages/effects/ground-tile-upgrade/index.ts +0 -410
  109. package/packages/effects/hit-flash/index.ts +0 -77
  110. package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
  111. package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
  112. package/packages/effects/laser-beam/index.ts +0 -6
  113. package/packages/effects/laser-beam-factory.ts +0 -146
  114. package/packages/effects/lumber-cart-suction/effect.json +0 -6
  115. package/packages/effects/lumber-cart-suction/index.ts +0 -399
  116. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
  117. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +0 -1
  118. package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
  119. package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +0 -236
  120. package/packages/effects/lumber-debris-scatter/effect.json +0 -228
  121. package/packages/effects/lumber-debris-scatter/index.ts +0 -780
  122. package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +0 -202
  123. package/packages/effects/lumber_vehicle_gear_spin/index.ts +0 -11
  124. package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +0 -338
  125. package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +0 -353
  126. package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +0 -13
  127. package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +0 -365
  128. package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +0 -310
  129. package/packages/effects/lumber_vehicle_wood_chips/index.ts +0 -11
  130. package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +0 -335
  131. package/packages/effects/monster-hit/index.ts +0 -129
  132. package/packages/effects/player-upgrade/effect.json +0 -6
  133. package/packages/effects/player-upgrade/index.ts +0 -640
  134. package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
  135. package/packages/effects/pulse-laser-volley/index.ts +0 -215
  136. package/packages/effects/resource-collect-sparkles/effect.json +0 -6
  137. package/packages/effects/resource-collect-sparkles/index.ts +0 -254
  138. package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +0 -215
  139. package/packages/effects/run-footstep-dust/effect.json +0 -183
  140. package/packages/effects/run-footstep-dust/index.ts +0 -377
  141. package/packages/effects/space-shared.ts +0 -120
  142. package/packages/effects/thruster-flame/index.ts +0 -306
  143. package/packages/effects/treasure-attention/effect.json +0 -7
  144. package/packages/effects/treasure-attention/index.ts +0 -630
  145. package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
  146. package/packages/effects/tree-chop-dust/effect.json +0 -8
  147. package/packages/effects/tree-chop-dust/index.ts +0 -202
  148. package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +0 -303
  149. package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
  150. package/packages/effects/tree-leaf-chop-burst/effect.json +0 -498
  151. package/packages/effects/tree-leaf-chop-burst/index.ts +0 -294
  152. package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +0 -318
  153. package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
  154. package/packages/effects/tree_chop_dust_burst/index.ts +0 -13
  155. package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +0 -412
  156. package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
  157. package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
  158. package/packages/effects/ufo-thread-flame/index.ts +0 -153
  159. package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
  160. package/packages/effects/vehicle-exhaust-smoke/effect.json +0 -8
  161. package/packages/effects/vehicle-exhaust-smoke/index.ts +0 -298
  162. package/packages/effects/vehicle-upgrade/effect.json +0 -6
  163. package/packages/effects/vehicle-upgrade/index.ts +0 -404
  164. package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
  165. package/packages/effects/weapon-trail/index.ts +0 -317
  166. package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  167. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  168. package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  169. package/packages/effects/wood-crusher-sawdust/index.ts +0 -43
  170. package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +0 -592
  171. package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
  172. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  173. package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  174. package/packages/effects/wood-cutter-sawdust/index.ts +0 -43
  175. package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +0 -592
  176. package/packages/effects/wood-sawdust-effect-factory.ts +0 -194
  177. package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  178. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
  179. package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
  180. package/packages/effects/wood_crusher_sawdust/index.ts +0 -29
  181. package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +0 -592
  182. package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
  183. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
  184. package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
  185. package/packages/effects/wood_cutter_sawdust/index.ts +0 -29
  186. package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +0 -592
  187. package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +0 -196
  188. package/packages/effects/wood_peel_material_test/index.ts +0 -11
  189. package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +0 -136
  190. package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +0 -210
  191. package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
  192. package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
  193. package/packages/env.particle.forest_edge_fog/effect.json +0 -854
  194. package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
  195. package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
  196. package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
  197. package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
  198. package/packages/env.particle.forest_edge_fog/metadata/description.json +0 -148
  199. package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +0 -827
  200. package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +0 -196
  201. package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +0 -432
  202. package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +0 -28
  203. package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +0 -124
  204. package/packages/env.particle.forest_edge_fog/provenance/lineage.json +0 -41
  205. package/packages/generation.ts +0 -14
  206. package/packages/index.ts +0 -14
  207. package/packages/legacy-particle-runtime.ts +0 -113
  208. package/packages/manifestRuntimePackage.ts +0 -519
  209. package/packages/registry.ts +0 -85
  210. package/packages/rendering.ts +0 -13
  211. package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +0 -424
  212. package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
  213. package/packages/resource.particle.viscous_oil_suction/effect.json +0 -1254
  214. package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
  215. package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
  216. package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
  217. package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
  218. package/packages/resource.particle.viscous_oil_suction/metadata/description.json +0 -122
  219. package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +0 -1051
  220. package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +0 -200
  221. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +0 -581
  222. package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +0 -28
  223. package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +0 -111
  224. package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +0 -45
  225. package/packages/types.ts +0 -195
  226. package/tooling/check-dist-runtime.mjs +0 -166
  227. package/tooling/generate-index.mjs +0 -55
  228. package/tooling/test-guardrails.mjs +0 -157
  229. package/tooling/validate-boundary.mjs +0 -92
  230. package/tooling/validate-effects.mjs +0 -304
  231. package/tooling/validate.mjs +0 -53
@@ -1,294 +0,0 @@
1
- import { Color4 } from '@babylonjs/core/Maths/math.color';
2
- import { Vector3 } from '@babylonjs/core/Maths/math.vector';
3
- import { Sprite } from '@babylonjs/core/Sprites/sprite';
4
- import { SpriteManager } from '@babylonjs/core/Sprites/spriteManager';
5
- import type { Scene } from '@babylonjs/core/scene';
6
- import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
7
- import type { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
8
- import { configureVfxSpriteManager } from '../../rendering';
9
-
10
- interface TreeLeafChopBurstParams extends VfxParamValues {
11
- lifetime: number;
12
- scale: number;
13
- initialHeight: number;
14
- leafColor: VfxColorValue;
15
- deadColor: VfxColorValue;
16
- opacity: number;
17
- particleCount: number;
18
- emitRange: number;
19
- riseHeight: number;
20
- spread: number;
21
- minSpeed: number;
22
- maxSpeed: number;
23
- leafSize: number;
24
- gravity: number;
25
- }
26
-
27
- interface SourceEmitter {
28
- capacity?: unknown;
29
- manualEmitCount?: unknown;
30
- effectScale?: unknown;
31
- minSize?: unknown;
32
- maxSize?: unknown;
33
- minLifeTime?: unknown;
34
- maxLifeTime?: unknown;
35
- minEmitPower?: unknown;
36
- maxEmitPower?: unknown;
37
- updateSpeed?: unknown;
38
- gravity?: { y?: unknown };
39
- shape?: {
40
- direction1?: { x?: unknown; y?: unknown; z?: unknown };
41
- direction2?: { x?: unknown; y?: unknown; z?: unknown };
42
- minEmitBox?: { x?: unknown; y?: unknown; z?: unknown };
43
- maxEmitBox?: { x?: unknown; y?: unknown; z?: unknown };
44
- };
45
- runtime?: {
46
- stopAfterSeconds?: unknown;
47
- };
48
- }
49
-
50
- interface LeafSpriteState {
51
- sprite: Sprite;
52
- velocity: Vector3;
53
- spin: number;
54
- width: number;
55
- height: number;
56
- lifetime: number;
57
- }
58
-
59
- import LEAF_TEXTURE_URL from './assets/textures/tree_leaf_chop_burst_leaf_atlas.png?url';
60
- const SOURCE_EMITTER: SourceEmitter = {
61
- manualEmitCount: 42,
62
- effectScale: 1,
63
- maxSize: 0.21,
64
- maxLifeTime: 0.775,
65
- minEmitPower: 3.125,
66
- maxEmitPower: 3.125,
67
- gravity: { y: -3.8 },
68
- shape: {
69
- direction1: { x: -1.103, y: 0.55, z: -0.62 },
70
- direction2: { x: 0.943, y: 1.85, z: 0.62 },
71
- minEmitBox: { x: -0.08, y: 0.05, z: -0.08 },
72
- maxEmitBox: { x: 0.08, y: 0.18, z: 0.08 },
73
- },
74
- runtime: { stopAfterSeconds: 1.25 },
75
- };
76
- const SOURCE_SHAPE = SOURCE_EMITTER.shape ?? {};
77
-
78
- const DEFAULT_PARAMS: TreeLeafChopBurstParams = {
79
- lifetime: readNumber(SOURCE_EMITTER.maxLifeTime, 0.775),
80
- scale: readNumber(SOURCE_EMITTER.effectScale, 1),
81
- initialHeight: 1.4,
82
- leafColor: { r: 0.82, g: 1, b: 0.32 },
83
- deadColor: { r: 0.54, g: 0.43, b: 0.12 },
84
- opacity: 1,
85
- particleCount: readNumber(SOURCE_EMITTER.manualEmitCount, 42),
86
- emitRange: Math.max(
87
- Math.abs(readNumber(SOURCE_SHAPE.minEmitBox?.x, -0.08)),
88
- Math.abs(readNumber(SOURCE_SHAPE.maxEmitBox?.x, 0.08)),
89
- 0.08,
90
- ),
91
- riseHeight: Math.max(
92
- readNumber(SOURCE_SHAPE.direction1?.y, 0.55),
93
- readNumber(SOURCE_SHAPE.direction2?.y, 1.85),
94
- ),
95
- spread: Math.max(
96
- Math.abs(readNumber(SOURCE_SHAPE.direction1?.x, -1.103)),
97
- Math.abs(readNumber(SOURCE_SHAPE.direction2?.x, 0.943)),
98
- Math.abs(readNumber(SOURCE_SHAPE.direction1?.z, -0.62)),
99
- Math.abs(readNumber(SOURCE_SHAPE.direction2?.z, 0.62)),
100
- ),
101
- minSpeed: readNumber(SOURCE_EMITTER.minEmitPower, 3.125),
102
- maxSpeed: readNumber(SOURCE_EMITTER.maxEmitPower, 3.125),
103
- leafSize: readNumber(SOURCE_EMITTER.maxSize, 0.21),
104
- gravity: Math.abs(readNumber(SOURCE_EMITTER.gravity?.y, -3.8)),
105
- };
106
-
107
- export const treeLeafChopBurstEffectPackage: VfxEffectPackage<TreeLeafChopBurstParams> = {
108
- id: 'tree-leaf-chop-burst',
109
- nameZh: '砍树树叶溅射',
110
- manifest: {
111
- id: 'build.particle.tree_leaf_chop_burst',
112
- nameZh: '砍树树叶溅射',
113
- assets: [
114
- 'assets/textures/tree_leaf_chop_burst_leaf_atlas.png',
115
- ],
116
- source: 'tree_leaf_chop_burst.json',
117
- },
118
- defaultParams: DEFAULT_PARAMS,
119
- debugAnchor: 'player',
120
- debugParams: [
121
- { key: 'lifetime', label: '生命周期', kind: 'lifetime', min: 0.08, max: 4, step: 0.01 },
122
- { key: 'scale', label: '整体缩放', kind: 'scale', min: 0.1, max: 8, step: 0.01 },
123
- { key: 'initialHeight', label: '初始高度', kind: 'number', min: 0, max: 5, step: 0.01 },
124
- { key: 'leafColor', label: '叶子颜色', kind: 'color' },
125
- { key: 'deadColor', label: '消失颜色', kind: 'color' },
126
- { key: 'opacity', label: '透明度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
127
- { key: 'particleCount', label: '粒子数量', kind: 'number', min: 1, max: 160, step: 1 },
128
- { key: 'emitRange', label: '发射范围', kind: 'number', min: 0, max: 2, step: 0.01 },
129
- { key: 'riseHeight', label: '上升高度', kind: 'number', min: 0, max: 6, step: 0.01 },
130
- { key: 'spread', label: '扩散幅度', kind: 'number', min: 0, max: 8, step: 0.01 },
131
- { key: 'minSpeed', label: '最小速度', kind: 'number', min: 0, max: 20, step: 0.01 },
132
- { key: 'maxSpeed', label: '最大速度', kind: 'number', min: 0, max: 30, step: 0.01 },
133
- { key: 'leafSize', label: '叶片大小', kind: 'number', min: 0.01, max: 3, step: 0.01 },
134
- { key: 'gravity', label: '下落重力', kind: 'number', min: 0, max: 16, step: 0.01 },
135
- ],
136
- create({ scene, root, position, renderingGroupId, params }) {
137
- root.position.copyFrom(position).addInPlace(new Vector3(0, params.initialHeight, 0));
138
- const leaves = createLeafSpriteBurst(scene, root, params, renderingGroupId);
139
- let disposed = false;
140
-
141
- const disposeDelay = getDisposeDelaySeconds(params);
142
- const disposeTimer = window.setTimeout(() => disposeAll(), disposeDelay * 1000);
143
-
144
- return {
145
- root,
146
- dispose() {
147
- disposeAll();
148
- },
149
- };
150
-
151
- function disposeAll(): void {
152
- if (disposed) return;
153
- disposed = true;
154
- window.clearTimeout(disposeTimer);
155
- leaves.dispose();
156
- root.dispose();
157
- }
158
- },
159
- };
160
-
161
- function createLeafSpriteBurst(
162
- scene: Scene,
163
- root: TransformNode,
164
- params: TreeLeafChopBurstParams,
165
- renderingGroupId?: number,
166
- ): { dispose(): void } {
167
- const count = Math.max(1, Math.round(params.particleCount));
168
- const spatialScale = Math.sqrt(Math.max(0.1, params.scale));
169
- const manager = new SpriteManager('tree-leaf-chop-burst.leaves', LEAF_TEXTURE_URL, count, { width: 128, height: 128 }, scene);
170
- configureVfxSpriteManager(manager);
171
- if (renderingGroupId !== undefined) manager.renderingGroupId = renderingGroupId;
172
- manager.texture.hasAlpha = true;
173
- manager.texture.getAlphaFromRGB = false;
174
- manager.fogEnabled = false;
175
-
176
- const minSpeed = Math.max(0, Math.min(params.minSpeed, params.maxSpeed));
177
- const maxSpeed = Math.max(minSpeed, params.maxSpeed);
178
- const minLife = Math.max(0.03, params.lifetime * 0.72);
179
- const maxLife = Math.max(minLife, params.lifetime);
180
- const origin = root.getAbsolutePosition().clone();
181
- const states: LeafSpriteState[] = [];
182
-
183
- for (let index = 0; index < count; index += 1) {
184
- const sprite = new Sprite(`tree-leaf-chop-burst.leaf.${index}`, manager);
185
- const localPosition = new Vector3(
186
- lerp(-params.emitRange * spatialScale, params.emitRange * spatialScale, sequence01(index, 0)),
187
- lerp(0.05 * spatialScale, 0.18 * spatialScale, sequence01(index, 1)),
188
- lerp(-params.emitRange * spatialScale, params.emitRange * spatialScale, sequence01(index, 2)),
189
- );
190
- const direction = new Vector3(
191
- lerp(-params.spread * spatialScale, params.spread * 0.85 * spatialScale, sequence01(index, 3)),
192
- lerp(params.riseHeight * 0.3 * spatialScale, params.riseHeight * spatialScale, sequence01(index, 4)),
193
- lerp(-params.spread * 0.56 * spatialScale, params.spread * 0.56 * spatialScale, sequence01(index, 5)),
194
- );
195
- const speed = lerp(minSpeed, maxSpeed, sequence01(index, 6));
196
- if (direction.lengthSquared() > 0.0001) direction.normalize().scaleInPlace(speed);
197
-
198
- const size = Math.max(0.01, params.leafSize * params.scale * lerp(0.72, 1.24, sequence01(index, 7)));
199
- sprite.position = origin.add(localPosition);
200
- sprite.cellIndex = Math.floor(sequence01(index, 8) * 16) % 16;
201
- sprite.width = size * lerp(0.82, 1.28, sequence01(index, 9));
202
- sprite.height = size * lerp(0.72, 1.08, sequence01(index, 10));
203
- sprite.angle = sequence01(index, 11) * Math.PI * 2;
204
- sprite.color = toColor4(params.leafColor, params.opacity);
205
- states.push({
206
- sprite,
207
- velocity: direction,
208
- spin: lerp(-8, 8, sequence01(index, 12)),
209
- width: sprite.width,
210
- height: sprite.height,
211
- lifetime: lerp(minLife, maxLife, sequence01(index, 13)),
212
- });
213
- }
214
-
215
- let age = 0;
216
- let disposed = false;
217
- const observer = scene.onBeforeRenderObservable.add(() => {
218
- if (disposed) return;
219
- const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1000);
220
- age += deltaSeconds;
221
- for (const state of states) {
222
- const t = Math.min(1, age / state.lifetime);
223
- const fade = t < 0.72 ? 1 : Math.max(0, 1 - (t - 0.72) / 0.28);
224
- const color = mixColor(params.leafColor, params.deadColor, Math.max(0, (t - 0.55) / 0.45));
225
- state.velocity.y -= Math.max(0, params.gravity) * deltaSeconds;
226
- state.sprite.position.addInPlace(state.velocity.scale(deltaSeconds));
227
- state.sprite.angle += state.spin * deltaSeconds;
228
- state.sprite.color = toColor4(color, params.opacity * fade);
229
- const shrink = 1 - Math.max(0, t - 0.78) / 0.22 * 0.65;
230
- state.sprite.width = state.width * shrink;
231
- state.sprite.height = state.height * shrink;
232
- state.sprite.isVisible = fade > 0.01;
233
- }
234
- if (age >= maxLife + 0.08) dispose();
235
- });
236
-
237
- function dispose(): void {
238
- if (disposed) return;
239
- disposed = true;
240
- scene.onBeforeRenderObservable.remove(observer);
241
- for (const state of states) state.sprite.dispose();
242
- manager.dispose();
243
- }
244
-
245
- return { dispose };
246
- }
247
-
248
- function getDisposeDelaySeconds(params: TreeLeafChopBurstParams): number {
249
- return Math.max(
250
- readNumber(SOURCE_EMITTER.runtime?.stopAfterSeconds, 1.25),
251
- params.lifetime + 0.45,
252
- );
253
- }
254
-
255
- function toColor4(color: VfxColorValue, alpha: number): Color4 {
256
- return new Color4(
257
- clamp01(color.r),
258
- clamp01(color.g),
259
- clamp01(color.b),
260
- clamp01(alpha),
261
- );
262
- }
263
-
264
- function mixColor(from: VfxColorValue, to: VfxColorValue, amount: number): VfxColorValue {
265
- const t = clamp01(amount);
266
- return {
267
- r: from.r + (to.r - from.r) * t,
268
- g: from.g + (to.g - from.g) * t,
269
- b: from.b + (to.b - from.b) * t,
270
- };
271
- }
272
-
273
- function readNumber(value: unknown, fallback: number): number {
274
- const next = Number(value);
275
- return Number.isFinite(next) ? next : fallback;
276
- }
277
-
278
- function clamp01(value: number): number {
279
- return Math.min(1, Math.max(0, value));
280
- }
281
-
282
- function lerp(min: number, max: number, t: number): number {
283
- return min + (max - min) * t;
284
- }
285
-
286
- function fract(value: number): number {
287
- return value - Math.floor(value);
288
- }
289
-
290
- function sequence01(index: number, axis: number): number {
291
- if (index === 0) return 0.5;
292
- const strides = [0.618033988749895, 0.414213562373095, 0.732050807568877, 0.324717957244746, 0.754877666246693, 0.569840290998053];
293
- return fract(0.5 + index * strides[axis % strides.length] + axis * 0.173205080756888);
294
- }
@@ -1,318 +0,0 @@
1
- export const runtimeId = "particleEmitter/v1";
2
-
3
- export const runtimeContract = {
4
- runtimeId,
5
- kind: "particleEmitter",
6
- emitterFields: {
7
- capacity: "Maximum Babylon particle capacity.",
8
- particleTexturePath: "Package-relative particle texture path used to load the Babylon ParticleSystem.particleTexture.",
9
- blendMode: "Babylon particle blend mode label: ADD, STANDARD, MULTIPLY, or ONEONE.",
10
- shape: "Emitter shape definition generated by the package build stage.",
11
- spriteSheet: "Optional Babylon particle spritesheet settings for atlas-based particle textures.",
12
- effectScale: "Spatial scale for the whole effect; scales emitter volume, particle size, velocity, and gravity together.",
13
- renderColor: "Converted particle color inputs: one base color plus RGB/alpha intensity before writing Babylon color1/color2/colorDead.",
14
- alphaKeys: "Color alpha gradients sampled over normalized particle lifetime.",
15
- sizeKeys: "Size gradients sampled over normalized particle lifetime.",
16
- },
17
- runtimeBindings: {
18
- "ParticleSystem.particleTexture": "Texture loaded from emitter.particleTexturePath through urlForPackagePath.",
19
- "ParticleSystem.blendMode": "Mapped from emitter.blendMode.",
20
- "ParticleSystem.manualEmitCount": "emitter.manualEmitCount when emitRate is 0.",
21
- "ParticleSystem.emitRate": "emitter.emitRate for sustained emitters.",
22
- "ParticleSystem.shape": "Mapped from emitter.shape.type and shape parameters, then scaled by emitter.effectScale.",
23
- "ParticleSystem.spriteSheet": "Applied from emitter.spriteSheet when enabled.",
24
- "ParticleSystem.colorGradient": "emitter.alphaKeys applied to the final ParticleSystem.color1.",
25
- "ParticleSystem.sizeGradient": "emitter.sizeKeys multiplied by emitter.maxSize and emitter.effectScale.",
26
- },
27
- };
28
-
29
- const BABYLON_PARTICLE_UPDATE_SPEED_UNIT = 0.01;
30
-
31
- function num(value, fallback = 0) {
32
- const next = Number(value);
33
- return Number.isFinite(next) ? next : fallback;
34
- }
35
-
36
- function readColor(BABYLON, value, fallback = new BABYLON.Color4(1, 1, 1, 1)) {
37
- if (!value) return fallback;
38
- return new BABYLON.Color4(num(value.r, fallback.r), num(value.g, fallback.g), num(value.b, fallback.b), num(value.a, fallback.a));
39
- }
40
-
41
- function applyRenderColorIntensity(BABYLON, color, renderColor = {}) {
42
- const colorIntensity = Math.max(0, num(renderColor.colorIntensity, 1));
43
- const alphaIntensity = Math.max(0, num(renderColor.alphaIntensity, colorIntensity));
44
- return new BABYLON.Color4(
45
- color.r * colorIntensity,
46
- color.g * colorIntensity,
47
- color.b * colorIntensity,
48
- Math.min(1, color.a * alphaIntensity)
49
- );
50
- }
51
-
52
- function particleColors(BABYLON, emitter) {
53
- const renderColor = emitter.renderColor;
54
- const baseColor = readColor(BABYLON, renderColor?.color, new BABYLON.Color4(1, 1, 1, 1));
55
- const color1 = applyRenderColorIntensity(BABYLON, baseColor, renderColor);
56
- return {
57
- color1,
58
- color2: color1,
59
- colorDead: new BABYLON.Color4(color1.r, color1.g, color1.b, 0),
60
- };
61
- }
62
-
63
- function readVec(BABYLON, value, fallback = new BABYLON.Vector3(0, 0, 0)) {
64
- if (!value) return fallback;
65
- return new BABYLON.Vector3(num(value.x, fallback.x), num(value.y, fallback.y), num(value.z, fallback.z));
66
- }
67
-
68
- function blendMode(BABYLON, value) {
69
- if (value === "STANDARD") return BABYLON.ParticleSystem.BLENDMODE_STANDARD;
70
- if (value === "MULTIPLY") return BABYLON.ParticleSystem.BLENDMODE_MULTIPLY;
71
- if (value === "ONEONE") return BABYLON.ParticleSystem.BLENDMODE_ONEONE;
72
- return BABYLON.ParticleSystem.BLENDMODE_ADD;
73
- }
74
-
75
- function billboardMode(BABYLON, value) {
76
- if (!value || BABYLON.ParticleSystem[value] === undefined) return undefined;
77
- return BABYLON.ParticleSystem[value];
78
- }
79
-
80
- function effectScale(emitter) {
81
- return Math.max(0.0001, num(emitter.effectScale, 1));
82
- }
83
-
84
- function applyRenderOrder(system, emitter) {
85
- system.renderingGroupId = Math.max(0, Math.round(num(emitter.renderingGroupId, 2)));
86
- system.alphaIndex = num(emitter.alphaIndex, 100);
87
- if ("forceDepthWrite" in system) {
88
- system.forceDepthWrite = false;
89
- }
90
- }
91
-
92
- function isDeterministic(emitter) {
93
- return emitter?.deterministic !== false && emitter?.randomize !== true;
94
- }
95
-
96
- function midpoint(min, max) {
97
- return (min + max) * 0.5;
98
- }
99
-
100
- function fract(value) {
101
- return value - Math.floor(value);
102
- }
103
-
104
- function sequence01(index, axis) {
105
- if (index === 0) return 0.5;
106
- const strides = [0.618033988749895, 0.414213562373095, 0.732050807568877, 0.324717957244746, 0.754877666246693, 0.569840290998053];
107
- return fract(0.5 + index * strides[axis % strides.length] + axis * 0.173205080756888);
108
- }
109
-
110
- function lerp(min, max, t) {
111
- return min + (max - min) * t;
112
- }
113
-
114
- function applyDeterministicBoxEmitter(BABYLON, system, direction1, direction2, boxMin, boxMax) {
115
- system.minEmitBox = boxMin;
116
- system.maxEmitBox = boxMax;
117
- system.direction1 = direction1;
118
- system.direction2 = direction2;
119
-
120
- let positionIndex = 0;
121
- let directionIndex = 0;
122
-
123
- system.startPositionFunction = (worldMatrix, positionToUpdate, _particle, isLocal) => {
124
- const index = positionIndex;
125
- positionIndex += 1;
126
- const x = lerp(boxMin.x, boxMax.x, sequence01(index, 0));
127
- const y = lerp(boxMin.y, boxMax.y, sequence01(index, 1));
128
- const z = lerp(boxMin.z, boxMax.z, sequence01(index, 2));
129
- if (isLocal) positionToUpdate.set(x, y, z);
130
- else BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(x, y, z, worldMatrix, positionToUpdate);
131
- };
132
-
133
- system.startDirectionFunction = (worldMatrix, directionToUpdate, _particle, isLocal) => {
134
- const index = directionIndex;
135
- directionIndex += 1;
136
- const x = lerp(direction1.x, direction2.x, sequence01(index, 3));
137
- const y = lerp(direction1.y, direction2.y, sequence01(index, 4));
138
- const z = lerp(direction1.z, direction2.z, sequence01(index, 5));
139
- if (isLocal) directionToUpdate.set(x, y, z);
140
- else BABYLON.Vector3.TransformNormalFromFloatsToRef(x, y, z, worldMatrix, directionToUpdate);
141
- };
142
- }
143
-
144
- function applyCocosConeEmitFunctions(BABYLON, system, radius, angle, radiusRange, scale) {
145
- const safeRadius = Math.max(0, radius * scale);
146
- const innerSq = (safeRadius * Math.max(0, 1 - radiusRange)) ** 2;
147
- const outerSq = safeRadius * safeRadius;
148
- const halfAngle = Math.min(Math.PI, Math.max(0, angle));
149
- const cosAngle = Math.cos(halfAngle);
150
-
151
- system.startPositionFunction = (worldMatrix, positionToUpdate, _particle, isLocal) => {
152
- const s = Math.random() * Math.PI * 2;
153
- const r2 = innerSq + Math.random() * (outerSq - innerSq);
154
- const r = Math.sqrt(Math.max(0, r2));
155
- const lx = r * Math.cos(s);
156
- const lz = r * Math.sin(s);
157
- if (isLocal) positionToUpdate.set(lx, 0, lz);
158
- else BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(lx, 0, lz, worldMatrix, positionToUpdate);
159
- };
160
-
161
- system.startDirectionFunction = (worldMatrix, directionToUpdate, _particle, isLocal) => {
162
- const phi = Math.random() * Math.PI * 2;
163
- const cosTheta = 1 - Math.random() * (1 - cosAngle);
164
- const sinTheta = Math.sqrt(Math.max(0, 1 - cosTheta * cosTheta));
165
- const dx = sinTheta * Math.cos(phi);
166
- const dy = cosTheta;
167
- const dz = sinTheta * Math.sin(phi);
168
- if (isLocal) directionToUpdate.set(dx, dy, dz);
169
- else BABYLON.Vector3.TransformNormalFromFloatsToRef(dx, dy, dz, worldMatrix, directionToUpdate);
170
- };
171
- }
172
-
173
- function applyEmitterShape(BABYLON, system, emitter) {
174
- const scale = effectScale(emitter);
175
- const shape = emitter.shape || {};
176
- const type = shape.type;
177
- const radius = num(shape.radius, 1);
178
- const radiusRange = Math.min(1, Math.max(0, num(shape.radiusRange, 1)));
179
- const angle = num(shape.angle, Math.PI / 4);
180
- const direction1 = readVec(BABYLON, shape.direction1, new BABYLON.Vector3(0, 1, 0));
181
- const direction2 = readVec(BABYLON, shape.direction2, new BABYLON.Vector3(0, 1, 0));
182
- const boxMin = readVec(BABYLON, shape.minEmitBox, new BABYLON.Vector3(-radius * 0.5, -radius * 0.5, -radius * 0.5)).scale(scale);
183
- const boxMax = readVec(BABYLON, shape.maxEmitBox, new BABYLON.Vector3(radius * 0.5, radius * 0.5, radius * 0.5)).scale(scale);
184
-
185
- if (type === "Box") {
186
- if (isDeterministic(emitter)) applyDeterministicBoxEmitter(BABYLON, system, direction1, direction2, boxMin, boxMax);
187
- else system.createBoxEmitter(direction1, direction2, boxMin, boxMax);
188
- } else if (type === "SphereDirected") {
189
- system.createDirectedSphereEmitter(radius * scale, direction1, direction2);
190
- } else if (type === "Sphere") {
191
- system.createSphereEmitter(radius * scale, radiusRange);
192
- } else if (type === "Hemisphere") {
193
- system.createHemisphericEmitter(radius * scale, radiusRange);
194
- } else if (type === "Cone") {
195
- const dirSpread = direction1.subtract(direction2).lengthSquared();
196
- if (dirSpread < 1e-4) {
197
- system.createConeEmitter(Math.max(0.001, radius * scale), angle);
198
- applyCocosConeEmitFunctions(BABYLON, system, radius, angle, radiusRange, scale);
199
- } else {
200
- system.createDirectedConeEmitter(Math.max(0.001, radius * scale), angle, direction1, direction2);
201
- }
202
- }
203
- }
204
-
205
- function applySpriteSheet(system, emitter) {
206
- const spriteSheet = emitter.spriteSheet || {};
207
- if (!spriteSheet.enabled) return;
208
- const deterministic = isDeterministic(emitter);
209
-
210
- system.isAnimationSheetEnabled = true;
211
- system.spriteCellWidth = Math.max(1, Math.round(num(spriteSheet.cellWidth, 256)));
212
- system.spriteCellHeight = Math.max(1, Math.round(num(spriteSheet.cellHeight, 256)));
213
- system.startSpriteCellID = Math.max(0, Math.round(num(spriteSheet.startCellID, 0)));
214
- system.endSpriteCellID = Math.max(system.startSpriteCellID, Math.round(num(spriteSheet.endCellID, system.startSpriteCellID)));
215
- system.spriteCellChangeSpeed = Math.max(0, num(spriteSheet.cellChangeSpeed, 0));
216
- system.spriteRandomStartCell = deterministic ? spriteSheet.randomStartCell === true && emitter.randomize === true : spriteSheet.randomStartCell !== false;
217
- }
218
-
219
- function addGradients(BABYLON, system, emitter, color1) {
220
- const scale = effectScale(emitter);
221
- for (const key of emitter.alphaKeys || []) {
222
- const time = Math.min(1, Math.max(0, num(key.time, 0)));
223
- const alpha = Math.min(1, Math.max(0, num(key.alpha, 1)));
224
- system.addColorGradient?.(time, new BABYLON.Color4(color1.r, color1.g, color1.b, Math.min(1, color1.a * alpha)));
225
- }
226
- for (const key of emitter.sizeKeys || []) {
227
- const time = Math.min(1, Math.max(0, num(key.time, 0)));
228
- const size = Math.max(0.001, num(key.size, 1) * num(emitter.maxSize, 1) * scale);
229
- system.addSizeGradient?.(time, size);
230
- }
231
- }
232
-
233
- function playbackSpeed(emitter) {
234
- return Math.max(0.001, num(emitter.updateSpeed, BABYLON_PARTICLE_UPDATE_SPEED_UNIT) / BABYLON_PARTICLE_UPDATE_SPEED_UNIT);
235
- }
236
-
237
- function runtimeDuration(emitter) {
238
- return Math.max(0.1, num(emitter.runtime?.stopAfterSeconds, 3) / playbackSpeed(emitter));
239
- }
240
-
241
- export async function createParticleEmitterRuntime({ BABYLON, scene, emitter, index = 0, urlForPackagePath, shouldStart = false }) {
242
- if (!BABYLON) throw new Error("createParticleEmitterRuntime requires BABYLON.");
243
- if (!scene) throw new Error("createParticleEmitterRuntime requires scene.");
244
- if (!emitter) throw new Error("createParticleEmitterRuntime requires emitter.");
245
-
246
- const scale = effectScale(emitter);
247
- const deterministic = isDeterministic(emitter);
248
- const capacity = Math.max(1, Math.round(num(emitter.capacity, 100)));
249
- const system = new BABYLON.ParticleSystem(`particle-emitter-${emitter.name || index}`, capacity, scene);
250
- const root = new BABYLON.TransformNode(`particle-emitter-root-${emitter.name || index}`, scene);
251
- root.position.copyFrom(readVec(BABYLON, emitter.origin, BABYLON.Vector3.Zero()));
252
- root.rotation.y = num(emitter.rotationY, 0);
253
- applyRenderOrder(system, emitter);
254
- const textureUrl = urlForPackagePath ? urlForPackagePath(emitter.particleTexturePath) : emitter.particleTexturePath;
255
- system.particleTexture = new BABYLON.Texture(textureUrl, scene);
256
- system.particleTexture.hasAlpha = true;
257
- system.emitter = root;
258
- system.blendMode = blendMode(BABYLON, emitter.blendMode);
259
- system.isLocal = emitter.isLocal === true;
260
- const minSize = Math.max(0.001, num(emitter.minSize, 1) * scale);
261
- const maxSize = Math.max(minSize, num(emitter.maxSize, minSize) * scale);
262
- system.minSize = deterministic ? midpoint(minSize, maxSize) : minSize;
263
- system.maxSize = deterministic ? system.minSize : maxSize;
264
- const minScaleX = Math.max(0.001, num(emitter.minScaleX, 1));
265
- const maxScaleX = Math.max(minScaleX, num(emitter.maxScaleX, minScaleX));
266
- system.minScaleX = deterministic ? midpoint(minScaleX, maxScaleX) : minScaleX;
267
- system.maxScaleX = deterministic ? system.minScaleX : maxScaleX;
268
- const minScaleY = Math.max(0.001, num(emitter.minScaleY, 1));
269
- const maxScaleY = Math.max(minScaleY, num(emitter.maxScaleY, minScaleY));
270
- system.minScaleY = deterministic ? midpoint(minScaleY, maxScaleY) : minScaleY;
271
- system.maxScaleY = deterministic ? system.minScaleY : maxScaleY;
272
- const minLifeTime = Math.max(0.02, num(emitter.minLifeTime, 0.55));
273
- const maxLifeTime = Math.max(minLifeTime, num(emitter.maxLifeTime, minLifeTime));
274
- system.minLifeTime = deterministic ? midpoint(minLifeTime, maxLifeTime) : minLifeTime;
275
- system.maxLifeTime = deterministic ? system.minLifeTime : maxLifeTime;
276
- const minEmitPower = Math.max(0, num(emitter.minEmitPower, 1) * scale);
277
- const maxEmitPower = Math.max(minEmitPower, num(emitter.maxEmitPower, minEmitPower) * scale);
278
- system.minEmitPower = deterministic ? midpoint(minEmitPower, maxEmitPower) : minEmitPower;
279
- system.maxEmitPower = deterministic ? system.minEmitPower : maxEmitPower;
280
- system.updateSpeed = Math.max(0.00001, num(emitter.updateSpeed, BABYLON_PARTICLE_UPDATE_SPEED_UNIT));
281
- system.gravity = readVec(BABYLON, emitter.gravity, new BABYLON.Vector3(0, -6, 0)).scale(scale);
282
- system.emitRate = Math.max(0, num(emitter.emitRate, 0));
283
- if (system.emitRate <= 0) system.manualEmitCount = Math.max(0, Math.round(num(emitter.manualEmitCount, 0)));
284
-
285
- const colors = particleColors(BABYLON, emitter);
286
- system.color1 = colors.color1;
287
- system.color2 = colors.color2;
288
- system.colorDead = colors.colorDead;
289
- const minInitialRotation = num(emitter.minInitialRotation, 0);
290
- const maxInitialRotation = Math.max(minInitialRotation, num(emitter.maxInitialRotation, minInitialRotation));
291
- system.minInitialRotation = deterministic ? midpoint(minInitialRotation, maxInitialRotation) : minInitialRotation;
292
- system.maxInitialRotation = deterministic ? system.minInitialRotation : maxInitialRotation;
293
- const minAngularSpeed = num(emitter.minAngularSpeed, 0);
294
- const maxAngularSpeed = Math.max(minAngularSpeed, num(emitter.maxAngularSpeed, minAngularSpeed));
295
- system.minAngularSpeed = deterministic ? midpoint(minAngularSpeed, maxAngularSpeed) : minAngularSpeed;
296
- system.maxAngularSpeed = deterministic ? system.minAngularSpeed : maxAngularSpeed;
297
-
298
- const nextBillboardMode = billboardMode(BABYLON, emitter.billboardMode);
299
- if (nextBillboardMode !== undefined) system.billboardMode = nextBillboardMode;
300
-
301
- applyEmitterShape(BABYLON, system, emitter);
302
- applySpriteSheet(system, emitter);
303
- addGradients(BABYLON, system, emitter, system.color1);
304
-
305
- const preview = {
306
- start: () => system.start(),
307
- stop: () => system.stop(),
308
- dispose: () => {
309
- system.dispose();
310
- root.dispose();
311
- },
312
- isStarted: () => system.isStarted(),
313
- duration: runtimeDuration(emitter),
314
- system,
315
- };
316
- if (shouldStart) preview.start();
317
- return preview;
318
- }
@@ -1,13 +0,0 @@
1
- import manifest from './tree_chop_dust_burst.json';
2
- import runtimeUrl from './assets/runtime/particleEmitter.v1.js?url';
3
- import dustTextureUrl from './assets/textures/tree_chop_dust_burst_dust.png?url';
4
- import { createManifestRuntimeEffectPackage } from '../../manifestRuntimePackage';
5
-
6
- export const treeChopDustBurstEffectPackage = createManifestRuntimeEffectPackage({
7
- id: 'tree_chop_dust_burst',
8
- manifest,
9
- assetUrls: {
10
- 'assets/runtime/particleEmitter.v1.js': runtimeUrl,
11
- 'assets/textures/tree_chop_dust_burst_dust.png': dustTextureUrl,
12
- },
13
- });