@fps-games/vfx 0.1.1
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.
- package/CHANGELOG.md +34 -0
- package/dist/EffectPackageService.d.ts +26 -0
- package/dist/SceneVfxService.d.ts +27 -0
- package/dist/chunks/legacy-particle-runtime-CbJYVxdd.js +75 -0
- package/dist/chunks/manifestRuntimePackage-CXQFSTo2.js +356 -0
- package/dist/chunks/rendering-CV3nhygX.js +13 -0
- package/dist/chunks/space-shared-BXV1hc0k.js +124 -0
- package/dist/chunks/wood-sawdust-effect-factory-DlETNaBn.js +129 -0
- package/dist/effects/building-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/building-upgrade/index.d.ts +20 -0
- package/dist/effects/building-upgrade/index.js +337 -0
- package/dist/effects/character-entrance/effect.json.d.ts +9 -0
- package/dist/effects/character-entrance/index.d.ts +18 -0
- package/dist/effects/character-entrance/index.js +271 -0
- package/dist/effects/coin-burst/index.d.ts +6 -0
- package/dist/effects/coin-burst/index.js +45 -0
- package/dist/effects/comet-trail-flame/index.d.ts +11 -0
- package/dist/effects/comet-trail-flame/index.js +103 -0
- package/dist/effects/conveyor-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/conveyor-upgrade/index.d.ts +20 -0
- package/dist/effects/conveyor-upgrade/index.js +349 -0
- package/dist/effects/debris-smoke/index.d.ts +10 -0
- package/dist/effects/debris-smoke/index.js +108 -0
- package/dist/effects/door_open_gold_flakes/door_open_gold_flakes.json.d.ts +501 -0
- package/dist/effects/door_open_gold_flakes/index.d.ts +1 -0
- package/dist/effects/door_open_gold_flakes/index.js +524 -0
- package/dist/effects/electric-arc/index.d.ts +8 -0
- package/dist/effects/electric-arc/index.js +71 -0
- package/dist/effects/energy-shield/index.d.ts +46 -0
- package/dist/effects/energy-shield/index.js +365 -0
- package/dist/effects/explosion/index.d.ts +11 -0
- package/dist/effects/explosion/index.js +129 -0
- package/dist/effects/ground-tile-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/ground-tile-upgrade/index.d.ts +20 -0
- package/dist/effects/ground-tile-upgrade/index.js +357 -0
- package/dist/effects/hit-flash/index.d.ts +8 -0
- package/dist/effects/hit-flash/index.js +71 -0
- package/dist/effects/laser-beam/index.d.ts +1 -0
- package/dist/effects/laser-beam/index.js +152 -0
- package/dist/effects/laser-beam-factory.d.ts +12 -0
- package/dist/effects/lumber-cart-suction/effect.json.d.ts +9 -0
- package/dist/effects/lumber-cart-suction/index.d.ts +26 -0
- package/dist/effects/lumber-cart-suction/index.js +322 -0
- package/dist/effects/lumber-debris-scatter/effect.json.d.ts +231 -0
- package/dist/effects/lumber-debris-scatter/index.d.ts +20 -0
- package/dist/effects/lumber-debris-scatter/index.js +637 -0
- package/dist/effects/lumber_vehicle_gear_spin/index.d.ts +1 -0
- package/dist/effects/lumber_vehicle_gear_spin/index.js +363 -0
- package/dist/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json.d.ts +341 -0
- package/dist/effects/lumber_vehicle_upgrade_aura/index.d.ts +1 -0
- package/dist/effects/lumber_vehicle_upgrade_aura/index.js +391 -0
- package/dist/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json.d.ts +368 -0
- package/dist/effects/lumber_vehicle_wood_chips/index.d.ts +1 -0
- package/dist/effects/lumber_vehicle_wood_chips/index.js +360 -0
- package/dist/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json.d.ts +338 -0
- package/dist/effects/monster-hit/index.d.ts +15 -0
- package/dist/effects/monster-hit/index.js +156 -0
- package/dist/effects/player-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/player-upgrade/index.d.ts +24 -0
- package/dist/effects/player-upgrade/index.js +539 -0
- package/dist/effects/pulse-laser-volley/index.d.ts +17 -0
- package/dist/effects/pulse-laser-volley/index.js +173 -0
- package/dist/effects/resource-collect-sparkles/effect.json.d.ts +9 -0
- package/dist/effects/resource-collect-sparkles/index.d.ts +21 -0
- package/dist/effects/resource-collect-sparkles/index.js +222 -0
- package/dist/effects/run-footstep-dust/effect.json.d.ts +186 -0
- package/dist/effects/run-footstep-dust/index.d.ts +23 -0
- package/dist/effects/run-footstep-dust/index.js +343 -0
- package/dist/effects/space-shared.d.ts +44 -0
- package/dist/effects/thruster-flame/index.d.ts +15 -0
- package/dist/effects/thruster-flame/index.js +301 -0
- package/dist/effects/tree-chop-dust/effect.json.d.ts +11 -0
- package/dist/effects/tree-chop-dust/index.d.ts +17 -0
- package/dist/effects/tree-chop-dust/index.js +165 -0
- package/dist/effects/tree-leaf-chop-burst/index.d.ts +19 -0
- package/dist/effects/tree-leaf-chop-burst/index.js +219 -0
- package/dist/effects/tree_chop_dust_burst/index.d.ts +1 -0
- package/dist/effects/tree_chop_dust_burst/index.js +443 -0
- package/dist/effects/tree_chop_dust_burst/tree_chop_dust_burst.json.d.ts +415 -0
- package/dist/effects/ufo-thread-flame/index.d.ts +21 -0
- package/dist/effects/ufo-thread-flame/index.js +140 -0
- package/dist/effects/vehicle-exhaust-smoke/effect.json.d.ts +11 -0
- package/dist/effects/vehicle-exhaust-smoke/index.d.ts +19 -0
- package/dist/effects/vehicle-exhaust-smoke/index.js +242 -0
- package/dist/effects/vehicle-upgrade/effect.json.d.ts +9 -0
- package/dist/effects/vehicle-upgrade/index.d.ts +20 -0
- package/dist/effects/vehicle-upgrade/index.js +349 -0
- package/dist/effects/weapon-trail/index.d.ts +26 -0
- package/dist/effects/weapon-trail/index.js +351 -0
- package/dist/effects/wood-crusher-sawdust/index.d.ts +2 -0
- package/dist/effects/wood-crusher-sawdust/index.js +648 -0
- package/dist/effects/wood-crusher-sawdust/wood_crusher_sawdust.json.d.ts +595 -0
- package/dist/effects/wood-cutter-sawdust/index.d.ts +2 -0
- package/dist/effects/wood-cutter-sawdust/index.js +648 -0
- package/dist/effects/wood-cutter-sawdust/wood_cutter_sawdust.json.d.ts +595 -0
- package/dist/effects/wood-sawdust-effect-factory.d.ts +36 -0
- package/dist/effects/wood_crusher_sawdust/index.d.ts +16 -0
- package/dist/effects/wood_crusher_sawdust/index.js +634 -0
- package/dist/effects/wood_crusher_sawdust/wood_crusher_sawdust.json.d.ts +595 -0
- package/dist/effects/wood_cutter_sawdust/index.d.ts +16 -0
- package/dist/effects/wood_cutter_sawdust/index.js +634 -0
- package/dist/effects/wood_cutter_sawdust/wood_cutter_sawdust.json.d.ts +595 -0
- package/dist/effects/wood_peel_material_test/index.d.ts +1 -0
- package/dist/effects/wood_peel_material_test/index.js +157 -0
- package/dist/effects/wood_peel_material_test/wood_peel_material_test.json.d.ts +139 -0
- package/dist/generation.d.ts +7 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +309 -0
- package/dist/legacy-particle-runtime.d.ts +30 -0
- package/dist/manifestRuntimePackage.d.ts +68 -0
- package/dist/registry.d.ts +20 -0
- package/dist/rendering.d.ts +5 -0
- package/dist/types.d.ts +83 -0
- package/docs/AUTHORING_EFFECTS.md +297 -0
- package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +1580 -0
- package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +229 -0
- package/docs/VFX_LIBRARY_PLAN.md +546 -0
- package/docs/vfx-ab/RESULTS.md +35 -0
- package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/after.png +0 -0
- package/docs/vfx-ab/lumber-order/vehicle-exhaust-smoke/before.png +0 -0
- package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/after.png +0 -0
- package/docs/vfx-ab/lumber-truck/vehicle-exhaust-smoke/before.png +0 -0
- package/docs/vfx-integration_chatgpt.md +462 -0
- package/docs/weapon-trail-visualization.html +241 -0
- package/index.json +381 -0
- package/package.json +51 -0
- package/packages/EffectPackageService.ts +240 -0
- package/packages/SceneVfxService.ts +96 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +333 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +25 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +11 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/textures/effect_jianbian.png +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/effect.json +927 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/contact-sheet.png +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.gif +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.mp4 +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/preview.webm +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/media/thumbnail.png +0 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/metadata/description.json +197 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +895 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +241 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +542 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +69 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +125 -0
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +44 -0
- package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +210 -0
- package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
- package/packages/build.particle.golden_upgrade_starburst/effect.json +880 -0
- package/packages/build.particle.golden_upgrade_starburst/media/contact-sheet.png +0 -0
- package/packages/build.particle.golden_upgrade_starburst/media/preview.gif +0 -0
- package/packages/build.particle.golden_upgrade_starburst/media/preview.mp4 +0 -0
- package/packages/build.particle.golden_upgrade_starburst/media/preview.webm +0 -0
- package/packages/build.particle.golden_upgrade_starburst/media/thumbnail.png +0 -0
- package/packages/build.particle.golden_upgrade_starburst/metadata/description.json +161 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +762 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +260 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +436 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +40 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +115 -0
- package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +40 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +210 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/assets/textures/b5b27ab1-e740-4398-b407-848fc2b2c897.png +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/effect.json +887 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.gif +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.mp4 +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/media/preview.webm +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/media/thumbnail.png +0 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/metadata/description.json +179 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +859 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +260 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +478 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +40 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +114 -0
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +41 -0
- package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +210 -0
- package/packages/build.particle.wood_chip_dust_burst/assets/textures/effect_yanwu4.png +0 -0
- package/packages/build.particle.wood_chip_dust_burst/assets/textures/suipian3.png +0 -0
- package/packages/build.particle.wood_chip_dust_burst/effect.json +1400 -0
- package/packages/build.particle.wood_chip_dust_burst/media/contact-sheet.png +0 -0
- package/packages/build.particle.wood_chip_dust_burst/media/preview.gif +0 -0
- package/packages/build.particle.wood_chip_dust_burst/media/preview.mp4 +0 -0
- package/packages/build.particle.wood_chip_dust_burst/media/preview.webm +0 -0
- package/packages/build.particle.wood_chip_dust_burst/media/thumbnail.png +0 -0
- package/packages/build.particle.wood_chip_dust_burst/metadata/description.json +173 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +1277 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +329 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +749 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +60 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +146 -0
- package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +69 -0
- package/packages/effects/building-upgrade/effect.json +6 -0
- package/packages/effects/building-upgrade/index.ts +387 -0
- package/packages/effects/building-upgrade/vfx-params.json +24 -0
- package/packages/effects/character-entrance/effect.json +6 -0
- package/packages/effects/character-entrance/index.ts +308 -0
- package/packages/effects/character-entrance/vfx-params.json +24 -0
- package/packages/effects/coin-burst/index.ts +43 -0
- package/packages/effects/coin-burst/vfx-params.json +5 -0
- package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
- package/packages/effects/comet-trail-flame/index.ts +106 -0
- package/packages/effects/comet-trail-flame/vfx-params.json +5 -0
- package/packages/effects/conveyor-upgrade/effect.json +6 -0
- package/packages/effects/conveyor-upgrade/index.ts +401 -0
- package/packages/effects/conveyor-upgrade/vfx-params.json +21 -0
- package/packages/effects/debris-smoke/assets/models/rock_debris.glb +0 -0
- package/packages/effects/debris-smoke/assets/textures/smoke22.webp +0 -0
- package/packages/effects/debris-smoke/index.ts +101 -0
- package/packages/effects/debris-smoke/vfx-params.json +5 -0
- package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +397 -0
- package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +498 -0
- package/packages/effects/door_open_gold_flakes/index.ts +11 -0
- package/packages/effects/door_open_gold_flakes/vfx-params.json +23 -0
- package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
- package/packages/effects/electric-arc/index.ts +62 -0
- package/packages/effects/electric-arc/vfx-params.json +5 -0
- package/packages/effects/energy-shield/effect.json +7 -0
- package/packages/effects/energy-shield/index.ts +431 -0
- package/packages/effects/energy-shield/vfx-params.json +29 -0
- package/packages/effects/explosion/assets/textures/baozha29.webp +0 -0
- package/packages/effects/explosion/assets/textures/glow01.webp +0 -0
- package/packages/effects/explosion/assets/textures/lizi01.webp +0 -0
- package/packages/effects/explosion/assets/textures/xulie_lizibaozha02_5x5.webp +0 -0
- package/packages/effects/explosion/index.ts +114 -0
- package/packages/effects/explosion/vfx-params.json +5 -0
- package/packages/effects/ground-tile-upgrade/effect.json +6 -0
- package/packages/effects/ground-tile-upgrade/index.ts +410 -0
- package/packages/effects/ground-tile-upgrade/vfx-params.json +21 -0
- package/packages/effects/hit-flash/index.ts +69 -0
- package/packages/effects/hit-flash/vfx-params.json +5 -0
- package/packages/effects/laser-beam/assets/textures/laser_glow.webp +0 -0
- package/packages/effects/laser-beam/assets/textures/laser_noise.webp +0 -0
- package/packages/effects/laser-beam/index.ts +6 -0
- package/packages/effects/laser-beam/vfx-params.json +5 -0
- package/packages/effects/laser-beam-factory.ts +135 -0
- package/packages/effects/lumber-cart-suction/effect.json +6 -0
- package/packages/effects/lumber-cart-suction/index.ts +399 -0
- package/packages/effects/lumber-cart-suction/vfx-params.json +30 -0
- package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb +0 -0
- package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/.active +1 -0
- package/packages/effects/lumber-debris-scatter/assets/models/lumber_prop_model.glb.versions/1781589063890_upload.glb +0 -0
- package/packages/effects/lumber-debris-scatter/assets/runtime/solidParticleScatter.v1.js +236 -0
- package/packages/effects/lumber-debris-scatter/effect.json +228 -0
- package/packages/effects/lumber-debris-scatter/index.ts +780 -0
- package/packages/effects/lumber-debris-scatter/vfx-params.json +19 -0
- package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +202 -0
- package/packages/effects/lumber_vehicle_gear_spin/index.ts +11 -0
- package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +338 -0
- package/packages/effects/lumber_vehicle_gear_spin/vfx-params.json +21 -0
- package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +353 -0
- package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +11 -0
- package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +365 -0
- package/packages/effects/lumber_vehicle_upgrade_aura/vfx-params.json +15 -0
- package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +310 -0
- package/packages/effects/lumber_vehicle_wood_chips/index.ts +11 -0
- package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +335 -0
- package/packages/effects/lumber_vehicle_wood_chips/vfx-params.json +11 -0
- package/packages/effects/monster-hit/index.ts +128 -0
- package/packages/effects/monster-hit/vfx-params.json +5 -0
- package/packages/effects/player-upgrade/effect.json +6 -0
- package/packages/effects/player-upgrade/index.ts +635 -0
- package/packages/effects/player-upgrade/vfx-params.json +28 -0
- package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
- package/packages/effects/pulse-laser-volley/index.ts +204 -0
- package/packages/effects/pulse-laser-volley/vfx-params.json +5 -0
- package/packages/effects/resource-collect-sparkles/effect.json +6 -0
- package/packages/effects/resource-collect-sparkles/index.ts +254 -0
- package/packages/effects/resource-collect-sparkles/vfx-params.json +25 -0
- package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +215 -0
- package/packages/effects/run-footstep-dust/effect.json +183 -0
- package/packages/effects/run-footstep-dust/index.ts +377 -0
- package/packages/effects/run-footstep-dust/vfx-params.json +27 -0
- package/packages/effects/space-shared.ts +120 -0
- package/packages/effects/thruster-flame/index.ts +305 -0
- package/packages/effects/thruster-flame/vfx-params.json +5 -0
- package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
- package/packages/effects/tree-chop-dust/effect.json +8 -0
- package/packages/effects/tree-chop-dust/index.ts +202 -0
- package/packages/effects/tree-chop-dust/vfx-params.json +21 -0
- package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +303 -0
- package/packages/effects/tree-leaf-chop-burst/assets/textures/tree_leaf_chop_burst_leaf_atlas.png +0 -0
- package/packages/effects/tree-leaf-chop-burst/effect.json +498 -0
- package/packages/effects/tree-leaf-chop-burst/index.ts +294 -0
- package/packages/effects/tree-leaf-chop-burst/vfx-params.json +27 -0
- package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +318 -0
- package/packages/effects/tree_chop_dust_burst/assets/textures/tree_chop_dust_burst_dust.png +0 -0
- package/packages/effects/tree_chop_dust_burst/index.ts +13 -0
- package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +412 -0
- package/packages/effects/tree_chop_dust_burst/vfx-params.json +9 -0
- package/packages/effects/ufo-thread-flame/assets/textures/flame_flow.webp +0 -0
- package/packages/effects/ufo-thread-flame/assets/textures/flame_spike.webp +0 -0
- package/packages/effects/ufo-thread-flame/index.ts +152 -0
- package/packages/effects/ufo-thread-flame/vfx-params.json +5 -0
- package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
- package/packages/effects/vehicle-exhaust-smoke/effect.json +8 -0
- package/packages/effects/vehicle-exhaust-smoke/index.ts +298 -0
- package/packages/effects/vehicle-exhaust-smoke/vfx-params.json +23 -0
- package/packages/effects/vehicle-upgrade/effect.json +6 -0
- package/packages/effects/vehicle-upgrade/index.ts +401 -0
- package/packages/effects/vehicle-upgrade/vfx-params.json +21 -0
- package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
- package/packages/effects/weapon-trail/index.ts +313 -0
- package/packages/effects/weapon-trail/vfx-params.json +5 -0
- package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +312 -0
- package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
- package/packages/effects/wood-crusher-sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
- package/packages/effects/wood-crusher-sawdust/index.ts +43 -0
- package/packages/effects/wood-crusher-sawdust/vfx-params.json +24 -0
- package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +592 -0
- package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +312 -0
- package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
- package/packages/effects/wood-cutter-sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
- package/packages/effects/wood-cutter-sawdust/index.ts +43 -0
- package/packages/effects/wood-cutter-sawdust/vfx-params.json +24 -0
- package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +592 -0
- package/packages/effects/wood-sawdust-effect-factory.ts +194 -0
- package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +318 -0
- package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_dust.png +0 -0
- package/packages/effects/wood_crusher_sawdust/assets/textures/wood_crusher_sawdust_fiber.png +0 -0
- package/packages/effects/wood_crusher_sawdust/index.ts +29 -0
- package/packages/effects/wood_crusher_sawdust/vfx-params.json +14 -0
- package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +592 -0
- package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +318 -0
- package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_chip.png +0 -0
- package/packages/effects/wood_cutter_sawdust/assets/textures/wood_cutter_sawdust_dust.png +0 -0
- package/packages/effects/wood_cutter_sawdust/index.ts +29 -0
- package/packages/effects/wood_cutter_sawdust/vfx-params.json +14 -0
- package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +592 -0
- package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +196 -0
- package/packages/effects/wood_peel_material_test/index.ts +11 -0
- package/packages/effects/wood_peel_material_test/vfx-params.json +9 -0
- package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +136 -0
- package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +210 -0
- package/packages/env.particle.forest_edge_fog/assets/textures/f12a23c4-b924-4322-a260-3d982428f1e8.png +0 -0
- package/packages/env.particle.forest_edge_fog/assets/textures/yuan.png +0 -0
- package/packages/env.particle.forest_edge_fog/effect.json +854 -0
- package/packages/env.particle.forest_edge_fog/media/preview.gif +0 -0
- package/packages/env.particle.forest_edge_fog/media/preview.mp4 +0 -0
- package/packages/env.particle.forest_edge_fog/media/preview.webm +0 -0
- package/packages/env.particle.forest_edge_fog/media/thumbnail.png +0 -0
- package/packages/env.particle.forest_edge_fog/metadata/description.json +148 -0
- package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +827 -0
- package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +196 -0
- package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +432 -0
- package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +28 -0
- package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +124 -0
- package/packages/env.particle.forest_edge_fog/provenance/lineage.json +41 -0
- package/packages/generation.ts +14 -0
- package/packages/index.ts +14 -0
- package/packages/legacy-particle-runtime.ts +113 -0
- package/packages/manifestRuntimePackage.ts +519 -0
- package/packages/registry.ts +85 -0
- package/packages/rendering.ts +13 -0
- package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +424 -0
- package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
- package/packages/resource.particle.viscous_oil_suction/effect.json +1254 -0
- package/packages/resource.particle.viscous_oil_suction/media/preview.gif +0 -0
- package/packages/resource.particle.viscous_oil_suction/media/preview.mp4 +0 -0
- package/packages/resource.particle.viscous_oil_suction/media/preview.webm +0 -0
- package/packages/resource.particle.viscous_oil_suction/media/thumbnail.png +0 -0
- package/packages/resource.particle.viscous_oil_suction/metadata/description.json +122 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +1051 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +200 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +581 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +28 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +111 -0
- package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +45 -0
- package/packages/types.ts +107 -0
- package/tooling/check-dist-runtime.mjs +166 -0
- package/tooling/generate-index.mjs +55 -0
- package/tooling/test-guardrails.mjs +157 -0
- package/tooling/validate-boundary.mjs +92 -0
- package/tooling/validate-effects.mjs +304 -0
- package/tooling/validate.mjs +53 -0
- package/tooling/vfx-cli.mjs +232 -0
- package/tooling/vfx-package-resolution.mjs +28 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
|
|
2
|
+
import { Mesh } from "@babylonjs/core/Meshes/mesh";
|
|
3
|
+
import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData";
|
|
4
|
+
import { CreatePlane } from "@babylonjs/core/Meshes/Builders/planeBuilder";
|
|
5
|
+
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
|
|
6
|
+
import { Texture } from "@babylonjs/core/Materials/Textures/texture";
|
|
7
|
+
import { Color3 } from "@babylonjs/core/Maths/math.color";
|
|
8
|
+
import { Constants } from "@babylonjs/core/Engines/constants";
|
|
9
|
+
import { L as LIFETIME_DEBUG_PARAMS, a as LIFETIME_DEFAULTS, b as makeFlareTexture, s as scheduleLifetime } from "../../chunks/space-shared-BXV1hc0k.js";
|
|
10
|
+
const arcTextureUrl = "data:image/webp;base64,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";
|
|
11
|
+
const noiseTextureUrl = "data:image/webp;base64,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";
|
|
12
|
+
function createBeamPlaneGeo(name, width, axis, scene) {
|
|
13
|
+
const h = width / 2;
|
|
14
|
+
const positions = axis === "x" ? [-h, 0, 0, h, 0, 0, h, 0, 1, -h, 0, 1] : [0, -h, 0, 0, h, 0, 0, h, 1, 0, -h, 1];
|
|
15
|
+
const normals = axis === "x" ? [0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0] : [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0];
|
|
16
|
+
const uvs = [0, 0, 0, 1, 1, 1, 1, 0];
|
|
17
|
+
const indices = [0, 1, 2, 0, 2, 3];
|
|
18
|
+
const mesh = new Mesh(name, scene);
|
|
19
|
+
const vd = new VertexData();
|
|
20
|
+
vd.positions = positions;
|
|
21
|
+
vd.normals = normals;
|
|
22
|
+
vd.uvs = uvs;
|
|
23
|
+
vd.indices = indices;
|
|
24
|
+
vd.applyToMesh(mesh);
|
|
25
|
+
return mesh;
|
|
26
|
+
}
|
|
27
|
+
function createLaserBeamEffectPackage(id, nameZh, core) {
|
|
28
|
+
const defaultParams = { ...LIFETIME_DEFAULTS, ...core };
|
|
29
|
+
return {
|
|
30
|
+
id,
|
|
31
|
+
nameZh,
|
|
32
|
+
defaultParams,
|
|
33
|
+
debugAnchor: "playerRight",
|
|
34
|
+
debugParams: [
|
|
35
|
+
...LIFETIME_DEBUG_PARAMS,
|
|
36
|
+
{ key: "width", label: "束宽", kind: "scale", min: 0.05, max: 2, step: 0.01 },
|
|
37
|
+
{ key: "intensity", label: "强度", kind: "number", min: 0.1, max: 3, step: 0.05 },
|
|
38
|
+
{ key: "laserSpeed", label: "纹理流速", kind: "number", min: 0, max: 20, step: 0.5 },
|
|
39
|
+
{ key: "targetDistance", label: "目标距离", kind: "number", min: 2, max: 40, step: 0.5 }
|
|
40
|
+
],
|
|
41
|
+
create({ scene, root, position, rotationY, params }) {
|
|
42
|
+
root.position.copyFrom(position);
|
|
43
|
+
root.rotation.y = rotationY;
|
|
44
|
+
const { width, intensity } = params;
|
|
45
|
+
const segLen = width * 5;
|
|
46
|
+
const arcTex = new Texture(arcTextureUrl, scene);
|
|
47
|
+
arcTex.wrapU = Texture.WRAP_ADDRESSMODE;
|
|
48
|
+
const arcMat = new StandardMaterial("vfx_laser_arcMat", scene);
|
|
49
|
+
arcMat.emissiveTexture = arcTex;
|
|
50
|
+
arcMat.opacityTexture = arcTex;
|
|
51
|
+
arcMat.emissiveColor = new Color3(0.45 * intensity, 0.62 * intensity, 1.35 * intensity);
|
|
52
|
+
arcMat.disableLighting = true;
|
|
53
|
+
arcMat.backFaceCulling = false;
|
|
54
|
+
arcMat.alphaMode = Constants.ALPHA_ADD;
|
|
55
|
+
const noiseTex = new Texture(noiseTextureUrl, scene);
|
|
56
|
+
noiseTex.wrapU = Texture.WRAP_ADDRESSMODE;
|
|
57
|
+
const noiseMat = new StandardMaterial("vfx_laser_noiseMat", scene);
|
|
58
|
+
noiseMat.emissiveTexture = noiseTex;
|
|
59
|
+
noiseMat.opacityTexture = noiseTex;
|
|
60
|
+
noiseMat.opacityTexture.getAlphaFromRGB = true;
|
|
61
|
+
noiseMat.emissiveColor = new Color3(0.2 * intensity, 0.35 * intensity, 0.9 * intensity);
|
|
62
|
+
noiseMat.disableLighting = true;
|
|
63
|
+
noiseMat.backFaceCulling = false;
|
|
64
|
+
noiseMat.alphaMode = Constants.ALPHA_ADD;
|
|
65
|
+
const beamRoot = new TransformNode("vfx_laser_beamRoot", scene);
|
|
66
|
+
beamRoot.parent = root;
|
|
67
|
+
const planes = [];
|
|
68
|
+
const layout = [
|
|
69
|
+
["x", arcMat, width],
|
|
70
|
+
["y", arcMat, width],
|
|
71
|
+
["x", noiseMat, width * 1.9],
|
|
72
|
+
["y", noiseMat, width * 1.9]
|
|
73
|
+
];
|
|
74
|
+
for (const [axis, mat, w] of layout) {
|
|
75
|
+
const p = createBeamPlaneGeo(`vfx_laser_p${planes.length}`, w, axis, scene);
|
|
76
|
+
p.material = mat;
|
|
77
|
+
p.parent = beamRoot;
|
|
78
|
+
p.isPickable = false;
|
|
79
|
+
planes.push(p);
|
|
80
|
+
}
|
|
81
|
+
const flareTex = makeFlareTexture(scene, "vfx_laser_flare");
|
|
82
|
+
function makeFlare(name, size) {
|
|
83
|
+
const f = CreatePlane(name, { size }, scene);
|
|
84
|
+
f.billboardMode = Mesh.BILLBOARDMODE_ALL;
|
|
85
|
+
const m = new StandardMaterial(name + "Mat", scene);
|
|
86
|
+
m.emissiveTexture = flareTex;
|
|
87
|
+
m.opacityTexture = flareTex;
|
|
88
|
+
m.emissiveColor = new Color3(0.7, 0.85, 1.6);
|
|
89
|
+
m.disableLighting = true;
|
|
90
|
+
m.alphaMode = Constants.ALPHA_ADD;
|
|
91
|
+
f.material = m;
|
|
92
|
+
f.isPickable = false;
|
|
93
|
+
f.parent = root;
|
|
94
|
+
return f;
|
|
95
|
+
}
|
|
96
|
+
const muzzleFlare = makeFlare("vfx_laser_muzzle", width * 3.2);
|
|
97
|
+
const hitFlare = makeFlare("vfx_laser_hit", width * 3.2);
|
|
98
|
+
let time = 0;
|
|
99
|
+
const observer = scene.onBeforeRenderObservable.add(() => {
|
|
100
|
+
const dt = Math.min(scene.getEngine().getDeltaTime() / 1e3, 0.05);
|
|
101
|
+
time += dt;
|
|
102
|
+
const dist = params.targetDistance;
|
|
103
|
+
beamRoot.scaling.z = dist;
|
|
104
|
+
const tiles = Math.max(1, dist / segLen);
|
|
105
|
+
arcMat.emissiveTexture.uScale = tiles;
|
|
106
|
+
arcMat.opacityTexture.uScale = tiles;
|
|
107
|
+
arcMat.emissiveTexture.uOffset -= params.laserSpeed * dt;
|
|
108
|
+
arcMat.opacityTexture.uOffset = arcMat.emissiveTexture.uOffset;
|
|
109
|
+
noiseMat.emissiveTexture.uScale = tiles * 0.6;
|
|
110
|
+
noiseMat.emissiveTexture.uOffset -= params.laserSpeed * 0.31 * dt;
|
|
111
|
+
noiseMat.opacityTexture.uScale = tiles * 0.6;
|
|
112
|
+
noiseMat.opacityTexture.uOffset = noiseMat.emissiveTexture.uOffset;
|
|
113
|
+
const pulse = 1 + Math.sin(time * 24) * 0.18;
|
|
114
|
+
muzzleFlare.position.set(0, 0, 0);
|
|
115
|
+
muzzleFlare.scaling.setAll(pulse);
|
|
116
|
+
hitFlare.position.set(0, 0, dist);
|
|
117
|
+
hitFlare.scaling.setAll(pulse * 1.4);
|
|
118
|
+
});
|
|
119
|
+
let disposed = false;
|
|
120
|
+
let ltTimer = 0;
|
|
121
|
+
const dispose = () => {
|
|
122
|
+
if (disposed) return;
|
|
123
|
+
disposed = true;
|
|
124
|
+
if (ltTimer) window.clearTimeout(ltTimer);
|
|
125
|
+
scene.onBeforeRenderObservable.remove(observer);
|
|
126
|
+
for (const p of planes) p.dispose();
|
|
127
|
+
muzzleFlare.material?.dispose();
|
|
128
|
+
muzzleFlare.dispose();
|
|
129
|
+
hitFlare.material?.dispose();
|
|
130
|
+
hitFlare.dispose();
|
|
131
|
+
beamRoot.dispose();
|
|
132
|
+
arcMat.dispose();
|
|
133
|
+
arcTex.dispose();
|
|
134
|
+
noiseMat.dispose();
|
|
135
|
+
noiseTex.dispose();
|
|
136
|
+
flareTex.dispose();
|
|
137
|
+
root.dispose();
|
|
138
|
+
};
|
|
139
|
+
ltTimer = scheduleLifetime(params, dispose);
|
|
140
|
+
return { root, dispose };
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const laserBeamEffectPackage = createLaserBeamEffectPackage("laser-beam", "激光束", {
|
|
145
|
+
width: 0.55,
|
|
146
|
+
intensity: 1,
|
|
147
|
+
laserSpeed: 7,
|
|
148
|
+
targetDistance: 12
|
|
149
|
+
});
|
|
150
|
+
export {
|
|
151
|
+
laserBeamEffectPackage
|
|
152
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { VfxEffectPackage, VfxParamValues } from '../types';
|
|
2
|
+
export interface LaserBeamParams extends VfxParamValues {
|
|
3
|
+
lifetimeMode: string;
|
|
4
|
+
lifetime: number;
|
|
5
|
+
width: number;
|
|
6
|
+
intensity: number;
|
|
7
|
+
laserSpeed: number;
|
|
8
|
+
targetDistance: number;
|
|
9
|
+
}
|
|
10
|
+
type LaserCoreDefaults = Omit<LaserBeamParams, 'lifetimeMode' | 'lifetime'>;
|
|
11
|
+
export declare function createLaserBeamEffectPackage(id: string, nameZh: string, core: LaserCoreDefaults): VfxEffectPackage<LaserBeamParams>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
|
|
2
|
+
interface LumberCartSuctionParams extends VfxParamValues {
|
|
3
|
+
lifetime: number;
|
|
4
|
+
scale: number;
|
|
5
|
+
initialHeight: number;
|
|
6
|
+
color: VfxColorValue;
|
|
7
|
+
opacity: number;
|
|
8
|
+
ringCount: number;
|
|
9
|
+
forwardOffset: number;
|
|
10
|
+
suctionLength: number;
|
|
11
|
+
startRadius: number;
|
|
12
|
+
endRadius: number;
|
|
13
|
+
ringWidth: number;
|
|
14
|
+
suctionSpeed: number;
|
|
15
|
+
pulse: number;
|
|
16
|
+
flyingParticleCount: number;
|
|
17
|
+
flyingParticleSize: number;
|
|
18
|
+
flyingParticleSpeed: number;
|
|
19
|
+
flyingParticleDrift: number;
|
|
20
|
+
flyingParticleOuterOffset: number;
|
|
21
|
+
flyingParticleOpacity: number;
|
|
22
|
+
directionX: number;
|
|
23
|
+
directionZ: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const lumberCartSuctionEffectPackage: VfxEffectPackage<LumberCartSuctionParams>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,322 @@
|
|
|
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 { CreateTube } from "@babylonjs/core/Meshes/Builders/tubeBuilder";
|
|
7
|
+
import { ParticleSystem } from "@babylonjs/core/Particles/particleSystem";
|
|
8
|
+
const id = "lumber-cart-suction";
|
|
9
|
+
const nameZh = "收集车吸入圆环";
|
|
10
|
+
const assets = [];
|
|
11
|
+
const source = "procedural";
|
|
12
|
+
const manifest = {
|
|
13
|
+
id,
|
|
14
|
+
nameZh,
|
|
15
|
+
assets,
|
|
16
|
+
source
|
|
17
|
+
};
|
|
18
|
+
const LUMBER_CART_SUCTION_RENDERING_GROUP_ID = 0;
|
|
19
|
+
const DEFAULT_PARAMS = {
|
|
20
|
+
lifetime: 1.8,
|
|
21
|
+
scale: 1,
|
|
22
|
+
initialHeight: 0.18,
|
|
23
|
+
color: { r: 1, g: 0.86, b: 0.42 },
|
|
24
|
+
opacity: 0.95,
|
|
25
|
+
ringCount: 5,
|
|
26
|
+
forwardOffset: 0.4,
|
|
27
|
+
suctionLength: 2.1,
|
|
28
|
+
startRadius: 0.62,
|
|
29
|
+
endRadius: 0.08,
|
|
30
|
+
ringWidth: 0.035,
|
|
31
|
+
suctionSpeed: 1.45,
|
|
32
|
+
pulse: 0.18,
|
|
33
|
+
flyingParticleCount: 42,
|
|
34
|
+
flyingParticleSize: 0.045,
|
|
35
|
+
flyingParticleSpeed: 4.2,
|
|
36
|
+
flyingParticleDrift: 0.22,
|
|
37
|
+
flyingParticleOuterOffset: 0.28,
|
|
38
|
+
flyingParticleOpacity: 0.74,
|
|
39
|
+
directionX: 1,
|
|
40
|
+
directionZ: 0
|
|
41
|
+
};
|
|
42
|
+
const lumberCartSuctionEffectPackage = {
|
|
43
|
+
id: "lumber-cart-suction",
|
|
44
|
+
nameZh: "收集车吸入圆环",
|
|
45
|
+
manifest,
|
|
46
|
+
defaultParams: DEFAULT_PARAMS,
|
|
47
|
+
debugAnchor: "playerRight",
|
|
48
|
+
debugParams: [
|
|
49
|
+
{ key: "lifetime", label: "生命周期", kind: "lifetime", min: 0.08, step: 0.01 },
|
|
50
|
+
{ key: "scale", label: "整体缩放", kind: "scale", min: 0.05, max: 6, step: 0.01 },
|
|
51
|
+
{ key: "initialHeight", label: "初始高度", kind: "number", min: -0.5, max: 3, step: 0.01 },
|
|
52
|
+
{ key: "color", label: "圆环颜色", kind: "color" },
|
|
53
|
+
{ key: "opacity", label: "透明度", kind: "opacity", min: 0, max: 1, step: 0.01 },
|
|
54
|
+
{ key: "ringCount", label: "圆环数量", kind: "number", min: 1, max: 16, step: 1 },
|
|
55
|
+
{ key: "forwardOffset", label: "车前偏移", kind: "number", min: -1, max: 4, step: 0.01 },
|
|
56
|
+
{ key: "suctionLength", label: "吸入长度", kind: "number", min: 0.1, max: 8, step: 0.01 },
|
|
57
|
+
{ key: "startRadius", label: "外圈半径", kind: "number", min: 0.02, max: 4, step: 0.01 },
|
|
58
|
+
{ key: "endRadius", label: "入口半径", kind: "number", min: 0.01, max: 2, step: 0.01 },
|
|
59
|
+
{ key: "ringWidth", label: "圆环粗细", kind: "number", min: 5e-3, max: 0.25, step: 1e-3 },
|
|
60
|
+
{ key: "suctionSpeed", label: "吸入速度", kind: "number", min: 0, max: 8, step: 0.01 },
|
|
61
|
+
{ key: "pulse", label: "收缩脉冲", kind: "number", min: 0, max: 1, step: 0.01 },
|
|
62
|
+
{ key: "flyingParticleCount", label: "飞行粒子数量", kind: "number", min: 0, max: 180, step: 1 },
|
|
63
|
+
{ key: "flyingParticleSize", label: "飞行粒子大小", kind: "number", min: 5e-3, max: 0.3, step: 1e-3 },
|
|
64
|
+
{ key: "flyingParticleSpeed", label: "飞行粒子速度", kind: "number", min: 0, max: 16, step: 0.01 },
|
|
65
|
+
{ key: "flyingParticleDrift", label: "飞行粒子散布", kind: "number", min: 0, max: 1.5, step: 0.01 },
|
|
66
|
+
{ key: "flyingParticleOuterOffset", label: "飞行粒子外偏移", kind: "number", min: -1, max: 2, step: 0.01 },
|
|
67
|
+
{ key: "flyingParticleOpacity", label: "飞行粒子透明度", kind: "opacity", min: 0, max: 1, step: 0.01 },
|
|
68
|
+
{ key: "directionX", label: "方向 X", kind: "number", min: -1, max: 1, step: 0.01 },
|
|
69
|
+
{ key: "directionZ", label: "方向 Z", kind: "number", min: -1, max: 1, step: 0.01 }
|
|
70
|
+
],
|
|
71
|
+
create({ scene, root, position, params }) {
|
|
72
|
+
root.position.copyFrom(position).addInPlace(new Vector3(0, params.initialHeight, 0));
|
|
73
|
+
const rings = createSuctionRings(scene, root, params);
|
|
74
|
+
let disposed = false;
|
|
75
|
+
rings.start();
|
|
76
|
+
return {
|
|
77
|
+
root,
|
|
78
|
+
dispose() {
|
|
79
|
+
disposeAll();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
function disposeAll() {
|
|
83
|
+
if (disposed) return;
|
|
84
|
+
disposed = true;
|
|
85
|
+
rings.dispose();
|
|
86
|
+
root.dispose();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
function createSuctionRings(scene, root, params) {
|
|
91
|
+
const basis = createRingBasis(params);
|
|
92
|
+
const ringCount = Math.max(1, Math.round(params.ringCount));
|
|
93
|
+
const material = createRingMaterial(scene, params);
|
|
94
|
+
const particles = createFlyingParticleSystem(scene, root, params, basis);
|
|
95
|
+
const rings = [];
|
|
96
|
+
let age = 0;
|
|
97
|
+
let observer = null;
|
|
98
|
+
let disposed = false;
|
|
99
|
+
for (let index = 0; index < ringCount; index += 1) {
|
|
100
|
+
const progress = index / ringCount;
|
|
101
|
+
const ring = CreateTube(`lumber-cart-suction.ring.${index}`, {
|
|
102
|
+
path: buildRingPath(basis, progress, params.pulse),
|
|
103
|
+
radius: basis.ringWidth,
|
|
104
|
+
tessellation: 8,
|
|
105
|
+
updatable: true
|
|
106
|
+
}, scene);
|
|
107
|
+
ring.parent = root;
|
|
108
|
+
ring.material = material;
|
|
109
|
+
ring.renderingGroupId = LUMBER_CART_SUCTION_RENDERING_GROUP_ID;
|
|
110
|
+
ring.isPickable = false;
|
|
111
|
+
rings.push(ring);
|
|
112
|
+
}
|
|
113
|
+
return { start, dispose };
|
|
114
|
+
function start() {
|
|
115
|
+
if (observer) return;
|
|
116
|
+
particles.start();
|
|
117
|
+
observer = scene.onBeforeRenderObservable.add(() => {
|
|
118
|
+
if (disposed) return;
|
|
119
|
+
const deltaSeconds = Math.min(0.05, scene.getEngine().getDeltaTime() / 1e3);
|
|
120
|
+
age += deltaSeconds;
|
|
121
|
+
for (let index = 0; index < rings.length; index += 1) {
|
|
122
|
+
const progress = fract(age * Math.max(0, params.suctionSpeed) + index / rings.length);
|
|
123
|
+
CreateTube(`lumber-cart-suction.ring.${index}`, {
|
|
124
|
+
path: buildRingPath(basis, progress, params.pulse),
|
|
125
|
+
radius: basis.ringWidth,
|
|
126
|
+
tessellation: 8,
|
|
127
|
+
instance: rings[index]
|
|
128
|
+
}, scene);
|
|
129
|
+
}
|
|
130
|
+
const pulse = Math.sin(age * Math.max(0.1, params.suctionSpeed) * Math.PI * 2) * Math.max(0, params.pulse);
|
|
131
|
+
material.alpha = clamp01(params.opacity * (0.88 + pulse * 0.12));
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function dispose() {
|
|
135
|
+
if (disposed) return;
|
|
136
|
+
disposed = true;
|
|
137
|
+
if (observer) scene.onBeforeRenderObservable.remove(observer);
|
|
138
|
+
observer = null;
|
|
139
|
+
for (const ring of rings) ring.dispose();
|
|
140
|
+
particles.stop();
|
|
141
|
+
particles.dispose(false);
|
|
142
|
+
material.dispose();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function createRingBasis(params) {
|
|
146
|
+
const scale = Math.max(0.01, params.scale);
|
|
147
|
+
const forward = new Vector3(params.directionX, 0, params.directionZ);
|
|
148
|
+
if (forward.lengthSquared() < 1e-4) forward.set(1, 0, 0);
|
|
149
|
+
forward.normalize();
|
|
150
|
+
return {
|
|
151
|
+
forward,
|
|
152
|
+
side: new Vector3(-forward.z, 0, forward.x),
|
|
153
|
+
up: Vector3.Up(),
|
|
154
|
+
mouth: forward.scale(params.forwardOffset * scale),
|
|
155
|
+
length: Math.max(0.01, params.suctionLength * scale),
|
|
156
|
+
startRadius: Math.max(1e-3, params.startRadius * scale),
|
|
157
|
+
endRadius: Math.max(1e-3, params.endRadius * scale),
|
|
158
|
+
ringWidth: Math.max(2e-3, params.ringWidth * scale)
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function buildRingPath(basis, progress, pulse) {
|
|
162
|
+
const points = [];
|
|
163
|
+
const segments = 72;
|
|
164
|
+
const eased = easeInCubic(clamp01(progress));
|
|
165
|
+
const distance = basis.length * (1 - eased);
|
|
166
|
+
const pulseScale = 1 + Math.sin(progress * Math.PI * 2) * Math.max(0, pulse) * 0.12;
|
|
167
|
+
const radius = lerp(basis.endRadius, basis.startRadius, 1 - eased) * pulseScale;
|
|
168
|
+
const center = basis.mouth.add(basis.forward.scale(distance));
|
|
169
|
+
for (let index = 0; index <= segments; index += 1) {
|
|
170
|
+
const angle = index / segments * Math.PI * 2;
|
|
171
|
+
points.push(
|
|
172
|
+
center.add(basis.side.scale(Math.cos(angle) * radius)).add(basis.up.scale(Math.sin(angle) * radius))
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
return points;
|
|
176
|
+
}
|
|
177
|
+
function createRingMaterial(scene, params) {
|
|
178
|
+
const material = new StandardMaterial("lumber-cart-suction.ring.material", scene);
|
|
179
|
+
const color = toColor3(params.color);
|
|
180
|
+
material.diffuseColor = color;
|
|
181
|
+
material.emissiveColor = color.scale(1.35);
|
|
182
|
+
material.alpha = params.opacity;
|
|
183
|
+
material.disableLighting = true;
|
|
184
|
+
material.backFaceCulling = false;
|
|
185
|
+
material.alphaMode = Constants.ALPHA_ADD;
|
|
186
|
+
return material;
|
|
187
|
+
}
|
|
188
|
+
function createFlyingParticleSystem(scene, root, params, basis) {
|
|
189
|
+
const scale = Math.max(0.01, params.scale);
|
|
190
|
+
const count = Math.max(0, Math.round(params.flyingParticleCount));
|
|
191
|
+
const speed = Math.max(0.01, params.flyingParticleSpeed * scale);
|
|
192
|
+
const particleLife = clampNumber(basis.length / speed, 0.18, 0.85);
|
|
193
|
+
const system = new ParticleSystem("lumber-cart-suction.flying-particles", Math.max(8, count * 2), scene);
|
|
194
|
+
const size = Math.max(1e-3, params.flyingParticleSize * scale);
|
|
195
|
+
const color = params.color;
|
|
196
|
+
const opacity = clamp01(params.flyingParticleOpacity * params.opacity);
|
|
197
|
+
system.isLocal = false;
|
|
198
|
+
system.renderingGroupId = LUMBER_CART_SUCTION_RENDERING_GROUP_ID;
|
|
199
|
+
system.particleTexture = getFlyingParticleTexture(scene);
|
|
200
|
+
system.emitter = root;
|
|
201
|
+
system.emitRate = count / particleLife;
|
|
202
|
+
system.updateSpeed = 1 / 60;
|
|
203
|
+
system.minLifeTime = particleLife * 0.72;
|
|
204
|
+
system.maxLifeTime = particleLife * 1.12;
|
|
205
|
+
system.minSize = size * 0.72;
|
|
206
|
+
system.maxSize = size * 1.28;
|
|
207
|
+
system.minAngularSpeed = -4;
|
|
208
|
+
system.maxAngularSpeed = 4;
|
|
209
|
+
system.minEmitPower = 1;
|
|
210
|
+
system.maxEmitPower = 1;
|
|
211
|
+
system.gravity = Vector3.Zero();
|
|
212
|
+
system.blendMode = ParticleSystem.BLENDMODE_ADD;
|
|
213
|
+
system.color1 = tintColor(color, 1.5, opacity * 0.78);
|
|
214
|
+
system.color2 = tintColor(color, 2.1, opacity);
|
|
215
|
+
system.colorDead = tintColor(color, 0.8, 0);
|
|
216
|
+
system.addColorGradient(0, tintColor(color, 1.1, 0));
|
|
217
|
+
system.addColorGradient(0.2, tintColor(color, 2.2, opacity));
|
|
218
|
+
system.addColorGradient(0.72, tintColor(color, 1.55, opacity * 0.68));
|
|
219
|
+
system.addColorGradient(1, tintColor(color, 0.8, 0));
|
|
220
|
+
system.addSizeGradient(0, size * 0.46, size * 0.72);
|
|
221
|
+
system.addSizeGradient(0.22, size * 0.9, size * 1.28);
|
|
222
|
+
system.addSizeGradient(1, size * 0.18, size * 0.36);
|
|
223
|
+
system.startPositionFunction = (worldMatrix, positionToUpdate, _particle, isLocal) => {
|
|
224
|
+
const local = sampleFlyingParticlePosition(basis, params);
|
|
225
|
+
if (isLocal) positionToUpdate.copyFrom(local);
|
|
226
|
+
else Vector3.TransformCoordinatesToRef(local, worldMatrix, positionToUpdate);
|
|
227
|
+
};
|
|
228
|
+
system.startDirectionFunction = (worldMatrix, directionToUpdate, particle, isLocal) => {
|
|
229
|
+
const id2 = flyingParticleDirectionSequenceIndex;
|
|
230
|
+
flyingParticleDirectionSequenceIndex += 1;
|
|
231
|
+
const localPosition = particle.position.clone();
|
|
232
|
+
const localTarget = basis.mouth.add(
|
|
233
|
+
basis.side.scale((sequence01(id2, 3) - 0.5) * basis.endRadius * 0.6)
|
|
234
|
+
).addInPlace(
|
|
235
|
+
basis.up.scale((sequence01(id2, 4) - 0.5) * basis.endRadius * 0.5)
|
|
236
|
+
);
|
|
237
|
+
const target = isLocal ? localTarget : Vector3.TransformCoordinates(localTarget, worldMatrix);
|
|
238
|
+
const direction = target.subtract(localPosition);
|
|
239
|
+
if (direction.lengthSquared() < 1e-4) {
|
|
240
|
+
const fallback = basis.forward.scale(-1);
|
|
241
|
+
if (isLocal) direction.copyFrom(fallback);
|
|
242
|
+
else Vector3.TransformNormalToRef(fallback, worldMatrix, direction);
|
|
243
|
+
} else direction.normalize();
|
|
244
|
+
const drift = Math.max(0, params.flyingParticleDrift) * scale;
|
|
245
|
+
const localTangent = basis.side.scale((sequence01(id2, 5) - 0.5) * drift).addInPlace(basis.up.scale((sequence01(id2, 6) - 0.5) * drift * 0.65));
|
|
246
|
+
const tangent = isLocal ? localTangent : Vector3.TransformNormal(localTangent, worldMatrix);
|
|
247
|
+
direction.scaleInPlace(speed * lerp(0.78, 1.28, sequence01(id2, 7))).addInPlace(tangent);
|
|
248
|
+
directionToUpdate.copyFrom(direction);
|
|
249
|
+
};
|
|
250
|
+
return system;
|
|
251
|
+
}
|
|
252
|
+
function sampleFlyingParticlePosition(basis, params) {
|
|
253
|
+
const id2 = flyingParticleSequenceIndex;
|
|
254
|
+
flyingParticleSequenceIndex += 1;
|
|
255
|
+
const scale = Math.max(0.01, params.scale);
|
|
256
|
+
const outerOffset = params.flyingParticleOuterOffset * scale;
|
|
257
|
+
const distanceRatio = lerp(0.68, 1.02, sequence01(id2, 0));
|
|
258
|
+
const radiusRatio = lerp(0.38, 0.92, Math.sqrt(sequence01(id2, 1)));
|
|
259
|
+
const angle = sequence01(id2, 2) * Math.PI * 2;
|
|
260
|
+
const radius = lerp(basis.endRadius, basis.startRadius, clamp01(distanceRatio)) * radiusRatio;
|
|
261
|
+
return basis.mouth.add(basis.forward.scale(basis.length * distanceRatio + outerOffset)).addInPlace(basis.side.scale(Math.cos(angle) * radius)).addInPlace(basis.up.scale(Math.sin(angle) * radius));
|
|
262
|
+
}
|
|
263
|
+
function getFlyingParticleTexture(scene) {
|
|
264
|
+
const key = "__vfx_lumber_cart_suction_particle_texture";
|
|
265
|
+
const metadata = scene.metadata && typeof scene.metadata === "object" ? scene.metadata : {};
|
|
266
|
+
scene.metadata = metadata;
|
|
267
|
+
const existing = metadata[key];
|
|
268
|
+
if (existing) return existing;
|
|
269
|
+
const texture = new DynamicTexture("lumber_cart_suction_particle_texture", { width: 64, height: 64 }, scene, true);
|
|
270
|
+
const context = texture.getContext();
|
|
271
|
+
context.clearRect(0, 0, 64, 64);
|
|
272
|
+
const dot = context.createRadialGradient(32, 32, 1, 32, 32, 30);
|
|
273
|
+
dot.addColorStop(0, "rgba(255, 255, 255, 1)");
|
|
274
|
+
dot.addColorStop(0.48, "rgba(255, 255, 255, 0.92)");
|
|
275
|
+
dot.addColorStop(0.78, "rgba(255, 255, 255, 0.42)");
|
|
276
|
+
dot.addColorStop(1, "rgba(255, 255, 255, 0)");
|
|
277
|
+
context.fillStyle = dot;
|
|
278
|
+
context.beginPath();
|
|
279
|
+
context.arc(32, 32, 30, 0, Math.PI * 2);
|
|
280
|
+
context.fill();
|
|
281
|
+
texture.hasAlpha = true;
|
|
282
|
+
texture.update(false);
|
|
283
|
+
metadata[key] = texture;
|
|
284
|
+
return texture;
|
|
285
|
+
}
|
|
286
|
+
function toColor3(color) {
|
|
287
|
+
return new Color3(clamp01(color.r), clamp01(color.g), clamp01(color.b));
|
|
288
|
+
}
|
|
289
|
+
function tintColor(color, brightness, alpha) {
|
|
290
|
+
return new Color4(
|
|
291
|
+
Math.max(0, color.r * brightness),
|
|
292
|
+
Math.max(0, color.g * brightness),
|
|
293
|
+
Math.max(0, color.b * brightness),
|
|
294
|
+
clamp01(alpha)
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
function lerp(min, max, t) {
|
|
298
|
+
return min + (max - min) * t;
|
|
299
|
+
}
|
|
300
|
+
function clamp01(value) {
|
|
301
|
+
return Math.min(1, Math.max(0, value));
|
|
302
|
+
}
|
|
303
|
+
function clampNumber(value, min, max) {
|
|
304
|
+
return Math.min(max, Math.max(min, value));
|
|
305
|
+
}
|
|
306
|
+
function fract(value) {
|
|
307
|
+
return value - Math.floor(value);
|
|
308
|
+
}
|
|
309
|
+
function easeInCubic(value) {
|
|
310
|
+
const t = clamp01(value);
|
|
311
|
+
return t * t * t;
|
|
312
|
+
}
|
|
313
|
+
function sequence01(index, axis) {
|
|
314
|
+
if (index === 0) return 0.5;
|
|
315
|
+
const strides = [0.618033988749895, 0.414213562373095, 0.732050807568877, 0.324717957244746, 0.754877666246693, 0.569840290998053];
|
|
316
|
+
return fract(0.5 + index * strides[axis % strides.length] + axis * 0.173205080756888);
|
|
317
|
+
}
|
|
318
|
+
let flyingParticleSequenceIndex = 0;
|
|
319
|
+
let flyingParticleDirectionSequenceIndex = 2048;
|
|
320
|
+
export {
|
|
321
|
+
lumberCartSuctionEffectPackage
|
|
322
|
+
};
|