@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.
- package/CHANGELOG.md +8 -0
- package/package.json +5 -4
- package/tooling/vfx-cli.mjs +8 -1
- package/docs/AUTHORING_EFFECTS.md +0 -297
- package/docs/INTEGRATION.md +0 -194
- package/docs/VFX_LIBRARY_ARCHITECTURE_chatgpt.md +0 -1580
- package/docs/VFX_LIBRARY_EXECUTION_PLAN.md +0 -229
- package/docs/VFX_LIBRARY_PLAN.md +0 -546
- package/docs/hit-flash-red-method.md +0 -155
- package/docs/treasure_attention_fx_babylonjs_guide.md +0 -901
- package/docs/vfx-ab/RESULTS.md +0 -35
- 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 +0 -462
- package/docs/vfx-placement-design.md +0 -164
- package/docs/weapon-trail-visualization.html +0 -241
- package/packages/EffectPackageService.ts +0 -346
- package/packages/SceneVfxService.ts +0 -96
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js +0 -333
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.frag.glsl +0 -25
- package/packages/build.mesh.yellow_build_upgrade_indicator/assets/shaders/mesh-effect-preview.vert.glsl +0 -11
- 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 +0 -927
- 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 +0 -197
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-effect.original.json +0 -895
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/03-normalized-vfx-to-babylon-report.json +0 -241
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-overrides.json +0 -542
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/04-preview-tuning-report.json +0 -69
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/asset-map.json +0 -125
- package/packages/build.mesh.yellow_build_upgrade_indicator/provenance/lineage.json +0 -44
- package/packages/build.particle.golden_upgrade_starburst/assets/runtime/particleEmitter.v1.js +0 -210
- package/packages/build.particle.golden_upgrade_starburst/assets/textures/effect_guangdian.png +0 -0
- package/packages/build.particle.golden_upgrade_starburst/effect.json +0 -880
- 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 +0 -161
- package/packages/build.particle.golden_upgrade_starburst/provenance/03-effect.original.json +0 -762
- package/packages/build.particle.golden_upgrade_starburst/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
- package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-overrides.json +0 -436
- package/packages/build.particle.golden_upgrade_starburst/provenance/04-preview-tuning-report.json +0 -40
- package/packages/build.particle.golden_upgrade_starburst/provenance/asset-map.json +0 -115
- package/packages/build.particle.golden_upgrade_starburst/provenance/lineage.json +0 -40
- package/packages/build.particle.orange_upgrade_transform_sparks/assets/runtime/particleEmitter.v1.js +0 -210
- 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 +0 -887
- 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 +0 -179
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-effect.original.json +0 -859
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/03-normalized-vfx-to-babylon-report.json +0 -260
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-overrides.json +0 -478
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/04-preview-tuning-report.json +0 -40
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/asset-map.json +0 -114
- package/packages/build.particle.orange_upgrade_transform_sparks/provenance/lineage.json +0 -41
- package/packages/build.particle.wood_chip_dust_burst/assets/runtime/particleEmitter.v1.js +0 -210
- 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 +0 -1400
- 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 +0 -173
- package/packages/build.particle.wood_chip_dust_burst/provenance/03-effect.original.json +0 -1277
- package/packages/build.particle.wood_chip_dust_burst/provenance/03-normalized-vfx-to-babylon-report.json +0 -329
- package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-overrides.json +0 -749
- package/packages/build.particle.wood_chip_dust_burst/provenance/04-preview-tuning-report.json +0 -60
- package/packages/build.particle.wood_chip_dust_burst/provenance/asset-map.json +0 -146
- package/packages/build.particle.wood_chip_dust_burst/provenance/lineage.json +0 -69
- package/packages/effects/building-upgrade/effect.json +0 -6
- package/packages/effects/building-upgrade/index.ts +0 -387
- package/packages/effects/character-entrance/effect.json +0 -6
- package/packages/effects/character-entrance/index.ts +0 -308
- package/packages/effects/coin-burst/index.ts +0 -48
- package/packages/effects/comet-trail-flame/assets/textures/trail_5x4.webp +0 -0
- package/packages/effects/comet-trail-flame/index.ts +0 -107
- package/packages/effects/conveyor-upgrade/effect.json +0 -6
- package/packages/effects/conveyor-upgrade/index.ts +0 -401
- 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 +0 -102
- package/packages/effects/door_open_gold_flakes/assets/runtime/goldFlakes.v1.js +0 -397
- package/packages/effects/door_open_gold_flakes/door_open_gold_flakes.json +0 -498
- package/packages/effects/door_open_gold_flakes/index.ts +0 -11
- package/packages/effects/electric-arc/assets/textures/spark_4x4.webp +0 -0
- package/packages/effects/electric-arc/index.ts +0 -63
- package/packages/effects/energy-shield/effect.json +0 -7
- package/packages/effects/energy-shield/index.ts +0 -432
- 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 +0 -115
- package/packages/effects/ground-tile-upgrade/effect.json +0 -6
- package/packages/effects/ground-tile-upgrade/index.ts +0 -410
- package/packages/effects/hit-flash/index.ts +0 -77
- 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 +0 -6
- package/packages/effects/laser-beam-factory.ts +0 -146
- package/packages/effects/lumber-cart-suction/effect.json +0 -6
- package/packages/effects/lumber-cart-suction/index.ts +0 -399
- 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 +0 -1
- 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 +0 -236
- package/packages/effects/lumber-debris-scatter/effect.json +0 -228
- package/packages/effects/lumber-debris-scatter/index.ts +0 -780
- package/packages/effects/lumber_vehicle_gear_spin/assets/runtime/gearSpin.v1.js +0 -202
- package/packages/effects/lumber_vehicle_gear_spin/index.ts +0 -11
- package/packages/effects/lumber_vehicle_gear_spin/lumber_vehicle_gear_spin.json +0 -338
- package/packages/effects/lumber_vehicle_upgrade_aura/assets/runtime/upgradeAura.v1.js +0 -353
- package/packages/effects/lumber_vehicle_upgrade_aura/index.ts +0 -13
- package/packages/effects/lumber_vehicle_upgrade_aura/lumber_vehicle_upgrade_aura.json +0 -365
- package/packages/effects/lumber_vehicle_wood_chips/assets/runtime/solidParticleScatter.v1.js +0 -310
- package/packages/effects/lumber_vehicle_wood_chips/index.ts +0 -11
- package/packages/effects/lumber_vehicle_wood_chips/lumber_vehicle_wood_chips.json +0 -335
- package/packages/effects/monster-hit/index.ts +0 -129
- package/packages/effects/player-upgrade/effect.json +0 -6
- package/packages/effects/player-upgrade/index.ts +0 -640
- package/packages/effects/pulse-laser-volley/assets/textures/bolt_guangshu.webp +0 -0
- package/packages/effects/pulse-laser-volley/index.ts +0 -215
- package/packages/effects/resource-collect-sparkles/effect.json +0 -6
- package/packages/effects/resource-collect-sparkles/index.ts +0 -254
- package/packages/effects/run-footstep-dust/assets/runtime/runFootstepDust.v1.js +0 -215
- package/packages/effects/run-footstep-dust/effect.json +0 -183
- package/packages/effects/run-footstep-dust/index.ts +0 -377
- package/packages/effects/space-shared.ts +0 -120
- package/packages/effects/thruster-flame/index.ts +0 -306
- package/packages/effects/treasure-attention/effect.json +0 -7
- package/packages/effects/treasure-attention/index.ts +0 -630
- package/packages/effects/tree-chop-dust/assets/textures/tree_chop_dust_atlas.png +0 -0
- package/packages/effects/tree-chop-dust/effect.json +0 -8
- package/packages/effects/tree-chop-dust/index.ts +0 -202
- package/packages/effects/tree-leaf-chop-burst/assets/runtime/particleEmitter.v1.js +0 -303
- 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 +0 -498
- package/packages/effects/tree-leaf-chop-burst/index.ts +0 -294
- package/packages/effects/tree_chop_dust_burst/assets/runtime/particleEmitter.v1.js +0 -318
- 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 +0 -13
- package/packages/effects/tree_chop_dust_burst/tree_chop_dust_burst.json +0 -412
- 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 +0 -153
- package/packages/effects/vehicle-exhaust-smoke/assets/textures/vehicle_exhaust_smoke_atlas.png +0 -0
- package/packages/effects/vehicle-exhaust-smoke/effect.json +0 -8
- package/packages/effects/vehicle-exhaust-smoke/index.ts +0 -298
- package/packages/effects/vehicle-upgrade/effect.json +0 -6
- package/packages/effects/vehicle-upgrade/index.ts +0 -404
- package/packages/effects/weapon-trail/assets/textures/trail_wedge.png +0 -0
- package/packages/effects/weapon-trail/index.ts +0 -317
- package/packages/effects/wood-crusher-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
- 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 +0 -43
- package/packages/effects/wood-crusher-sawdust/wood_crusher_sawdust.json +0 -592
- package/packages/effects/wood-cutter-sawdust/assets/runtime/particleEmitter.v1.js +0 -312
- 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 +0 -43
- package/packages/effects/wood-cutter-sawdust/wood_cutter_sawdust.json +0 -592
- package/packages/effects/wood-sawdust-effect-factory.ts +0 -194
- package/packages/effects/wood_crusher_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
- 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 +0 -29
- package/packages/effects/wood_crusher_sawdust/wood_crusher_sawdust.json +0 -592
- package/packages/effects/wood_cutter_sawdust/assets/runtime/particleEmitter.v1.js +0 -318
- 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 +0 -29
- package/packages/effects/wood_cutter_sawdust/wood_cutter_sawdust.json +0 -592
- package/packages/effects/wood_peel_material_test/assets/runtime/woodPeelMaterialTest.v1.js +0 -196
- package/packages/effects/wood_peel_material_test/index.ts +0 -11
- package/packages/effects/wood_peel_material_test/wood_peel_material_test.json +0 -136
- package/packages/env.particle.forest_edge_fog/assets/runtime/particleEmitter.v1.js +0 -210
- 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 +0 -854
- 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 +0 -148
- package/packages/env.particle.forest_edge_fog/provenance/03-effect.original.json +0 -827
- package/packages/env.particle.forest_edge_fog/provenance/03-normalized-vfx-to-babylon-report.json +0 -196
- package/packages/env.particle.forest_edge_fog/provenance/04-preview-overrides.json +0 -432
- package/packages/env.particle.forest_edge_fog/provenance/04-preview-tuning-report.json +0 -28
- package/packages/env.particle.forest_edge_fog/provenance/asset-map.json +0 -124
- package/packages/env.particle.forest_edge_fog/provenance/lineage.json +0 -41
- package/packages/generation.ts +0 -14
- package/packages/index.ts +0 -14
- package/packages/legacy-particle-runtime.ts +0 -113
- package/packages/manifestRuntimePackage.ts +0 -519
- package/packages/registry.ts +0 -85
- package/packages/rendering.ts +0 -13
- package/packages/resource.particle.viscous_oil_suction/assets/runtime/top_disk_suction/particleEmitter.v1.js +0 -424
- package/packages/resource.particle.viscous_oil_suction/assets/textures/Glow ad.png +0 -0
- package/packages/resource.particle.viscous_oil_suction/effect.json +0 -1254
- 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 +0 -122
- package/packages/resource.particle.viscous_oil_suction/provenance/03-effect.original.json +0 -1051
- package/packages/resource.particle.viscous_oil_suction/provenance/03-normalized-vfx-to-babylon-report.json +0 -200
- package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-overrides.json +0 -581
- package/packages/resource.particle.viscous_oil_suction/provenance/04-preview-tuning-report.json +0 -28
- package/packages/resource.particle.viscous_oil_suction/provenance/asset-map.json +0 -111
- package/packages/resource.particle.viscous_oil_suction/provenance/lineage.json +0 -45
- package/packages/types.ts +0 -195
- package/tooling/check-dist-runtime.mjs +0 -166
- package/tooling/generate-index.mjs +0 -55
- package/tooling/test-guardrails.mjs +0 -157
- package/tooling/validate-boundary.mjs +0 -92
- package/tooling/validate-effects.mjs +0 -304
- package/tooling/validate.mjs +0 -53
package/packages/build.mesh.yellow_build_upgrade_indicator/assets/runtime/simpleMeshEffect.v1.js
DELETED
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
export const runtimeId = "simpleMeshEffect/v1";
|
|
2
|
-
|
|
3
|
-
export const runtimeContract = {
|
|
4
|
-
runtimeId,
|
|
5
|
-
kind: "meshEffect",
|
|
6
|
-
meshEffectFields: {
|
|
7
|
-
shape: "Mesh primitive to create. Supported values: box, cylinder.",
|
|
8
|
-
size: "Absolute mesh dimensions in Babylon local x/y/z units.",
|
|
9
|
-
offset: "Babylon TransformNode position offset in x/y/z units.",
|
|
10
|
-
tintColor: "Base shader tint color in 0-1 RGBA space. RGB is multiplied by tintColorIntensity; alpha is not.",
|
|
11
|
-
tintColorIntensity: "Brightness multiplier applied only to shader tintColor.rgb.",
|
|
12
|
-
fadeSoftness: "Softness of the upward reveal edge in normalized local-Y space.",
|
|
13
|
-
boundsAxis: "Axis used by the shader for height fade and reveal. simpleMeshEffect/v1 uses localY.",
|
|
14
|
-
},
|
|
15
|
-
shaderUniforms: {
|
|
16
|
-
diffuseSampler: "Emitter texture sampled by UV.",
|
|
17
|
-
tintColor: "Final vec4 tint passed to shader after runtime keyframe sampling.",
|
|
18
|
-
globalAlpha: "Final alpha multiplier sampled from emitter.alphaKeys.",
|
|
19
|
-
revealY: "Normalized upward reveal progress from 0 to 1.",
|
|
20
|
-
fadeSoftness: "Soft reveal edge width.",
|
|
21
|
-
meshMinY: "Minimum local mesh Y used to normalize vertical gradients.",
|
|
22
|
-
meshMaxY: "Maximum local mesh Y used to normalize vertical gradients.",
|
|
23
|
-
},
|
|
24
|
-
runtimeBindings: {
|
|
25
|
-
"shader.tintColor.rgb": "meshEffect.tintColor.rgb * meshEffect.tintColorIntensity * sample(colorKeys, t).rgb",
|
|
26
|
-
"shader.tintColor.a": "meshEffect.tintColor.a * sample(colorKeys, t).a",
|
|
27
|
-
"shader.globalAlpha": "sample(alphaKeys, t).alpha",
|
|
28
|
-
"root.scaling.y": "sample(meshScaleKeys.y, t) / finalMeshScaleKeysY",
|
|
29
|
-
"shader.revealY": "elapsed / duration",
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
function num(value, fallback = 0) {
|
|
34
|
-
const next = Number(value);
|
|
35
|
-
return Number.isFinite(next) ? next : fallback;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function readColor(BABYLON, value, fallback = new BABYLON.Color4(1, 1, 1, 1)) {
|
|
39
|
-
if (!value) return fallback;
|
|
40
|
-
return new BABYLON.Color4(num(value.r, fallback.r), num(value.g, fallback.g), num(value.b, fallback.b), num(value.a, fallback.a));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function sampleKeyframes(keys, valueKey, t, fallback = 1) {
|
|
44
|
-
if (!Array.isArray(keys) || keys.length === 0) return fallback;
|
|
45
|
-
const points = keys
|
|
46
|
-
.map((key) => ({ time: Math.min(1, Math.max(0, num(key.time, 0))), value: num(key[valueKey], fallback) }))
|
|
47
|
-
.sort((a, b) => a.time - b.time);
|
|
48
|
-
if (t <= points[0].time) return points[0].value;
|
|
49
|
-
for (let index = 1; index < points.length; index += 1) {
|
|
50
|
-
const prev = points[index - 1];
|
|
51
|
-
const next = points[index];
|
|
52
|
-
if (t <= next.time) {
|
|
53
|
-
const span = Math.max(0.0001, next.time - prev.time);
|
|
54
|
-
const local = (t - prev.time) / span;
|
|
55
|
-
return prev.value + (next.value - prev.value) * local;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return points.at(-1).value;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function sampleColorKeyframes(BABYLON, keys, t, fallback = new BABYLON.Color4(1, 1, 1, 1)) {
|
|
62
|
-
if (!Array.isArray(keys) || keys.length === 0) return fallback;
|
|
63
|
-
const points = keys
|
|
64
|
-
.map((key) => ({
|
|
65
|
-
time: Math.min(1, Math.max(0, num(key.time, 0))),
|
|
66
|
-
color: readColor(BABYLON, key.color, fallback),
|
|
67
|
-
}))
|
|
68
|
-
.sort((a, b) => a.time - b.time);
|
|
69
|
-
if (t <= points[0].time) return points[0].color;
|
|
70
|
-
for (let index = 1; index < points.length; index += 1) {
|
|
71
|
-
const prev = points[index - 1];
|
|
72
|
-
const next = points[index];
|
|
73
|
-
if (t <= next.time) {
|
|
74
|
-
const span = Math.max(0.0001, next.time - prev.time);
|
|
75
|
-
const local = (t - prev.time) / span;
|
|
76
|
-
return new BABYLON.Color4(
|
|
77
|
-
prev.color.r + (next.color.r - prev.color.r) * local,
|
|
78
|
-
prev.color.g + (next.color.g - prev.color.g) * local,
|
|
79
|
-
prev.color.b + (next.color.b - prev.color.b) * local,
|
|
80
|
-
prev.color.a + (next.color.a - prev.color.a) * local,
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return points.at(-1).color;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function shaderMaterialAlphaMode(BABYLON, value) {
|
|
88
|
-
if (value === "STANDARD") return BABYLON.Engine.ALPHA_COMBINE;
|
|
89
|
-
if (value === "MULTIPLY") return BABYLON.Engine.ALPHA_MULTIPLY ?? BABYLON.Engine.ALPHA_COMBINE;
|
|
90
|
-
return BABYLON.Engine.ALPHA_ADD;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function shaderStoreName(emitter, index) {
|
|
94
|
-
const id = String(emitter?.shader?.id || emitter?.meshEffect?.shaderId || `simpleMeshEffectV1_${index}`)
|
|
95
|
-
.replace(/[^a-zA-Z0-9_]/g, "_")
|
|
96
|
-
.replace(/^([^a-zA-Z_])/, "_$1");
|
|
97
|
-
return id || `simpleMeshEffectV1_${index}`;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async function fetchShaderSource({ packagePath, label, urlForPackagePath }) {
|
|
101
|
-
if (!packagePath) throw new Error(`Missing ${label} shader path.`);
|
|
102
|
-
const url = urlForPackagePath ? urlForPackagePath(packagePath) : packagePath;
|
|
103
|
-
const response = await fetch(url, { cache: "no-store" });
|
|
104
|
-
if (!response.ok) throw new Error(`Failed to load ${label} shader ${packagePath}: HTTP ${response.status}.`);
|
|
105
|
-
const source = await response.text();
|
|
106
|
-
if (!source.trim()) throw new Error(`Loaded empty ${label} shader ${packagePath}.`);
|
|
107
|
-
return source;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function loadShaders({ BABYLON, emitter, index, urlForPackagePath }) {
|
|
111
|
-
const name = shaderStoreName(emitter, index);
|
|
112
|
-
const vertexSource = await fetchShaderSource({
|
|
113
|
-
packagePath: emitter?.shader?.vertexShaderPath,
|
|
114
|
-
label: "vertex",
|
|
115
|
-
urlForPackagePath,
|
|
116
|
-
});
|
|
117
|
-
const fragmentSource = await fetchShaderSource({
|
|
118
|
-
packagePath: emitter?.shader?.fragmentShaderPath,
|
|
119
|
-
label: "fragment",
|
|
120
|
-
urlForPackagePath,
|
|
121
|
-
});
|
|
122
|
-
BABYLON.Effect.ShadersStore[`${name}VertexShader`] = vertexSource;
|
|
123
|
-
BABYLON.Effect.ShadersStore[`${name}FragmentShader`] = fragmentSource;
|
|
124
|
-
return name;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function createMaterial({ BABYLON, scene, name, texture, alphaMode, shaderName }) {
|
|
128
|
-
const material = new BABYLON.ShaderMaterial(name, scene, {
|
|
129
|
-
vertex: shaderName,
|
|
130
|
-
fragment: shaderName,
|
|
131
|
-
}, {
|
|
132
|
-
attributes: ["position", "uv"],
|
|
133
|
-
uniforms: ["worldViewProjection", "tintColor", "meshMinY", "meshMaxY", "revealY", "fadeSoftness", "globalAlpha"],
|
|
134
|
-
samplers: ["diffuseSampler"],
|
|
135
|
-
needAlphaBlending: true,
|
|
136
|
-
});
|
|
137
|
-
material.setTexture("diffuseSampler", texture);
|
|
138
|
-
material.setFloat("meshMinY", -1);
|
|
139
|
-
material.setFloat("meshMaxY", 1);
|
|
140
|
-
material.setFloat("revealY", 0);
|
|
141
|
-
material.setFloat("fadeSoftness", 0.24);
|
|
142
|
-
material.setFloat("globalAlpha", 1);
|
|
143
|
-
material.backFaceCulling = false;
|
|
144
|
-
material.alphaMode = shaderMaterialAlphaMode(BABYLON, alphaMode);
|
|
145
|
-
return material;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function meshLocalYBounds(BABYLON, meshes) {
|
|
149
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
150
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
151
|
-
for (const mesh of meshes) {
|
|
152
|
-
const positions = mesh.getVerticesData?.(BABYLON.VertexBuffer.PositionKind) || [];
|
|
153
|
-
for (let index = 1; index < positions.length; index += 3) {
|
|
154
|
-
minY = Math.min(minY, positions[index]);
|
|
155
|
-
maxY = Math.max(maxY, positions[index]);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (!Number.isFinite(minY) || !Number.isFinite(maxY)) return { minY: -1, maxY: 1 };
|
|
159
|
-
return { minY, maxY: Math.max(maxY, minY + 0.0001) };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function shapeType(emitter) {
|
|
163
|
-
const shape = emitter?.meshEffect?.shape || "box";
|
|
164
|
-
return ["box", "cylinder"].includes(shape) ? shape : "box";
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function createBoxMeshes({ BABYLON, scene, emitter, index, root, material, width, depth, height }) {
|
|
168
|
-
const sides = [
|
|
169
|
-
{ name: "front", sideWidth: width, position: new BABYLON.Vector3(0, 0, depth * 0.5), rotationY: 0 },
|
|
170
|
-
{ name: "back", sideWidth: width, position: new BABYLON.Vector3(0, 0, -depth * 0.5), rotationY: Math.PI },
|
|
171
|
-
{ name: "right", sideWidth: depth, position: new BABYLON.Vector3(width * 0.5, 0, 0), rotationY: Math.PI * 0.5 },
|
|
172
|
-
{ name: "left", sideWidth: depth, position: new BABYLON.Vector3(-width * 0.5, 0, 0), rotationY: -Math.PI * 0.5 },
|
|
173
|
-
];
|
|
174
|
-
return sides.map((side) => {
|
|
175
|
-
const mesh = BABYLON.MeshBuilder.CreatePlane(`simple-mesh-effect-${emitter.name || index}-${side.name}`, { width: side.sideWidth, height }, scene);
|
|
176
|
-
mesh.material = material;
|
|
177
|
-
mesh.parent = root;
|
|
178
|
-
mesh.position = side.position;
|
|
179
|
-
mesh.rotation.y = side.rotationY;
|
|
180
|
-
mesh.renderingGroupId = 2;
|
|
181
|
-
mesh.metadata = { ...(mesh.metadata || {}), emitterIndex: index, meshEffectMode: "simple", meshEffectShape: "box" };
|
|
182
|
-
return mesh;
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function createCylinderMeshes({ BABYLON, scene, emitter, index, root, material, width, depth, height }) {
|
|
187
|
-
const mesh = BABYLON.MeshBuilder.CreateCylinder(`simple-mesh-effect-${emitter.name || index}-cylinder`, {
|
|
188
|
-
height,
|
|
189
|
-
diameter: 1,
|
|
190
|
-
tessellation: 48,
|
|
191
|
-
cap: BABYLON.Mesh.NO_CAP,
|
|
192
|
-
}, scene);
|
|
193
|
-
mesh.material = material;
|
|
194
|
-
mesh.parent = root;
|
|
195
|
-
mesh.scaling.x = width;
|
|
196
|
-
mesh.scaling.z = depth;
|
|
197
|
-
mesh.renderingGroupId = 2;
|
|
198
|
-
mesh.metadata = { ...(mesh.metadata || {}), emitterIndex: index, meshEffectMode: "simple", meshEffectShape: "cylinder" };
|
|
199
|
-
return [mesh];
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function createMeshes({ BABYLON, scene, emitter, index, root, material, size }) {
|
|
203
|
-
if (shapeType(emitter) === "cylinder") {
|
|
204
|
-
return createCylinderMeshes({ BABYLON, scene, emitter, index, root, material, width: size.x, depth: size.z, height: size.y });
|
|
205
|
-
}
|
|
206
|
-
return createBoxMeshes({ BABYLON, scene, emitter, index, root, material, width: size.x, depth: size.z, height: size.y });
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function defaultSize(emitter) {
|
|
210
|
-
const finalMeshScaleY = Math.max(0.001, num(emitter.meshScaleKeys?.y?.at?.(-1)?.scale, 8));
|
|
211
|
-
return {
|
|
212
|
-
x: Math.max(0.1, num(emitter.meshScaleKeys?.x?.[0]?.scale, 7.125) * 1.016),
|
|
213
|
-
y: Math.max(0.1, finalMeshScaleY * 1.016),
|
|
214
|
-
z: Math.max(0.1, num(emitter.meshScaleKeys?.z?.[0]?.scale, 4.125) * 1.016),
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function meshEffectSize(emitter) {
|
|
219
|
-
const fallback = defaultSize(emitter);
|
|
220
|
-
return {
|
|
221
|
-
x: Math.max(0.1, num(emitter.meshEffect?.size?.x, fallback.x)),
|
|
222
|
-
y: Math.max(0.1, num(emitter.meshEffect?.size?.y, fallback.y)),
|
|
223
|
-
z: Math.max(0.1, num(emitter.meshEffect?.size?.z, fallback.z)),
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function meshEffectOffset(emitter) {
|
|
228
|
-
return {
|
|
229
|
-
x: num(emitter.meshEffect?.offset?.x, 0),
|
|
230
|
-
y: num(emitter.meshEffect?.offset?.y, 0.65),
|
|
231
|
-
z: num(emitter.meshEffect?.offset?.z, 0),
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function playbackSpeed(emitter) {
|
|
236
|
-
return Math.max(0.001, num(emitter.updateSpeed, 0.01) / 0.01);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function stopAfterSeconds(emitter, fallback = 1) {
|
|
240
|
-
return num(emitter.runtime?.stopAfterSeconds, fallback);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export async function createSimpleMeshEffectRuntime({ BABYLON, scene, emitter, index = 0, urlForPackagePath, shouldStart = false }) {
|
|
244
|
-
if (!BABYLON) throw new Error("createSimpleMeshEffectRuntime requires BABYLON.");
|
|
245
|
-
if (!scene) throw new Error("createSimpleMeshEffectRuntime requires scene.");
|
|
246
|
-
if (!emitter) throw new Error("createSimpleMeshEffectRuntime requires emitter.");
|
|
247
|
-
const shaderName = await loadShaders({ BABYLON, emitter, index, urlForPackagePath });
|
|
248
|
-
const textureUrl = urlForPackagePath ? urlForPackagePath(emitter.particleTexturePath) : emitter.particleTexturePath;
|
|
249
|
-
const texture = new BABYLON.Texture(textureUrl, scene);
|
|
250
|
-
texture.hasAlpha = true;
|
|
251
|
-
texture.getAlphaFromRGB = true;
|
|
252
|
-
|
|
253
|
-
const material = createMaterial({
|
|
254
|
-
BABYLON,
|
|
255
|
-
scene,
|
|
256
|
-
name: `simple-mesh-effect-material-${emitter.name || index}`,
|
|
257
|
-
texture,
|
|
258
|
-
alphaMode: emitter.blendMode,
|
|
259
|
-
shaderName,
|
|
260
|
-
});
|
|
261
|
-
const size = meshEffectSize(emitter);
|
|
262
|
-
const offset = meshEffectOffset(emitter);
|
|
263
|
-
const root = new BABYLON.TransformNode(`simple-mesh-effect-${emitter.name || index}`, scene);
|
|
264
|
-
root.position = new BABYLON.Vector3(offset.x, offset.y, offset.z);
|
|
265
|
-
root.metadata = { ...(root.metadata || {}), emitterIndex: index, meshEffectMode: "simple", meshEffectShape: shapeType(emitter) };
|
|
266
|
-
const meshes = createMeshes({ BABYLON, scene, emitter, index, root, material, size });
|
|
267
|
-
root.setEnabled(false);
|
|
268
|
-
|
|
269
|
-
const bounds = meshLocalYBounds(BABYLON, meshes);
|
|
270
|
-
material.setFloat("meshMinY", bounds.minY);
|
|
271
|
-
material.setFloat("meshMaxY", bounds.maxY);
|
|
272
|
-
|
|
273
|
-
const finalMeshScaleY = Math.max(0.001, num(emitter.meshScaleKeys?.y?.at?.(-1)?.scale, 1));
|
|
274
|
-
const duration = Math.max(0.1, stopAfterSeconds(emitter) / playbackSpeed(emitter));
|
|
275
|
-
const baseTint = readColor(BABYLON, emitter.meshEffect?.tintColor, new BABYLON.Color4(1, 1, 1, 1));
|
|
276
|
-
const tintColorIntensity = Math.max(0, num(emitter.meshEffect?.tintColorIntensity, 1));
|
|
277
|
-
const fadeSoftness = Math.max(0.03, num(emitter.meshEffect?.fadeSoftness, 0.24));
|
|
278
|
-
const colorKeys = emitter.colorKeys || [];
|
|
279
|
-
const meshScaleKeys = emitter.meshScaleKeys || null;
|
|
280
|
-
let startedAt = 0;
|
|
281
|
-
let observer = null;
|
|
282
|
-
let running = false;
|
|
283
|
-
|
|
284
|
-
const update = () => {
|
|
285
|
-
const elapsed = (performance.now() - startedAt) / 1000;
|
|
286
|
-
const t = Math.min(1, elapsed / duration);
|
|
287
|
-
const sizeFactor = Math.max(0.001, sampleKeyframes(emitter.sizeKeys, "size", t, 1));
|
|
288
|
-
const alphaFactor = Math.min(1, Math.max(0, sampleKeyframes(emitter.alphaKeys, "alpha", t, 1)));
|
|
289
|
-
const colorFactor = sampleColorKeyframes(BABYLON, colorKeys, t);
|
|
290
|
-
const rawScaleY = Math.max(0.001, sampleKeyframes(meshScaleKeys?.y, "scale", t, sizeFactor));
|
|
291
|
-
const scaleY = Math.max(0.001, rawScaleY / finalMeshScaleY);
|
|
292
|
-
root.scaling.set(1, scaleY, 1);
|
|
293
|
-
root.position.set(offset.x, offset.y - bounds.minY * scaleY, offset.z);
|
|
294
|
-
material.setFloat("revealY", Math.min(1, Math.max(0.001, t)));
|
|
295
|
-
material.setFloat("fadeSoftness", fadeSoftness);
|
|
296
|
-
material.setFloat("globalAlpha", alphaFactor);
|
|
297
|
-
material.setVector4("tintColor", new BABYLON.Vector4(
|
|
298
|
-
baseTint.r * tintColorIntensity * colorFactor.r,
|
|
299
|
-
baseTint.g * tintColorIntensity * colorFactor.g,
|
|
300
|
-
baseTint.b * tintColorIntensity * colorFactor.b,
|
|
301
|
-
baseTint.a * colorFactor.a,
|
|
302
|
-
));
|
|
303
|
-
if (t >= 1) stop();
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
function start() {
|
|
307
|
-
stop();
|
|
308
|
-
running = true;
|
|
309
|
-
startedAt = performance.now();
|
|
310
|
-
root.setEnabled(true);
|
|
311
|
-
update();
|
|
312
|
-
observer = scene.onBeforeRenderObservable.add(update);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function stop() {
|
|
316
|
-
if (observer) scene.onBeforeRenderObservable.remove(observer);
|
|
317
|
-
observer = null;
|
|
318
|
-
running = false;
|
|
319
|
-
root.setEnabled(false);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function dispose() {
|
|
323
|
-
stop();
|
|
324
|
-
for (const mesh of meshes) mesh.dispose();
|
|
325
|
-
root.dispose();
|
|
326
|
-
material.dispose();
|
|
327
|
-
texture.dispose();
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const preview = { start, stop, dispose, isStarted: () => running, root, meshes, material };
|
|
331
|
-
if (shouldStart) preview.start();
|
|
332
|
-
return preview;
|
|
333
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
precision highp float;
|
|
2
|
-
varying vec2 vUV;
|
|
3
|
-
varying float vLocalY;
|
|
4
|
-
uniform sampler2D diffuseSampler;
|
|
5
|
-
uniform vec4 tintColor;
|
|
6
|
-
uniform float meshMinY;
|
|
7
|
-
uniform float meshMaxY;
|
|
8
|
-
uniform float revealY;
|
|
9
|
-
uniform float fadeSoftness;
|
|
10
|
-
uniform float globalAlpha;
|
|
11
|
-
float saturate(float value) {
|
|
12
|
-
return clamp(value, 0.0, 1.0);
|
|
13
|
-
}
|
|
14
|
-
void main(void) {
|
|
15
|
-
vec4 tex = texture2D(diffuseSampler, vUV);
|
|
16
|
-
float height = max(meshMaxY - meshMinY, 0.0001);
|
|
17
|
-
float y01 = saturate((vLocalY - meshMinY) / height);
|
|
18
|
-
float revealMask = saturate((revealY - y01) / max(fadeSoftness, 0.0001));
|
|
19
|
-
float bottomSoft = smoothstep(0.0, 0.06, y01);
|
|
20
|
-
float verticalFade = pow(saturate(1.0 - y01), 1.35);
|
|
21
|
-
float textureGlow = mix(0.65, 1.15, max(max(tex.r, tex.g), tex.b));
|
|
22
|
-
float alpha = tintColor.a * globalAlpha * revealMask * bottomSoft * verticalFade * textureGlow;
|
|
23
|
-
vec3 color = tintColor.rgb * mix(vec3(0.72), vec3(1.18), tex.rgb);
|
|
24
|
-
gl_FragColor = vec4(color, alpha);
|
|
25
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
precision highp float;
|
|
2
|
-
attribute vec3 position;
|
|
3
|
-
attribute vec2 uv;
|
|
4
|
-
uniform mat4 worldViewProjection;
|
|
5
|
-
varying vec2 vUV;
|
|
6
|
-
varying float vLocalY;
|
|
7
|
-
void main(void) {
|
|
8
|
-
vUV = uv;
|
|
9
|
-
vLocalY = position.y;
|
|
10
|
-
gl_Position = worldViewProjection * vec4(position, 1.0);
|
|
11
|
-
}
|