@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,640 +0,0 @@
1
- import { Color3, Color4 } from '@babylonjs/core/Maths/math.color';
2
- import { Vector3 } from '@babylonjs/core/Maths/math.vector';
3
- import { Constants } from '@babylonjs/core/Engines/constants';
4
- import { DynamicTexture } from '@babylonjs/core/Materials/Textures/dynamicTexture';
5
- import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
6
- import { CreateCylinder } from '@babylonjs/core/Meshes/Builders/cylinderBuilder';
7
- import { CreateDisc } from '@babylonjs/core/Meshes/Builders/discBuilder';
8
- import { CreatePlane } from '@babylonjs/core/Meshes/Builders/planeBuilder';
9
- import { CreateTorus } from '@babylonjs/core/Meshes/Builders/torusBuilder';
10
- import type { Mesh } from '@babylonjs/core/Meshes/mesh';
11
- import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem';
12
- import type { Scene } from '@babylonjs/core/scene';
13
- import type { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
14
- import { configureVfxParticleSystem, VFX_RENDERING_GROUP_ID } from '../../rendering';
15
- import manifest from './effect.json';
16
-
17
- interface PlayerUpgradeParams extends VfxParamValues {
18
- lifetime: number;
19
- scale: number;
20
- initialHeight: number;
21
- color: VfxColorValue;
22
- opacity: number;
23
- strandCount: number;
24
- strandLength: number;
25
- strandHeight: number;
26
- strandRadius: number;
27
- strandWidth: number;
28
- riseSpeed: number;
29
- ringCount: number;
30
- ringMaxRadius: number;
31
- ringThickness: number;
32
- ringInterval: number;
33
- ringOpacity: number;
34
- glowIntensity: number;
35
- glowHeight: number;
36
- glowWidth: number;
37
- }
38
-
39
- interface RingState {
40
- mesh: Mesh;
41
- material: StandardMaterial;
42
- startDelay: number;
43
- duration: number;
44
- }
45
-
46
- interface StrandMeshState {
47
- mesh: Mesh;
48
- material: StandardMaterial;
49
- height: number;
50
- startDelay: number;
51
- duration: number;
52
- }
53
-
54
- const strandTextureByScene = new WeakMap<Scene, DynamicTexture>();
55
- const glowTextureByScene = new WeakMap<Scene, DynamicTexture>();
56
- const haloTextureByScene = new WeakMap<Scene, DynamicTexture>();
57
-
58
- const DEFAULT_PARAMS: PlayerUpgradeParams = {
59
- lifetime: 2.4,
60
- scale: 1,
61
- initialHeight: 0.02,
62
- color: { r: 1, g: 0.78, b: 0.08 },
63
- opacity: 1,
64
- strandCount: 120,
65
- strandLength: 0.72,
66
- strandHeight: 1.55,
67
- strandRadius: 0.58,
68
- strandWidth: 0.075,
69
- riseSpeed: 1.45,
70
- ringCount: 4,
71
- ringMaxRadius: 2.15,
72
- ringThickness: 0.09,
73
- ringInterval: 0.28,
74
- ringOpacity: 1,
75
- glowIntensity: 1.85,
76
- glowHeight: 2.15,
77
- glowWidth: 1.08,
78
- };
79
-
80
- export const playerUpgradeEffectPackage: VfxEffectPackage<PlayerUpgradeParams> = {
81
- id: 'player-upgrade',
82
- nameZh: '人物&NPC升级',
83
- placement: 'socket',
84
- manifest,
85
- defaultParams: DEFAULT_PARAMS,
86
- // initialHeight 走 service 存活的 Y 偏移通道(不写 root.position,避免被 applySpawnToRoot 覆盖)(G6/M13)。
87
- spawnParams: { offsetY: 'initialHeight' },
88
- debugAnchor: 'player',
89
- debugParams: [
90
- { key: 'lifetime', label: '生命周期', kind: 'lifetime', min: 0.2, max: 6, step: 0.01 },
91
- { key: 'scale', label: '整体缩放', kind: 'scale', min: 0.1, max: 5, step: 0.01 },
92
- { key: 'initialHeight', label: '初始高度', kind: 'number', min: -1, max: 3, step: 0.01 },
93
- { key: 'color', label: '金光颜色', kind: 'color' },
94
- { key: 'opacity', label: '金丝透明度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
95
- { key: 'strandCount', label: '金丝数量', kind: 'number', min: 0, max: 240, step: 1 },
96
- { key: 'strandLength', label: '金丝长度', kind: 'number', min: 0.05, max: 3, step: 0.01 },
97
- { key: 'strandHeight', label: '金丝上升高度', kind: 'number', min: 0.2, max: 5, step: 0.01 },
98
- { key: 'strandRadius', label: '金丝包围半径', kind: 'number', min: 0.05, max: 2, step: 0.01 },
99
- { key: 'strandWidth', label: '金丝粗细', kind: 'number', min: 0.005, max: 0.2, step: 0.001 },
100
- { key: 'riseSpeed', label: '金丝上升速度', kind: 'number', min: 0.05, max: 6, step: 0.01 },
101
- { key: 'ringCount', label: '亮环次数', kind: 'number', min: 0, max: 10, step: 1 },
102
- { key: 'ringMaxRadius', label: '亮环最大半径', kind: 'number', min: 0.1, max: 5, step: 0.01 },
103
- { key: 'ringThickness', label: '亮环粗细', kind: 'number', min: 0.005, max: 0.3, step: 0.001 },
104
- { key: 'ringInterval', label: '亮环间隔', kind: 'number', min: 0.02, max: 1.2, step: 0.01 },
105
- { key: 'ringOpacity', label: '亮环透明度', kind: 'opacity', min: 0, max: 1, step: 0.01 },
106
- { key: 'glowIntensity', label: '光芒强度', kind: 'number', min: 0, max: 3, step: 0.01 },
107
- { key: 'glowHeight', label: '光柱高度', kind: 'number', min: 0.2, max: 5, step: 0.01 },
108
- { key: 'glowWidth', label: '光柱宽度', kind: 'number', min: 0.1, max: 4, step: 0.01 },
109
- ],
110
- create({ scene, root, position, params }) {
111
- markVfxRoot(root);
112
- root.position.copyFrom(position); // 高度偏移由 service 经 spawnParams.offsetY 施加(存活)
113
- const strands = createStrandSystem(scene, root, params);
114
- const strandMeshes = createStrandMeshes(scene, root, params);
115
- const rings = createExpandingRings(scene, root, params);
116
- const glowAura = createGlowAura(scene, root, params);
117
- let disposed = false;
118
- const disposeTimer = window.setTimeout(() => disposeAll(), getDisposeDelaySeconds(params) * 1000);
119
-
120
- strands.start();
121
-
122
- return {
123
- root,
124
- dispose() {
125
- disposeAll();
126
- },
127
- };
128
-
129
- function disposeAll(): void {
130
- if (disposed) return;
131
- disposed = true;
132
- window.clearTimeout(disposeTimer);
133
- strands.stop();
134
- // dispose(false):金丝粒子贴图是按 scene 缓存的共享 DynamicTexture(strandTextureByScene),
135
- // ParticleSystem.dispose() 默认 disposeTexture=true 会销毁它,WeakMap 却仍持失效引用 →
136
- // 二次升级金丝空白。纹理生命周期绑 scene、跨播放复用,故不随实例销毁。
137
- strands.dispose(false);
138
- strandMeshes.dispose();
139
- rings.dispose();
140
- glowAura.dispose();
141
- cleanupPlanarShadowArtifacts(scene);
142
- root.dispose();
143
- }
144
- },
145
- };
146
-
147
- function markVfxRoot(root: unknown): void {
148
- const target = root as { metadata?: Record<string, unknown> | null };
149
- target.metadata = {
150
- ...(target.metadata ?? {}),
151
- disablePlanarShadow: true,
152
- disablePostOutlineDepth: true,
153
- };
154
- }
155
-
156
- function prepareVfxMesh(mesh: Mesh): void {
157
- mesh.isPickable = false;
158
- mesh.checkCollisions = false;
159
- mesh.receiveShadows = false;
160
- mesh.metadata = {
161
- ...((mesh.metadata as Record<string, unknown> | null) ?? {}),
162
- disablePlanarShadow: true,
163
- disablePostOutlineDepth: true,
164
- };
165
- }
166
-
167
- function cleanupPlanarShadowArtifacts(scene: Scene): void {
168
- for (const mesh of [...scene.meshes]) {
169
- if (mesh.name.startsWith('player-upgrade.') && mesh.name.includes('_planarShadow')) {
170
- mesh.dispose();
171
- }
172
- }
173
-
174
- for (const node of [...scene.transformNodes]) {
175
- if (node.name.startsWith('player-upgrade.') && node.name.includes('_shadow_root')) {
176
- node.dispose();
177
- }
178
- }
179
- }
180
-
181
- function createGlowAura(scene: Scene, root: { getAbsolutePosition(): Vector3 }, params: PlayerUpgradeParams): { dispose(): void } {
182
- const effectScale = Math.max(0.05, params.scale);
183
- const color = params.color;
184
- const glowHeight = Math.max(0.1, params.glowHeight) * effectScale;
185
- const glowWidth = Math.max(0.05, params.glowWidth) * effectScale;
186
- const glowIntensity = Math.max(0, params.glowIntensity);
187
- const meshes: Mesh[] = [];
188
- const materials: StandardMaterial[] = [];
189
-
190
- for (let index = 0; index < 3; index += 1) {
191
- const mesh = CreatePlane(`player-upgrade.soft-glow-column.${index}`, { size: 1 }, scene);
192
- prepareVfxMesh(mesh);
193
- mesh.parent = root as any;
194
- mesh.position.y = glowHeight * 0.48;
195
- mesh.rotation.y = (index * Math.PI) / 3;
196
- mesh.scaling.set(glowWidth, glowHeight, 1);
197
- mesh.renderingGroupId = VFX_RENDERING_GROUP_ID;
198
-
199
- const material = new StandardMaterial(`player-upgrade.soft-glow-column-material.${index}`, scene);
200
- configureTexturedGlowMaterial(material, color, getGlowTexture(scene), 2.8);
201
- material.alpha = 0;
202
- mesh.material = material;
203
-
204
- meshes.push(mesh);
205
- materials.push(material);
206
- }
207
-
208
- const halo = CreateDisc('player-upgrade.ground-halo', { radius: 1, tessellation: 96 }, scene);
209
- prepareVfxMesh(halo);
210
- halo.parent = root as any;
211
- halo.position.y = 0.025 * effectScale;
212
- halo.rotation.x = Math.PI / 2;
213
- halo.scaling.set(glowWidth * 1.12, glowWidth * 1.12, 1);
214
- halo.renderingGroupId = VFX_RENDERING_GROUP_ID;
215
-
216
- const haloMaterial = new StandardMaterial('player-upgrade.ground-halo-material', scene);
217
- configureTexturedGlowMaterial(haloMaterial, color, getHaloTexture(scene), 2.4);
218
- haloMaterial.alpha = 0;
219
- halo.material = haloMaterial;
220
- meshes.push(halo);
221
- materials.push(haloMaterial);
222
-
223
- let age = 0;
224
- let disposed = false;
225
- const observer = scene.onBeforeRenderObservable.add(() => {
226
- if (disposed) return;
227
- const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1000);
228
- age += deltaSeconds;
229
- const lifetime = Math.max(0.2, params.lifetime);
230
- const t = Math.min(1, age / lifetime);
231
- const fadeIn = Math.min(1, t / 0.12);
232
- const fadeOut = Math.max(0, 1 - Math.max(0, t - 0.72) / 0.28);
233
- const pulse = 0.86 + Math.sin(age * 13) * 0.1 + Math.sin(age * 23) * 0.04;
234
- const columnAlpha = Math.min(1, glowIntensity * params.opacity * 0.56 * fadeIn * fadeOut * pulse);
235
- const haloAlpha = Math.min(1, glowIntensity * params.ringOpacity * 0.68 * fadeIn * fadeOut);
236
-
237
- for (let index = 0; index < materials.length; index += 1) {
238
- materials[index].alpha = index === materials.length - 1 ? haloAlpha : columnAlpha;
239
- }
240
-
241
- const haloRadius = glowWidth * 1.12 * (1 + easeOutCubic(t) * 0.34);
242
- halo.scaling.set(haloRadius, haloRadius, 1);
243
-
244
- if (age >= lifetime + 0.35) dispose();
245
- });
246
-
247
- function dispose(): void {
248
- if (disposed) return;
249
- disposed = true;
250
- scene.onBeforeRenderObservable.remove(observer);
251
- for (const mesh of meshes) mesh.dispose();
252
- for (const material of materials) material.dispose();
253
- }
254
-
255
- return { dispose };
256
- }
257
-
258
- function createStrandSystem(scene: Scene, root: { getAbsolutePosition(): Vector3 }, params: PlayerUpgradeParams): ParticleSystem {
259
- const effectScale = Math.max(0.05, params.scale);
260
- const count = Math.max(0, Math.round(params.strandCount));
261
- const color = params.color;
262
- const bright = brighten(color, 0.72);
263
- const strandLength = Math.max(0.05, params.strandLength) * effectScale;
264
- const strandRadius = Math.max(0, params.strandRadius) * effectScale;
265
- const strandWidth = Math.max(0.001, params.strandWidth) * effectScale;
266
-
267
- const system = new ParticleSystem('player-upgrade.gold-strands', Math.max(1, count), scene);
268
- configureVfxParticleSystem(system);
269
- system.particleTexture = getStrandTexture(scene);
270
- system.particleTexture.hasAlpha = true;
271
- system.emitter = root as any;
272
- system.manualEmitCount = count;
273
- system.emitRate = count * 60;
274
- system.targetStopDuration = 0.05;
275
- system.disposeOnStop = false;
276
- system.blendMode = ParticleSystem.BLENDMODE_ADD;
277
- system.minLifeTime = Math.max(0.12, params.lifetime * 0.52);
278
- system.maxLifeTime = Math.max(system.minLifeTime + 0.01, params.lifetime * 0.95);
279
- system.minSize = Math.max(0.04, strandLength * 0.42);
280
- system.maxSize = Math.max(system.minSize, strandLength * 0.9);
281
- system.minScaleX = strandWidth;
282
- system.maxScaleX = strandWidth * 1.8;
283
- system.minScaleY = 1;
284
- system.maxScaleY = 1.6;
285
- system.minEmitPower = Math.max(0.01, params.riseSpeed * effectScale * 0.55);
286
- system.maxEmitPower = Math.max(system.minEmitPower, params.riseSpeed * effectScale * 1.28);
287
- system.gravity = new Vector3(0, 0.34 * effectScale, 0);
288
- system.updateSpeed = 1 / 60;
289
- system.color1 = toColor4(color, params.opacity * 0.72);
290
- system.color2 = toColor4(bright, params.opacity);
291
- system.colorDead = toColor4(color, 0);
292
- system.addColorGradient(0, toColor4(color, 0));
293
- system.addColorGradient(0.13, toColor4(bright, params.opacity));
294
- system.addColorGradient(0.72, toColor4(color, params.opacity * 0.58));
295
- system.addColorGradient(1, toColor4(color, 0));
296
- system.addVelocityGradient(0, 1);
297
- system.addVelocityGradient(0.66, 0.62);
298
- system.addVelocityGradient(1, 0.16);
299
-
300
- let positionIndex = 0;
301
- let directionIndex = 0;
302
- system.startPositionFunction = (worldMatrix, positionToUpdate, particle, isLocal) => {
303
- const index = particle.id + positionIndex;
304
- positionIndex += 1;
305
- const angle = sequence01(index, 0) * Math.PI * 2;
306
- const radius = Math.sqrt(sequence01(index, 1)) * strandRadius;
307
- const local = new Vector3(
308
- Math.cos(angle) * radius,
309
- sequence01(index, 2) * 0.08 * effectScale,
310
- Math.sin(angle) * radius,
311
- );
312
- if (isLocal) positionToUpdate.copyFrom(local);
313
- else Vector3.TransformCoordinatesToRef(local, worldMatrix, positionToUpdate);
314
- };
315
- system.startDirectionFunction = (worldMatrix, directionToUpdate, particle, isLocal) => {
316
- const index = particle.id + directionIndex;
317
- directionIndex += 1;
318
- const sway = strandRadius * 0.16;
319
- const local = new Vector3(
320
- (sequence01(index, 3) - 0.5) * sway,
321
- 0.86 + sequence01(index, 4) * 0.52,
322
- (sequence01(index, 5) - 0.5) * sway,
323
- );
324
- if (isLocal) directionToUpdate.copyFrom(local);
325
- else Vector3.TransformNormalToRef(local, worldMatrix, directionToUpdate);
326
- };
327
-
328
- return system;
329
- }
330
-
331
- function createStrandMeshes(scene: Scene, root: { getAbsolutePosition(): Vector3 }, params: PlayerUpgradeParams): { dispose(): void } {
332
- const effectScale = Math.max(0.05, params.scale);
333
- const count = Math.min(90, Math.max(0, Math.round(params.strandCount * 0.62)));
334
- const color = params.color;
335
- const radius = Math.max(0.04, params.strandRadius * effectScale);
336
- const strandLength = Math.max(0.05, params.strandLength * effectScale);
337
- const riseHeight = Math.max(0.1, params.strandHeight * effectScale);
338
- const width = Math.max(0.005, params.strandWidth * effectScale * 1.25);
339
- const speedScale = Math.max(0.2, params.riseSpeed / DEFAULT_PARAMS.riseSpeed);
340
- const duration = Math.max(0.22, params.lifetime * 0.72 / speedScale);
341
- const states: StrandMeshState[] = [];
342
-
343
- for (let index = 0; index < count; index += 1) {
344
- const angle = sequence01(index, 0) * Math.PI * 2;
345
- const localRadius = radius * lerp(0.42, 1.08, sequence01(index, 1));
346
- const mesh = CreateCylinder(
347
- `player-upgrade.gold-strand-mesh.${index}`,
348
- { height: 1, diameter: width, tessellation: 6 },
349
- scene,
350
- );
351
- prepareVfxMesh(mesh);
352
- mesh.parent = root as any;
353
- mesh.position.x = Math.cos(angle) * localRadius;
354
- mesh.position.z = Math.sin(angle) * localRadius;
355
- mesh.position.y = 0;
356
- mesh.renderingGroupId = VFX_RENDERING_GROUP_ID;
357
- mesh.isVisible = false;
358
-
359
- const material = new StandardMaterial(`player-upgrade.gold-strand-mesh-material.${index}`, scene);
360
- configureGlowMaterial(material, color, 2.8);
361
- material.alpha = 0;
362
- mesh.material = material;
363
-
364
- states.push({
365
- mesh,
366
- material,
367
- height: strandLength * lerp(0.68, 1.18, sequence01(index, 2)),
368
- startDelay: sequence01(index, 3) * Math.min(0.34, params.lifetime * 0.18),
369
- duration: duration * lerp(0.78, 1.12, sequence01(index, 4)),
370
- });
371
- }
372
-
373
- let age = 0;
374
- let disposed = false;
375
- const observer = scene.onBeforeRenderObservable.add(() => {
376
- if (disposed) return;
377
- const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1000);
378
- age += deltaSeconds;
379
- for (const state of states) {
380
- const localAge = age - state.startDelay;
381
- if (localAge < 0 || localAge > state.duration) {
382
- state.mesh.isVisible = false;
383
- state.material.alpha = 0;
384
- continue;
385
- }
386
- const t = Math.min(1, localAge / state.duration);
387
- const grow = Math.min(1, t / 0.32);
388
- const fadeOut = Math.max(0, 1 - Math.max(0, t - 0.66) / 0.34);
389
- const alpha = params.opacity * fadeOut * Math.min(1, t / 0.12);
390
- const currentHeight = state.height * grow;
391
- state.mesh.isVisible = alpha > 0.01;
392
- state.mesh.scaling.set(1, currentHeight, 1);
393
- state.mesh.position.y = currentHeight * 0.5 + riseHeight * easeOutCubic(t);
394
- state.material.alpha = Math.min(1, alpha * 1.35);
395
- }
396
- if (age >= params.lifetime + 0.45) dispose();
397
- });
398
-
399
- function dispose(): void {
400
- if (disposed) return;
401
- disposed = true;
402
- scene.onBeforeRenderObservable.remove(observer);
403
- for (const state of states) {
404
- state.mesh.dispose();
405
- state.material.dispose();
406
- }
407
- }
408
-
409
- return { dispose };
410
- }
411
-
412
- function createExpandingRings(scene: Scene, root: { getAbsolutePosition(): Vector3 }, params: PlayerUpgradeParams): { dispose(): void } {
413
- const effectScale = Math.max(0.05, params.scale);
414
- const ringCount = Math.max(0, Math.round(params.ringCount));
415
- const ringDuration = Math.max(0.18, Math.min(0.9, params.lifetime * 0.38));
416
- const minRadius = 0.14 * effectScale;
417
- const maxRadius = Math.max(minRadius + 0.01, params.ringMaxRadius * effectScale);
418
- const thickness = Math.max(0.002, params.ringThickness * effectScale);
419
- const color = params.color;
420
- const states: RingState[] = [];
421
-
422
- for (let index = 0; index < ringCount; index += 1) {
423
- const mesh = CreateTorus(
424
- `player-upgrade.expanding-ring.${index}`,
425
- { diameter: 1, thickness, tessellation: 96 },
426
- scene,
427
- );
428
- prepareVfxMesh(mesh);
429
- mesh.parent = root as any;
430
- mesh.position.y = 0.03 * effectScale + index * 0.012 * effectScale;
431
- mesh.renderingGroupId = VFX_RENDERING_GROUP_ID;
432
- mesh.isVisible = false;
433
-
434
- const material = new StandardMaterial(`player-upgrade.ring-material.${index}`, scene);
435
- configureGlowMaterial(material, color, 2.4);
436
- material.alpha = 0;
437
- mesh.material = material;
438
-
439
- states.push({
440
- mesh,
441
- material,
442
- startDelay: index * Math.max(0.02, params.ringInterval),
443
- duration: ringDuration,
444
- });
445
- }
446
-
447
- let age = 0;
448
- let disposed = false;
449
- const observer = scene.onBeforeRenderObservable.add(() => {
450
- if (disposed) return;
451
- const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1000);
452
- age += deltaSeconds;
453
- for (const state of states) {
454
- const localAge = age - state.startDelay;
455
- if (localAge < 0 || localAge > state.duration) {
456
- state.mesh.isVisible = false;
457
- state.material.alpha = 0;
458
- continue;
459
- }
460
- const t = Math.min(1, localAge / state.duration);
461
- const eased = easeOutCubic(t);
462
- const radius = lerp(minRadius, maxRadius, eased);
463
- const alpha = params.ringOpacity * (1 - t) * Math.min(1, t / 0.12);
464
- state.mesh.isVisible = alpha > 0.01;
465
- state.mesh.scaling.set(radius, radius, radius);
466
- const ringColor = brighten(color, 0.1 + 0.08 * (1 - t));
467
- state.material.diffuseColor = toColor3(ringColor);
468
- state.material.emissiveColor = toGlowColor3(ringColor, 3.4);
469
- state.material.alpha = Math.min(1, alpha * 1.45);
470
- }
471
- if (age >= getLastRingEndTime(params, ringDuration) + 0.1) dispose();
472
- });
473
-
474
- function dispose(): void {
475
- if (disposed) return;
476
- disposed = true;
477
- scene.onBeforeRenderObservable.remove(observer);
478
- for (const state of states) {
479
- state.mesh.dispose();
480
- state.material.dispose();
481
- }
482
- }
483
-
484
- return { dispose };
485
- }
486
-
487
- function getStrandTexture(scene: Scene): DynamicTexture {
488
- const existing = strandTextureByScene.get(scene);
489
- if (existing) return existing;
490
- const texture = new DynamicTexture('player_upgrade_gold_strand_texture', { width: 48, height: 192 }, scene, true);
491
- const context = texture.getContext();
492
- context.clearRect(0, 0, 48, 192);
493
- const glow = context.createLinearGradient(0, 0, 0, 192);
494
- glow.addColorStop(0, 'rgba(255,255,255,0)');
495
- glow.addColorStop(0.18, 'rgba(255,255,255,0.9)');
496
- glow.addColorStop(0.62, 'rgba(255,255,255,0.5)');
497
- glow.addColorStop(1, 'rgba(255,255,255,0)');
498
- context.fillStyle = glow;
499
- context.fillRect(19, 0, 10, 192);
500
- context.fillStyle = 'rgba(255,255,255,0.95)';
501
- context.fillRect(23, 8, 2, 168);
502
- texture.hasAlpha = true;
503
- texture.update(false);
504
- strandTextureByScene.set(scene, texture);
505
- return texture;
506
- }
507
-
508
- function getGlowTexture(scene: Scene): DynamicTexture {
509
- const existing = glowTextureByScene.get(scene);
510
- if (existing) return existing;
511
-
512
- const texture = new DynamicTexture('player_upgrade_soft_glow_texture', { width: 256, height: 512 }, scene, true);
513
- const context = texture.getContext();
514
- context.clearRect(0, 0, 256, 512);
515
-
516
- const vertical = context.createLinearGradient(0, 0, 0, 512);
517
- vertical.addColorStop(0, 'rgba(255,255,255,0)');
518
- vertical.addColorStop(0.16, 'rgba(255,255,255,0.28)');
519
- vertical.addColorStop(0.46, 'rgba(255,255,255,0.72)');
520
- vertical.addColorStop(0.78, 'rgba(255,255,255,0.22)');
521
- vertical.addColorStop(1, 'rgba(255,255,255,0)');
522
- context.fillStyle = vertical;
523
- context.fillRect(0, 0, 256, 512);
524
-
525
- const radial = context.createRadialGradient(128, 262, 6, 128, 262, 120);
526
- radial.addColorStop(0, 'rgba(255,255,255,1)');
527
- radial.addColorStop(0.18, 'rgba(255,255,255,0.76)');
528
- radial.addColorStop(0.48, 'rgba(255,255,255,0.22)');
529
- radial.addColorStop(1, 'rgba(255,255,255,0)');
530
- const compositeContext = context as unknown as CanvasRenderingContext2D;
531
- compositeContext.globalCompositeOperation = 'destination-in';
532
- context.fillStyle = radial;
533
- context.fillRect(0, 0, 256, 512);
534
- compositeContext.globalCompositeOperation = 'source-over';
535
-
536
- texture.hasAlpha = true;
537
- texture.update(false);
538
- glowTextureByScene.set(scene, texture);
539
- return texture;
540
- }
541
-
542
- function getHaloTexture(scene: Scene): DynamicTexture {
543
- const existing = haloTextureByScene.get(scene);
544
- if (existing) return existing;
545
-
546
- const texture = new DynamicTexture('player_upgrade_ground_halo_texture', { width: 256, height: 256 }, scene, true);
547
- const context = texture.getContext();
548
- context.clearRect(0, 0, 256, 256);
549
-
550
- const halo = context.createRadialGradient(128, 128, 18, 128, 128, 128);
551
- halo.addColorStop(0, 'rgba(255,255,255,0.74)');
552
- halo.addColorStop(0.34, 'rgba(255,255,255,0.42)');
553
- halo.addColorStop(0.58, 'rgba(255,255,255,0.16)');
554
- halo.addColorStop(0.76, 'rgba(255,255,255,0.04)');
555
- halo.addColorStop(1, 'rgba(255,255,255,0)');
556
- context.fillStyle = halo;
557
- context.fillRect(0, 0, 256, 256);
558
-
559
- texture.hasAlpha = true;
560
- texture.update(false);
561
- haloTextureByScene.set(scene, texture);
562
- return texture;
563
- }
564
-
565
- function getDisposeDelaySeconds(params: PlayerUpgradeParams): number {
566
- const ringDuration = Math.max(0.18, Math.min(0.9, params.lifetime * 0.38));
567
- return Math.max(0.2, params.lifetime) + getLastRingEndTime(params, ringDuration) + 0.35;
568
- }
569
-
570
- function getLastRingEndTime(params: PlayerUpgradeParams, ringDuration: number): number {
571
- return Math.max(0, Math.round(params.ringCount) - 1) * Math.max(0.02, params.ringInterval) + ringDuration;
572
- }
573
-
574
- function toColor4(color: VfxColorValue, alpha: number): Color4 {
575
- return new Color4(clamp01(color.r), clamp01(color.g), clamp01(color.b), clamp01(alpha));
576
- }
577
-
578
- function toColor3(color: VfxColorValue): Color3 {
579
- return new Color3(clamp01(color.r), clamp01(color.g), clamp01(color.b));
580
- }
581
-
582
- function toGlowColor3(color: VfxColorValue, intensity: number): Color3 {
583
- return new Color3(
584
- Math.max(0, color.r * intensity),
585
- Math.max(0, color.g * intensity),
586
- Math.max(0, color.b * intensity),
587
- );
588
- }
589
-
590
- function configureGlowMaterial(material: StandardMaterial, color: VfxColorValue, intensity: number): void {
591
- material.disableLighting = true;
592
- material.backFaceCulling = false;
593
- material.diffuseColor = toColor3(color);
594
- material.emissiveColor = toGlowColor3(color, intensity);
595
- material.specularColor = Color3.Black();
596
- material.alphaMode = Constants.ALPHA_ADD;
597
- material.transparencyMode = StandardMaterial.MATERIAL_ALPHABLEND;
598
- }
599
-
600
- function configureTexturedGlowMaterial(
601
- material: StandardMaterial,
602
- color: VfxColorValue,
603
- texture: DynamicTexture,
604
- intensity: number,
605
- ): void {
606
- configureGlowMaterial(material, color, intensity);
607
- material.diffuseTexture = texture;
608
- material.opacityTexture = texture;
609
- material.useAlphaFromDiffuseTexture = true;
610
- }
611
-
612
- function brighten(color: VfxColorValue, amount: number): VfxColorValue {
613
- return {
614
- r: lerp(color.r, 1, amount),
615
- g: lerp(color.g, 1, amount),
616
- b: lerp(color.b, 1, amount),
617
- };
618
- }
619
-
620
- function easeOutCubic(t: number): number {
621
- return 1 - (1 - t) ** 3;
622
- }
623
-
624
- function lerp(min: number, max: number, t: number): number {
625
- return min + (max - min) * t;
626
- }
627
-
628
- function clamp01(value: number): number {
629
- return Math.min(1, Math.max(0, value));
630
- }
631
-
632
- function fract(value: number): number {
633
- return value - Math.floor(value);
634
- }
635
-
636
- function sequence01(index: number, axis: number): number {
637
- if (index === 0) return 0.5;
638
- const strides = [0.618033988749895, 0.414213562373095, 0.732050807568877, 0.324717957244746, 0.754877666246693, 0.569840290998053];
639
- return fract(0.5 + index * strides[axis % strides.length] + axis * 0.173205080756888);
640
- }