@fps-games/vfx 0.3.4 → 0.3.6
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 +22 -0
- package/dist/chunks/{manifestRuntimePackage-CXQFSTo2.js → manifestRuntimePackage-Vgh-cH5X.js} +9 -0
- package/dist/effects/door_open_gold_flakes/index.js +1 -1
- package/dist/effects/energy-shield/index.d.ts +2 -3
- package/dist/effects/energy-shield/index.js +80 -37
- package/dist/effects/lumber_vehicle_gear_spin/index.js +1 -1
- package/dist/effects/lumber_vehicle_upgrade_aura/index.js +1 -1
- package/dist/effects/lumber_vehicle_wood_chips/index.js +1 -1
- package/dist/effects/treasure-attention/index.d.ts +1 -0
- package/dist/effects/treasure-attention/index.js +5 -3
- package/dist/effects/tree_chop_dust_burst/index.js +1 -1
- package/dist/effects/weapon-trail/index.d.ts +5 -1
- package/dist/effects/weapon-trail/index.js +130 -77
- package/dist/effects/wood_crusher_sawdust/index.js +1 -1
- package/dist/effects/wood_cutter_sawdust/index.js +1 -1
- package/dist/effects/wood_peel_material_test/index.js +1 -1
- package/dist/index.js +1 -1
- package/dist/manifestRuntimePackage.d.ts +1 -1
- package/dist/types.d.ts +6 -3
- package/package.json +1 -1
- package/packages/effects/energy-shield/vfx-params.json +2 -1
- package/packages/effects/treasure-attention/vfx-params.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,28 @@
|
|
|
12
12
|
|
|
13
13
|
<!-- release.mjs 在此行下方插入新版本区块 -->
|
|
14
14
|
|
|
15
|
+
## v0.3.6 — 2026-07-01
|
|
16
|
+
|
|
17
|
+
### 改动
|
|
18
|
+
- perf(energy-shield): 去掉 per-instance GlowLayer,改用 shader halo shell,并默认关闭外层壳。
|
|
19
|
+
- perf(treasure-attention): 默认不创建 per-instance GlowLayer,保留 `showGlowLayer` 调试开关用于后续 AB。
|
|
20
|
+
- feat(energy-shield/treasure-attention): 补充 boolean 调试开关,方便在 demo/debug panel 中临时切换。
|
|
21
|
+
|
|
22
|
+
### 特效
|
|
23
|
+
- 无新增 / 删除(仍 37 个)。
|
|
24
|
+
|
|
25
|
+
## v0.3.5 — 2026-07-01
|
|
26
|
+
|
|
27
|
+
### 改动
|
|
28
|
+
- fix(weapon-trail): 拖尾按实际历史弧长映射,消除运动采样不足导致的截断
|
|
29
|
+
- feat(weapon-trail): refine layered trail controls
|
|
30
|
+
- feat(weapon-trail): 默认关闭刃头火花 (sparkRate 20→0)
|
|
31
|
+
- feat(weapon-trail): 软边加色外晕 ribbon 替代 GlowLayer 的柔光晕
|
|
32
|
+
- perf(weapon-trail): 去掉 per-instance GlowLayer,bloom 折进 additive 亮度 (#11 L-D)
|
|
33
|
+
|
|
34
|
+
### 特效
|
|
35
|
+
- 无新增 / 删除(仍 37 个)。
|
|
36
|
+
|
|
15
37
|
## v0.3.4 — 2026-06-30
|
|
16
38
|
|
|
17
39
|
### 改动
|
package/dist/chunks/{manifestRuntimePackage-CXQFSTo2.js → manifestRuntimePackage-Vgh-cH5X.js}
RENAMED
|
@@ -294,6 +294,14 @@ function buildDebugParams(manifest) {
|
|
|
294
294
|
});
|
|
295
295
|
continue;
|
|
296
296
|
}
|
|
297
|
+
if (param.type === "boolean") {
|
|
298
|
+
result.push({
|
|
299
|
+
key: param.key,
|
|
300
|
+
label,
|
|
301
|
+
kind: "boolean"
|
|
302
|
+
});
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
297
305
|
if (param.type === "enum" && Array.isArray(param.options)) {
|
|
298
306
|
result.push({
|
|
299
307
|
key: param.key,
|
|
@@ -311,6 +319,7 @@ function buildDebugParams(manifest) {
|
|
|
311
319
|
function isVfxParamValue(value) {
|
|
312
320
|
if (typeof value === "number") return Number.isFinite(value);
|
|
313
321
|
if (typeof value === "string") return true;
|
|
322
|
+
if (typeof value === "boolean") return true;
|
|
314
323
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
315
324
|
const color = value;
|
|
316
325
|
return typeof color.r === "number" && Number.isFinite(color.r) && typeof color.g === "number" && Number.isFinite(color.g) && typeof color.b === "number" && Number.isFinite(color.b);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-
|
|
1
|
+
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
2
2
|
const schemaVersion = "vfx-effect-package/1.0";
|
|
3
3
|
const id = "build.particle.door_open_gold_flakes";
|
|
4
4
|
const name = {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { GlowLayer } from '@babylonjs/core/Layers/glowLayer';
|
|
2
1
|
import { ShaderMaterial } from '@babylonjs/core/Materials/shaderMaterial';
|
|
3
2
|
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
4
3
|
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
|
|
@@ -24,7 +23,8 @@ export interface EnergyShieldParams extends VfxParamValues {
|
|
|
24
23
|
flowIntensity: number;
|
|
25
24
|
marbleContrast: number;
|
|
26
25
|
bloomIntensity: number;
|
|
27
|
-
|
|
26
|
+
haloScale: number;
|
|
27
|
+
showHalo: boolean;
|
|
28
28
|
segments: number;
|
|
29
29
|
}
|
|
30
30
|
export interface CreateEnergyShieldOptions {
|
|
@@ -38,7 +38,6 @@ export interface CreateEnergyShieldOptions {
|
|
|
38
38
|
export interface EnergyShieldHandle extends VfxEffectHandle {
|
|
39
39
|
shield: Mesh;
|
|
40
40
|
material: ShaderMaterial;
|
|
41
|
-
glowLayer: GlowLayer | null;
|
|
42
41
|
update(params: Partial<EnergyShieldParams>): void;
|
|
43
42
|
}
|
|
44
43
|
export declare const energyShieldEffectPackage: VfxEffectPackage<EnergyShieldParams>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Constants } from "@babylonjs/core/Engines/constants";
|
|
2
|
-
import { GlowLayer } from "@babylonjs/core/Layers/glowLayer";
|
|
3
2
|
import { Effect } from "@babylonjs/core/Materials/effect";
|
|
4
3
|
import { ShaderMaterial } from "@babylonjs/core/Materials/shaderMaterial";
|
|
5
4
|
import { Color3 } from "@babylonjs/core/Maths/math.color";
|
|
@@ -26,7 +25,8 @@ const DEFAULT_PARAMS = {
|
|
|
26
25
|
flowIntensity: 1.15,
|
|
27
26
|
marbleContrast: 0.67,
|
|
28
27
|
bloomIntensity: 0.45,
|
|
29
|
-
|
|
28
|
+
haloScale: 1.012,
|
|
29
|
+
showHalo: false,
|
|
30
30
|
segments: 64
|
|
31
31
|
};
|
|
32
32
|
const VERTEX_SHADER = `
|
|
@@ -69,6 +69,8 @@ uniform float uFlowScale;
|
|
|
69
69
|
uniform float uFlowSpeed;
|
|
70
70
|
uniform float uFlowIntensity;
|
|
71
71
|
uniform float uMarbleContrast;
|
|
72
|
+
uniform float uHaloAlphaScale;
|
|
73
|
+
uniform float uHaloMode;
|
|
72
74
|
|
|
73
75
|
varying vec3 vObjPos;
|
|
74
76
|
varying vec3 vWorldPos;
|
|
@@ -173,6 +175,16 @@ void main(void) {
|
|
|
173
175
|
alpha += fresnel * uOpacity * 0.58;
|
|
174
176
|
alpha += noiseEdge * uNoiseEdgeIntensity * 0.05;
|
|
175
177
|
|
|
178
|
+
if (uHaloMode > 0.5) {
|
|
179
|
+
float haloRim = pow(saturate(1.0 - ndv), max(0.35, uFresnelPower * 0.55));
|
|
180
|
+
float softRim = smoothstep(0.08, 0.86, haloRim);
|
|
181
|
+
float edgeTaper = 1.0 - smoothstep(0.78, 1.0, haloRim) * 0.62;
|
|
182
|
+
color = uColor * (0.82 + softRim * 0.32) * (0.9 + cloud * 0.1);
|
|
183
|
+
alpha = (0.06 + softRim * 0.62 + noiseEdge * 0.12) * edgeTaper;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
alpha *= uHaloAlphaScale;
|
|
187
|
+
|
|
176
188
|
gl_FragColor = vec4(color, saturate(alpha));
|
|
177
189
|
}
|
|
178
190
|
`;
|
|
@@ -205,7 +217,8 @@ const energyShieldEffectPackage = {
|
|
|
205
217
|
{ key: "flowIntensity", label: "流动强度", kind: "number", min: 0, max: 8, step: 0.01 },
|
|
206
218
|
{ key: "marbleContrast", label: "纹路锐度", kind: "number", min: 0.25, max: 4, step: 0.01 },
|
|
207
219
|
{ key: "bloomIntensity", label: "Bloom 强度", kind: "number", min: 0, max: 4, step: 0.01 },
|
|
208
|
-
{ key: "
|
|
220
|
+
{ key: "haloScale", label: "外层光晕缩放", kind: "scale", min: 1, max: 1.08, step: 1e-3 },
|
|
221
|
+
{ key: "showHalo", label: "显示外层光晕", kind: "boolean" }
|
|
209
222
|
],
|
|
210
223
|
create({ scene, root, position, renderingGroupId, params }) {
|
|
211
224
|
return createEnergyShield(scene, { root, position, renderingGroupId, params });
|
|
@@ -239,28 +252,56 @@ function createEnergyShield(scene, options = {}) {
|
|
|
239
252
|
shield.alphaIndex = 20;
|
|
240
253
|
const material = createShieldMaterial(scene);
|
|
241
254
|
shield.material = material;
|
|
242
|
-
let
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
255
|
+
let halo = null;
|
|
256
|
+
let haloMaterial = null;
|
|
257
|
+
const disposeHalo = () => {
|
|
258
|
+
halo?.dispose(false, false);
|
|
259
|
+
haloMaterial?.dispose();
|
|
260
|
+
halo = null;
|
|
261
|
+
haloMaterial = null;
|
|
262
|
+
};
|
|
263
|
+
const ensureHalo = () => {
|
|
264
|
+
if (!params.showHalo || params.bloomIntensity <= 1e-3) {
|
|
265
|
+
disposeHalo();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (halo && haloMaterial) return;
|
|
269
|
+
halo = MeshBuilder.CreateSphere(
|
|
270
|
+
"vfx_energyShield_halo",
|
|
271
|
+
{
|
|
272
|
+
diameter: 2,
|
|
273
|
+
segments: Math.max(16, Math.round(params.segments)),
|
|
274
|
+
slice: 0.5,
|
|
275
|
+
updatable: false
|
|
276
|
+
},
|
|
277
|
+
scene
|
|
278
|
+
);
|
|
279
|
+
halo.parent = shield;
|
|
280
|
+
halo.isPickable = false;
|
|
281
|
+
halo.alwaysSelectAsActiveMesh = true;
|
|
282
|
+
halo.renderingGroupId = shield.renderingGroupId;
|
|
283
|
+
halo.alphaIndex = shield.alphaIndex + 1;
|
|
284
|
+
halo.scaling.setAll(Math.max(1, params.haloScale));
|
|
285
|
+
haloMaterial = createShieldMaterial(scene, {
|
|
286
|
+
name: "vfx_energyShield_halo_material",
|
|
287
|
+
alphaMode: Constants.ALPHA_ADD
|
|
247
288
|
});
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
applyParams(material, shield, glowLayer, params);
|
|
289
|
+
halo.material = haloMaterial;
|
|
290
|
+
};
|
|
291
|
+
ensureHalo();
|
|
292
|
+
applyParams(material, shield, halo, haloMaterial, params);
|
|
253
293
|
let elapsed = 0;
|
|
254
294
|
const observer = scene.onBeforeRenderObservable.add(() => {
|
|
255
295
|
elapsed += Math.min(scene.getEngine().getDeltaTime() / 1e3, 0.05);
|
|
256
296
|
material.setFloat("uTime", elapsed);
|
|
297
|
+
haloMaterial?.setFloat("uTime", elapsed);
|
|
257
298
|
});
|
|
258
299
|
let disposed = false;
|
|
259
300
|
const dispose = () => {
|
|
260
301
|
if (disposed) return;
|
|
261
302
|
disposed = true;
|
|
262
303
|
scene.onBeforeRenderObservable.remove(observer);
|
|
263
|
-
|
|
304
|
+
disposeHalo();
|
|
264
305
|
shield.dispose(false, false);
|
|
265
306
|
material.dispose();
|
|
266
307
|
if (disposeRoot) root.dispose();
|
|
@@ -269,28 +310,17 @@ function createEnergyShield(scene, options = {}) {
|
|
|
269
310
|
root,
|
|
270
311
|
shield,
|
|
271
312
|
material,
|
|
272
|
-
glowLayer,
|
|
273
313
|
update(partial) {
|
|
274
314
|
params = mergeParams(partial, params);
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
glowLayer = new GlowLayer(`vfx_energyShield_glow_${shield.uniqueId}`, scene, {
|
|
278
|
-
blurKernelSize: params.bloomKernelSize,
|
|
279
|
-
mainTextureRatio: 0.35
|
|
280
|
-
});
|
|
281
|
-
glowLayer.addIncludedOnlyMesh(shield);
|
|
282
|
-
glowLayer.referenceMeshToUseItsOwnMaterial(shield);
|
|
283
|
-
glowLayer.intensity = params.bloomIntensity;
|
|
284
|
-
applyParams(material, shield, glowLayer, params);
|
|
285
|
-
this.glowLayer = glowLayer;
|
|
286
|
-
}
|
|
315
|
+
ensureHalo();
|
|
316
|
+
applyParams(material, shield, halo, haloMaterial, params);
|
|
287
317
|
},
|
|
288
318
|
dispose
|
|
289
319
|
};
|
|
290
320
|
}
|
|
291
|
-
function createShieldMaterial(scene) {
|
|
321
|
+
function createShieldMaterial(scene, options = {}) {
|
|
292
322
|
const material = new ShaderMaterial(
|
|
293
|
-
"vfx_energyShield_material",
|
|
323
|
+
options.name ?? "vfx_energyShield_material",
|
|
294
324
|
scene,
|
|
295
325
|
{ vertex: SHADER_NAME, fragment: SHADER_NAME },
|
|
296
326
|
{
|
|
@@ -313,21 +343,36 @@ function createShieldMaterial(scene) {
|
|
|
313
343
|
"uFlowScale",
|
|
314
344
|
"uFlowSpeed",
|
|
315
345
|
"uFlowIntensity",
|
|
316
|
-
"uMarbleContrast"
|
|
346
|
+
"uMarbleContrast",
|
|
347
|
+
"uHaloAlphaScale",
|
|
348
|
+
"uHaloMode"
|
|
317
349
|
],
|
|
318
350
|
needAlphaBlending: true
|
|
319
351
|
}
|
|
320
352
|
);
|
|
321
|
-
material.alphaMode = Constants.ALPHA_COMBINE;
|
|
353
|
+
material.alphaMode = options.alphaMode ?? Constants.ALPHA_COMBINE;
|
|
322
354
|
material.backFaceCulling = false;
|
|
323
355
|
material.disableDepthWrite = true;
|
|
324
356
|
material.fogEnabled = false;
|
|
325
357
|
return material;
|
|
326
358
|
}
|
|
327
|
-
function applyParams(material, shield,
|
|
359
|
+
function applyParams(material, shield, halo, haloMaterial, params) {
|
|
328
360
|
shield.scaling.set(params.radius, params.radius * params.verticalScale, params.radius);
|
|
361
|
+
applyMaterialParams(material, params, params.opacity, 1, 0);
|
|
362
|
+
if (halo && haloMaterial) {
|
|
363
|
+
halo.scaling.setAll(Math.max(1, params.haloScale));
|
|
364
|
+
applyMaterialParams(
|
|
365
|
+
haloMaterial,
|
|
366
|
+
params,
|
|
367
|
+
1,
|
|
368
|
+
params.opacity * 0.95 * Math.min(2.2, params.bloomIntensity),
|
|
369
|
+
1
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function applyMaterialParams(material, params, opacity, haloAlphaScale, haloMode) {
|
|
329
374
|
material.setColor3("uColor", toColor3(params.color));
|
|
330
|
-
material.setFloat("uOpacity",
|
|
375
|
+
material.setFloat("uOpacity", opacity);
|
|
331
376
|
material.setFloat("uFresnelPower", params.fresnelPower);
|
|
332
377
|
material.setFloat("uFresnelStrength", params.fresnelStrength);
|
|
333
378
|
material.setFloat("uRimIntensity", params.rimIntensity);
|
|
@@ -340,10 +385,8 @@ function applyParams(material, shield, glowLayer, params) {
|
|
|
340
385
|
material.setFloat("uFlowSpeed", params.flowSpeed);
|
|
341
386
|
material.setFloat("uFlowIntensity", params.flowIntensity);
|
|
342
387
|
material.setFloat("uMarbleContrast", params.marbleContrast);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
glowLayer.blurKernelSize = params.bloomKernelSize;
|
|
346
|
-
}
|
|
388
|
+
material.setFloat("uHaloAlphaScale", haloAlphaScale);
|
|
389
|
+
material.setFloat("uHaloMode", haloMode);
|
|
347
390
|
}
|
|
348
391
|
function mergeParams(patch, base = DEFAULT_PARAMS) {
|
|
349
392
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-
|
|
1
|
+
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
2
2
|
const schemaVersion = "vfx-effect-package/1.0";
|
|
3
3
|
const id = "build.particle.lumber_vehicle_gear_spin";
|
|
4
4
|
const name = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-
|
|
1
|
+
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
2
2
|
const schemaVersion = "vfx-effect-package/1.0";
|
|
3
3
|
const id = "build.particle.lumber_vehicle_upgrade_aura";
|
|
4
4
|
const name = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-
|
|
1
|
+
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
2
2
|
const schemaVersion = "vfx-effect-package/1.0";
|
|
3
3
|
const id = "build.particle.lumber_vehicle_wood_chips";
|
|
4
4
|
const name = {
|
|
@@ -35,7 +35,8 @@ const DEFAULT_PARAMS = {
|
|
|
35
35
|
riseSpeed: 0.72,
|
|
36
36
|
drift: 0.12,
|
|
37
37
|
bloomIntensity: 0.55,
|
|
38
|
-
bloomKernelSize: 32
|
|
38
|
+
bloomKernelSize: 32,
|
|
39
|
+
showGlowLayer: false
|
|
39
40
|
};
|
|
40
41
|
const treasureAttentionEffectPackage = {
|
|
41
42
|
id: "treasure-attention",
|
|
@@ -72,7 +73,8 @@ const treasureAttentionEffectPackage = {
|
|
|
72
73
|
{ key: "riseSpeed", label: "上浮速度", kind: "number", min: 0, max: 2.5, step: 0.01 },
|
|
73
74
|
{ key: "drift", label: "横向漂移", kind: "number", min: 0, max: 1.2, step: 0.01 },
|
|
74
75
|
{ key: "bloomIntensity", label: "Bloom 强度", kind: "number", min: 0, max: 2.5, step: 0.01 },
|
|
75
|
-
{ key: "bloomKernelSize", label: "Bloom 半径", kind: "number", min: 8, max: 96, step: 1 }
|
|
76
|
+
{ key: "bloomKernelSize", label: "Bloom 半径", kind: "number", min: 8, max: 96, step: 1 },
|
|
77
|
+
{ key: "showGlowLayer", label: "显示 GlowLayer", kind: "boolean" }
|
|
76
78
|
],
|
|
77
79
|
create({ scene, root, position, renderingGroupId, params }) {
|
|
78
80
|
return createTreasureAttentionFx(scene, { root, position, renderingGroupId, params, serviceOwnedRoot: true });
|
|
@@ -264,7 +266,7 @@ function createTreasureAttentionFx(scene, options = {}) {
|
|
|
264
266
|
}
|
|
265
267
|
}
|
|
266
268
|
function syncGlowLayer() {
|
|
267
|
-
const shouldGlow = params.bloomIntensity > 0;
|
|
269
|
+
const shouldGlow = params.showGlowLayer && params.bloomIntensity > 0;
|
|
268
270
|
if (!shouldGlow) {
|
|
269
271
|
if (glowLayer) {
|
|
270
272
|
for (const mesh of meshes) removeGlowMesh(mesh);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-
|
|
1
|
+
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
2
2
|
const schemaVersion = "vfx-effect-package/1.0";
|
|
3
3
|
const id = "build.particle.tree_chop_dust_burst";
|
|
4
4
|
const name = {
|
|
@@ -2,7 +2,11 @@ import { VfxColorValue, VfxEffectPackage, VfxParamValues } from '../../types';
|
|
|
2
2
|
interface WeaponTrailParams extends VfxParamValues {
|
|
3
3
|
lifetimeMode: string;
|
|
4
4
|
lifetime: number;
|
|
5
|
+
playbackMode: string;
|
|
5
6
|
orientation: string;
|
|
7
|
+
showGlow: boolean;
|
|
8
|
+
showOuter: boolean;
|
|
9
|
+
showCore: boolean;
|
|
6
10
|
orbitRadius: number;
|
|
7
11
|
orbitSpeed: number;
|
|
8
12
|
height: number;
|
|
@@ -12,6 +16,7 @@ interface WeaponTrailParams extends VfxParamValues {
|
|
|
12
16
|
coreWidth: number;
|
|
13
17
|
tailFadeStrength: number;
|
|
14
18
|
tailFadeExponent: number;
|
|
19
|
+
edgeSoftness: number;
|
|
15
20
|
opacity: number;
|
|
16
21
|
saturation: number;
|
|
17
22
|
contrast: number;
|
|
@@ -19,7 +24,6 @@ interface WeaponTrailParams extends VfxParamValues {
|
|
|
19
24
|
bloom: number;
|
|
20
25
|
blendMode: string;
|
|
21
26
|
flowSpeed: number;
|
|
22
|
-
sparkRate: number;
|
|
23
27
|
tint: VfxColorValue;
|
|
24
28
|
}
|
|
25
29
|
export declare const weaponTrailEffectPackage: VfxEffectPackage<WeaponTrailParams>;
|
|
@@ -4,26 +4,29 @@ import { VertexBuffer } from "@babylonjs/core/Buffers/buffer";
|
|
|
4
4
|
import { ShaderMaterial } from "@babylonjs/core/Materials/shaderMaterial";
|
|
5
5
|
import { Effect } from "@babylonjs/core/Materials/effect";
|
|
6
6
|
import { Texture } from "@babylonjs/core/Materials/Textures/texture";
|
|
7
|
-
import { Color3
|
|
7
|
+
import { Color3 } from "@babylonjs/core/Maths/math.color";
|
|
8
8
|
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
|
|
9
9
|
import { Constants } from "@babylonjs/core/Engines/constants";
|
|
10
|
-
import {
|
|
11
|
-
import { ParticleSystem } from "@babylonjs/core/Particles/particleSystem";
|
|
12
|
-
import { L as LIFETIME_DEBUG_PARAMS, a as LIFETIME_DEFAULTS, b as makeFlareTexture, s as scheduleLifetime } from "../../chunks/space-shared-BXV1hc0k.js";
|
|
10
|
+
import { L as LIFETIME_DEBUG_PARAMS, a as LIFETIME_DEFAULTS, s as scheduleLifetime } from "../../chunks/space-shared-BXV1hc0k.js";
|
|
13
11
|
const trailTextureUrl = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP4AAABNCAYAAACGyNmKAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAgAElEQVR4nOy9S49sWXYe9q219z6PiMy8eR91q6rZD/aDXQItyZKrbRiaiIIB/QPNDMMQZPNnsDXyxBNJIxKCBgY1sUcGBwQsAoaHAtgTAxRANLtJkWZXdXVV3Xsz43HO3uvhwT4nMiIy8t681Wx2N5mrcCtPxHnEiXPO9621vrX2DsK+/Yt/FwF0AM6mfw2ADGA1/Rvwb/+54MEe7MF+qS3e8b4CKNNymV4/2IM92N8Qo1vv/It/16ESQg8goIJ+C0Dwb//58Nd6dg/2YA/2MzE+8Z5M/7YAVs+e+PCVizP98L8u+uFv/3b66z29B3uwB/tZ2C2P7+6gf/kv41eufj09f47mvGsOtrkesl8N2QHgAo/kk6utP//gxS7v/95v/mY5PuaDPdiD/WLZSeB/53d+J72nv3L23uMv9TZcL9vUpZxLUjNfjaLmVjakRsWlWCoIkM/X2R4txjITwwUeVTJ4/0c7IvjeRx85vvvdB3HwwR7s52y3c/zvfjf+xuU/OPv7X3n/LKm/23B6f9nGpbOnXMSyk0iWvM2mBhqslFzIi5rl7QDJqpnZRd0Kh06uh2Jb07LN6szXGQAeiOHBHuzna7eA/+Fv/3Z6Tz54+u1n7ZeenPXfOm/S18+79KhJHFRhg2jJRXUQUQPGIprFkEVlNAuluIwqPDrZMGSzkm0sKMWExmKWh6KmjRUuLsWbwgHyYpvtFDHcSiMeiOHBHuyvxG4B/5/+r//X8sl5fO9rjy++8aUny7/7337t4n/82juPvvryeo1B7GqT5fPProf1aP4j4v5HxYqJuoq5FFEr5jKKWhYXsZJFkBU+qmkuwqNAsgmPYB83oyoHbEVKGQbIfYjhtfrCAzE82IPdyw6A7+70T/7V//noVy+fv/eVx/3f/crjxT/47/7Ou/+994uv/nhwXxDRRSQ8bskftUxiwKvVSrejbF+uhzyIXg3FP/98s12PxT8KTfexmKoaVNQ1q2oRl1HVcnERr8Rg8FxUR1XOMzGI+yg5j0ihjDnnYYBk07zZjh7OYpFBy6wvbIv6AzE82IPd36K7715853d+J57jXbhIExhNG0PSou2nwfF/fzrQi+y4FkMBU6Puz1rG8xj5nRCWT5vu7OkZnny1D1/7Lzumiy5iyIqr9Vo2Y9m+XG3KVvFqLP5pVv/x2vCxGtaqrupmuagWdxFxHVVtGEUU7aiOUqQZasSAYrQcVWiUMx9NSrbAeTNkU6ExW5s3cXTrOVNxubxYlM2nCwwUMgB82D3OV9/93ZPE8L2PPqoX4oEYHuxvgZ3s3FMt0R2JGQC5Fwc+LYS/3BZ8ng3FAA6B/nSlnrggUqQk5okJkYDE5E0GvbckfxoRny+786f9Es/O8eQrHX39cRdw1kash2yv1htbj2Vztd6WjfjLodhnRfDxFvyROQadIgVR02IuuagWcxtERLUdRSzrWZvVNOeCrLQYS/YM4lFyHofLVkspRYRGQ1vuIoYP8CU/67blgRge7G+D3QL+q02bvtwniEowA8yAgoCXSP5xLvTxRjFMDX1xZIoERFIkCp4Gp8SExEAsih++IooMJFYkJtRlQtMFX/YJz3ui591ZeKej86fniifJnzxu6JtPuog2Mq63W3u13up6lM1Q7PrlervdSvpM1D4SWv6luEspZuK+I4ZRRMdKDlq0HYtYVtPsTOM4aHY+zyVLNtBgXvJKgjq8bFacC3fyPLJaL7kglcuLhbz4qHVvmlKJoStX3/19v4DIJ1dbB4AHYniwX0Y76fGNhUQ9AMCqPb8QImwVuBLDy2LYOMEA8FBFgohgvBYKVMEdCOBRERmITEiheJzWpeLULBiREjV99MRAehLQtI3Frgm9wFMHulD4E+rpWdfHd9gvnizk4v0njMfJf+1xG8AMrLZZrkaVF5usWfTli20Z1OnjqzF/EpX+YhYe1V1rpAAtJjqqay4uYpqLWBb1sZz7qNZm8zAWLdlAg4qXdy9bK2ZZhUeFl80weL9cDo/eWRqFXrbXl2Wb1T/Al9wQM777+5iJ4fkH39jTF1YTMfzGAzE82M/dbgG/bwK5USQiAoA2EG2NUFIkMaAYMLrDAEDrs8zuoBZOKyMmAgGgwUAEMAG8BQV2BBYEAuJPnMJyhcigyIT0Mnhk4tQFj/2CmkVjTZO8WTRhuYannmjRJG0+BacEb3roI0F42rThaUC4bBa4PEP/9SfOTxp847IhUndcDSIvt2KbYpsXo+SN6KsyjB8X9T+H2mfFxERcxDERg0suxXKtUIzFXMtUqhRFVvNMtNxstCisH1VKGbtHeSzrMpZlKVIkNLEIvDz/lefy8vqVk2nZ5t4/ANywrcTw/jvyybr482V6IIYH+7nYXaPzYIbIcye/E5wY6KP4OkcHYA5g0gXNAb72qUIwvTmRAgFAriRAZOBsIAB8pWACqB8R1pECA4EIcXllIUSKDIpt54GA1ESPRBzblhoK1lzGELqGziX6+QWsK+CeQJHIjYDQQs9A4R1K4VlM4TLi8tkj4CvRnz9p8GsXDWFUx6tB9Tpbfjmoroa8Xqu+XOfyKWX9IVQ+VzerGoNpURIx1bGoZu1EHFlM81hcijajEw3mPqrwKF7GUVjf689KAcooXkZJpWyC2CJmiiKXjrJZv8IQmwwAH5zD7brP+O5/xMX74YEYHuxnareAP6y2sSxi2H8vEMAnx/NM5qgRwGxbqSSwuRnNS+O44wSSfPO+JNB6AFquRHAFDsvRa7SwBoPABAQmcAJiTIgfRQSGhzZS6kJITW/RG6RFRMNAIq/RQ5soBkYHRiSgG8mbBHQMPGsIz2LkJxHdkwb07El/9s3o7z5p8O1lon+0Lo6Xg+ir0ex61GE15vVa5OW4HT6Oju+L21YVKu5ailk2K0XNsriMklTBYzEdh6xm4FGh2XC2KaNmBB+3LYlepFw0lVE2RXQpZVnEomWKrVx2sWy2WwxZCnCGD87P3JJm/Ov/iIv2kBhmUvDf+scyBWoP9mCvtTs9/mxGzA3gLYPIUiUEFYDv2HUG/b6NI3ZFw5LrshQgJqAUEAVgBLQRwAHaCKFhIBt46Q6JREmcCU4YiQmgxGCCMxECEYUYEJgQ2+iB4TEkigwPXaBIhNQFtGiq8NhGRARqiT32AQ2TpyEgXbKxRjqPjuct8A4FftZFftL4+XvL/vxp4+9etvR32kC/scpmV9uir0bRVdb11uzVNtvnZcgfmeufZyUpIpPw6JPw6DJq1RrUfBTv83YUVTwai2pmarZFkY18GIVV+5SLUhlVylBCcVc1a3Lpx3LZPZUX1yt3o/LB+Znj7Bzf/jd/Un7tX3/fB/lUAOCBGB7sLjuJ3sBEIdx4eALQZexV/I9szASk256eCjDsxQIlH+4ntU3fp78QAKFUYsh1P8sgwqaWA4oBicEsBhCQAtGsKVA9z9BEIlRtgYjATfBAVLUFJuwIgshTFz3GWHUGBtJPEkcmb7uA78eAGAjJIxLDExNSExCZ/DwS3u2Z3gkcn3ZNfNqie6/lp09a+sZlSwhEuBrVrkaztdG4yrpdqa9Wg3yuw/CfTeUvioiJkapDc3EtXjWGUaG5mIh7Lo48qotYyiDfqmIsoAykcT24vtu3uSDlrFKKRSm9KhOXwo8KpXN5cb12p1A+eP/cbeT87X/zJ/jwt38kn6xrHvZ8+WMFPsT3PsJEDHgghr8l9lqPTyDqA9FoIIpwaxs6AD+LYT09KfugpwnIM+j3AS9Ho3b16PXIAE1prDoQtT6VRafaokOD1s9aD4YQmednNbCXdZ7aEev/mQGKPAmNlSS4qdolE4gBxC4h0KQxpFCrEU2cyIJRS5SEpo+eMnNaBv9jBpqQEBlomuAhAC23iInx5Czi3UXEs5jCOx0Wj/u4/GbC04uIr13Es39oAK6z23WBXRUvG6L1ZrDVar35zPLwx6L+WTFVUag6VY3BSUZRzVLJQRcYs9k4wlWtyXDeFgtZQCM8jUrIz0LSQk1RU9kqF3fT0OXtI3XfrqIQf1m25WP/4H13W67zt/89KjE8Vn/+4su7PO2BGP7m2WmPT0QEO7jDCcAB6Ac7SOtB2bEOdAD6GfDHYAduA17mKEF2wiAAoEzLPn2cZ2BGdXSCFDemSW2cVvHNqXskJwkMUwPXMIY2lVjmh5ji6EwApwAC6nKomgOHGhEEJkQmCm30+IKQGkZgQhMjIhNiF72NW2qYkF41aGKkLrVoekbbJU0auAV5G4FnHfBeQ7hMCE8aio8adF9dhifnz86/tojn/1UxYKOQdXFZqet1wXYjdrVabX8y5uH7Kvy5wFSMpIhZMRdxrq3Q5kWUcoZLWSxyUR+VYxGjTITNJrs6eLQl55LHskGngiGX4UwMIdOZyWVsZYPPMSBPwqO7WVu+/e+BD3/vR/LJVv35iy/vCY87YtAHYvjlsDfl+ASAmHc9/XSwbhBCAPByfqfQAeCBQ9DfBfa7zPcEbDWAj5INIQZ5JYr5zHYlh+mlOpzNAfBuf/OJHKj+Z9OkgmMBY0L9lCoQCiiwM9fXoakXIzCDY6RAQOgiQmJKzIgpINAGqYsemdDFllIbQkwBbRe9YULXNpQI1LXJGgu0iIQ+ghZnsL6A3zmDXQbwJVF7ycC7PS2WkZ8snp1/vePz/2ZU+NZcNwrbiI/XxYdVtlfrsfwoj+MfjYWzkosoLKuJTFFDNqrRgtM4iGrpm2xEo1qX7Zw2pXhBDONWgmhrueSmrNSNEHJxE6OYKQW9pKZssMVQb6h/cA43yxMxuH6yhT9/AcGHwPf+056/+B/oYe7GXxB7o7h3pw1TaP8SwGaKDk55+X2wvwnowI233we9GxAY8Hn/fWTvI/72Yj3mRAv7BDEdwtnd8w2hOTA1JtTXBAZHdZ2EA8rMhCooUBTnGIBtQUiRGJUEEK3EVyFxCohxxBwxpC4iEKFJEWnB0liKTRPQdME7JKSrQIs2Wvsi8DKSdwlYMlmzBNoMaiL8rIdeGvgiEj8OoGXA4ksLXizOw+OO09cTL/7RoI7BULbiPijG66LbTcbVKuc/WY/+w6woimRZTUVJi3MZTXVUSFGoEo3ilLcZqu65mGfmZluKZIs8jmqqZyGX7LJSN/UweGnMKOXCg1w+dXnRwv2HKh/EeknNzgp+131oUIXHb1Su3RHDAyn8tdpJ4McUQU4E3/PwDQhrTIDeq/alEQjTPSu4DfhjsO/n7wDA6Sa8D3sBBcUb8BNPHn/6XMdNbE9ewe9Ul99kexkBAMBACEdUYTcE4exQQQ1ggzvMHQwnAiCEEJ1BgBZzCgwuUk++zSVsmsRdAIIVZoA35KFhZ4sNt24ceWxD20QipBgoLIK0ffS2BG7a6AnM7SP2bhtDh6Cxo9ATaztSWPbIZwneCoVEQL9EbkfEBcMfOYWziHAZyLvgiy+3adExnrScvs4EH9V9NMgoXtZA3gz2ci32+avV+BfXlv6iiJkCKkaSzbQ4tBjJqI1mYxHTsbiXMUUR96zmGdxsi0hB9HG0Tt99VErRULJ7KZ6k5KysLuXMC7nri7+Ee9PLB4/h9goFv+u4eAT9ZFvvxQMx/GztFvDbVNHnTAEAElMYJvw5UKV9ncAve155HAG2OhP/1u/O2Y/N9lOB12y3ayY6uv8z4J1u7XKnHW9qe+/wCRLY7TclsAaa91ARAxFIFGCCUWBEdhJEi+KsAgJFNC7EDMogClJIAjERbZMUJvIQGbQmhCZ6iDSmNliAU7vpOTJZatkjk3YpUiTkdhmtQ4iJ4T3F0F6HbrGgMRL8gsiSwJcR3giFxMBigdxmxEWAL4lwxuBFoKYjNE8e8aIFvty+0/w9d/hgrqO7joZxNC+D8ItVLi9/8lL+ZEPhsyKk4lB11mymxVhGVc3OZRRWhebiMWeBFvdRXIv3PJhTNsRRg5dnDDUTycll20K8uPapGR8xfOuQ8S/h3kA/eAy3iILfd1xIJYaZFADge/8JD6TwBewA+J/88eP45aeTuEc2V8iw16R3YyLAqMBKCeMIjJP4NoP+FOD3w3d6Q5bhJxrUDDcA5wNF79Db39f7H9sx6G99/hylnCAZA9UZDdRIDE4EN3WfuIIlRsCcEoPgQCNCgRAyEUVGIQMTg7ZKnNiJmCkymK+dA3kI7KlhD8QIiZ1fMLqYLDJ507JFJu9joMCEbsHWI4RuwRIZpd+G1AtTImjfkkWCLwZwJPgiwaKjjqok+GUPvTDingh9QLOMaJ60OGuXzVeaJ83fU4dn9zIaLIOGUVQG5c9/srWrFxv+f7eKUQ0qRCIKzUpanMrUwSRiXrJxKS3KKNDiyAgYdHQR1qzAaO5lk2FFYxl7iG2zGDeFEvRyAdl8DAyh/u7Dh+9Drn6/VpovBIb3cfDgfO87D6Rwyr5Yjp8VgBKgjrEAJjUPL1ZDckIF/Snwzva6dfukoHvFAwYOuglmkW4f6G8C/esCAwO9EfzHoN/z/gfnRQCMqJ4LwVydmMyzgjkyKUULph4JVAxEBAvsFAhUjAACR0YIAUREksykBAIMHGFMhA2LMbGHRAhMFhtGDOxhRUjO1naBAoH6ZczhU3gXuI6eJKBD4L6nEgnou6AJTgnki8zcNrBE8FizL48AFg00Ab5gYEnkS4AWjLZvQntJWP7qskUCfr04PAOycdetet6obQfx63HjH/94CN8fFVm9RgzFTIuzZlXJC5ZRTBWcByEtHbI5srqVsYsFjhGMvFWoLlHKFjIGiAD6nKEmkP4RyvUrGAD7PMMe9dAP/4P7lcAvBPaNb8B+uL25v3/44d/eKsS9gH+yWXdUx3aoD3meQD/bMejdjnp69yycOPopUgh8QyoAAPOTnnc/7P8iXv914J8/zyY9Yo4Awj0eHnMAtZHAoeZEIEMdXEAERHao1QkNiECB3YrBxcGBQMZk2WulITBzJBdyhBhAmUCJKGYDM4EDI0RSFgUH8pgVKbEz4DExUoKHQCUIexvIuhVRx3WIdduTxoE8ELxv2BPDo4NirqMrFwneCFuEo+3JIuAJ8EDkCbAlnJZMWIJoEah5Fjl1Lc67M3wpAv8wAzaYy+jQrSJvRIbB6Gq70T//eBv/P3GUYjBxiJhrcZaspoOYFIcqcxZF2UaoAmKKwXuUIhAj5OcJUhzy1QVyBnQVYH1B0QjFGvLeBniR4U0D+c4fwD/8Dw4M0IkUZvM//LA+sX9TieFO4AdmMN+AcpffF60h/r55qUcqNgFvr/Z+F+Bn2/foxySwv25/GeYwJrCdBugXAfxsbwL9tOwG0D4RnCKhY9sRxp6gaKhaqTtAVCUMclR1FUAk93lEFAEUCW4Ol0oiqgqO7ExEQgQiRojmIkQp1gfXGngZnZiBEN05EGKq/BYjERM5N25tIE8bTAQBD5k8BvJI5A2TRXIkYe/VPBB5zOTLRM5wJCJEAJFhbfS6HjCGI4GMCd4w2QXViKGH8zJy+zRy0xPO+yV9iQk2Omx0l2yetw7ZFBm2xT99ucF/fqXN52NxU4dKjRpkNGgx6KhQA3IxFFGIOLICIg2KOoobChNKXkC+vIAWh1gDWQ9w66H4EewbjyCbDYAA+Sf/D3Bd4B/+Xm0gOREt/FITwy3gL/oebDffpmVQ9psc3+dlE4cqwUuNZYsB4rW7LmBavuNTfW8F7YH9dSQw70fASZQpdrX51wK/nu1pe12Yv6f0AwDNHp+nhiGGn6wQ7I5NNx88fY4biAIcBjhNy7vvM8XZakSR3c1BgeDqE/gNFGqVw9XJqFYaQnSY1mOpOYgcXkAcyE1rQYTEYcZgOIkQiAhRHBoJzFS7HIU8wBEDgYmQakOTp2wAwQPgTSBPSpYSIZA7O7wN8GDkTYC3wT2gRgIRcBbzwPAEsobggWAM8ujugdw6wM+JcEZkPSMuQOF55Kbrcd49wq8CsBGko1oZzWRrGLZi6zz4Zz8pzV9cCbZFYFL5ULNWgE+kUMQgBIwFEEONEnILNUfxAC0FgjPImCFjA7cGMgRYADT/CPjGI+jn1/Cugd5BDAf2hx/CflGJ4Y7OPaXaBF/P2xwIaa8SNqpjFIK8yZ1jD+R3YOo+JFDda102oHr6PfDPQH+Tuv9XfQ9mfTHsAfquVGH/lA0EchAfMpS73/IgFA67lmj6LJqiMYrk+yKDqSPEqfhgjjCRhRmIA0GzgQO5m4JACJEQEkMU5AQPVtuaGE5GBAOcyWFuREQYBR4COTNcAIc6kgIhkLO7E5EHcme4ty15gHskePX48GBwRo0IOoJHcg+ABSKLcA91nbHDW3ZjkAW4B8DPiGzJ8J4Y5xGhcyyeNKFrF3jy9wnfMkCzeRnNZWu+HdU3JfurFzm8/LTwq01BrtUIqGBHDKoCEaBYCykKoQ55dJgIBAuUUWDKEBXYe48gkqGbBCuAWiUGoy3svRV8UEBDrTp85w8OiMGPUgkHfn4RwxcS9xyZcCeSUXW/W1H4iUabg9d0QwL7BOBWt9knCGM6EPnmzONtSno/pdXg4wjMDL9XqlBf32x3SkQ50g3oPqnEG2yOGk6uU8eEeYQINyFQBLQ4IZGLAkQ1AlBzMqtFjBCqxlsUFAKc4AiBnADPo3uI5Az3JpKvxZ1BzoAHco+xphVhHno9cSiTo2cyVvdQicEbgr1wWHBYAjwSjAFLBEsODQRb1IjB+0DUB/TnCW3T+uWvMn01VeVIxyzjKJYHw2Y76rA1vn6h4fqFxNVoEDWIOKwYrHglhylaUAckK6REqDNEW6gYpBgMgDzuYQjQVYHligCzAFOFtZUYsGhhPxnhexGDAzti2D0T31sB/o/hPytieDvgM0+KPgA9yvNlOmfdA7CfigheQwBmVcmqie60Od+Af7d/zYdh1R+BJhZ4U679ujAfuKnnv0nZn23f478u1L8F+tvbEP/V3GQOBJrOhdObxQ6bAE1UQ3yEE9sIyMkRI7loBT9Q0z7VmyKMKxADoAriAIdX+SdEYCgOAjxMYCcHIDO/+fyep1j/XruDUbftmJzcvafaqhUIFgzeEDw4vOWaerxy2McG7wgSCJ4IhZycDdYadEHAIkZfRISOsDxfYtkQniQAU1+oDFnGUX3M4O06Y7sR37yQeP1ZxlArETDRmk4Ug2aDqUHEoOoQdWiJNarQFuI1q9Ii0GcXsKywywBzhb0yeFjCJ2Lw91bwFxm+VeDDCPvOHwAzMeD9w2fmp40Y7gT+XMO/deT4mrKo2aGwd8v2z/0oaHCfavNH6NwngXkfsykmZgJN6v5+hHFXSe8+1+ieoCfGXo4/7XNq35/GU4fTwL2X92f4HOoDAAWcqDveNEPOZgaQOoVIbnqz/76pAbEWWab2TnKiuq3ajTwzn7woEMJ099RBIEwzO+xaPWZXUaS2QKRKoE4E35qjZfKtORomZ4czqsdvCM5ag6YuwIlgscpM3k2yTAsoE/zaamRA0749IFxdh7WANQ5qQ7Q+Ii6B80cdzgKAWAnHFJBcdMzqZaPIg/lmNWL4TNL1q4JcOxzholBx2GhQd2hRqLVQtbqsDDWHPW9hajALUBX4ozPY+wU2FHiJMKvCo7HDYfDNTUXCv/MHAAb4P/ujCrj//dcPn70f/OAHAIBvfetbJx+P09Nrc4gMBoGo4RpJ70Q94LB0d+r1ydT/DXiqHtzBTDCtf2/tO5HC7J7cp9t2opHnFPj3g4a7bPb6d4l086HsngAEDnWAu2yPX+8Kx0+ehzhRrF+UZ09sR0IhKn/SCW9+bHyUdphWjw0AKpUQ3nQMs7kieeJ8521mWQZHf6mSxL6YDABSh094mfTdluvtHWoa4OzAVkENA6ESg18D6AjWeH1KmIDGoVMkYdcELABlh7PDCPDkEAL8jKDklXyYoGfulJg8MCMFipfwkIg6PoMHwvuocreMRUtWl0F9XCu2r3LYfqa8WQlkEh5NtXr+0sDUoAJYibACmARobmEOqLUwc5gHWClwWcC+vIAXh1sDGwL8ssDPCP6b34M/BvzTEfjKr8A/92/iX30LPv9uxjiOaNt258dvAb+Z4jgiIuaaeymmaNbD7d77fAJGbxXi7xlPIN7/e/vgVQWbD+juJ4H8RZT9GiLfP9Sf7U2NP28iCH67+qOb70iHTgCRpnM5efn2Pzbej2AOBEMFhQjoFHRNnh8xTGkD9ojCQHE6F5u8/myzdhuPychrUygdrZsJoJkIbSpwAg4M1bN7okoMDQPB6iajg3oCkYMToWynxsnWoWzw9QR+msmhgh4vAWoASQCxA2uHkLqjliidiGxJUEz9pLGmIAgxoI3gBdA9NWvpHI8iuTtgYiijqI6KvDHkrfj4eabhhcSyKRD12gonPhGDw3QiC2uhRWuB3ADLAsMClmpVyJ42MCf4WQOPV/ALgf8vfwrvtvBRgSfPWv8oA//sjxz/x39B/sVH530he8PzvQvh581n730kdxMR3B3stwGsOJmn3nkq+/sbCDa12hFeSwD7+uO9Wn33lf99241B8EOvz+RQJ0Ty10UW+x7/PkZ3nOsc8ptVgJo4hXtoBDPoVW+AqlM4zwFQc5rThaon3C/yAKqPOSaGrKAU4GOdjOnme+Hmlo4GahjElVxc6noXB6cpgJ2+mfcEbOtXzucAVgYLAYDD2EFiMGaYW92vCTQHvzYoNHAFvgCOKWrAFFEQscFgVLsfnQHEFH2ZEC8IgYHu1wgXXM+9Vhscmh2yVZf1aPLRENYvMsogMHGYAq4KzwrzGsUYATanMApYUfizBTwKTBM8R/gnn8I/38Kg8A9/z3+KYbmzNXCUI/jNXXa3bL49x38nm13UHLrPccoM9N1h3qBo7IP/vkQATKD06oHfJjW/y+PPDybfAfrXmJvTcSnvcH2t498X9DPY9tMAkwNPvvPUs5mAQrx9ziZORIRT6w62m/J9M1C447vrJOHE18zlemxFgeYN99QBKINDVdwPkkUAGBmcDLo2eM9wJYTPALtkQKYQv0xRAzOxB88AAB/fSURBVDmsENFFHVJmsJrzFwY6hY0M6rzK2sx1PWqyadOMNl5oRwrGgIt73d5J62Sy8EhAqqkLtZHikxji18/RUg3ydKo2aHG3rZiss5VXkvK1wLJCJ1IwmsjIp32GKjDahqDxU1jbwH42Hv8k6GfbB/vRs3BXeL8P+v3XRrcn5zi2N4F+P+y3Yya6w+6h0k/HqynHfbSA13DZfmh/a92ex98PyW9tN+X4d3n8/f2Pw3KgksQsrYQAcIDblPOrOSITxGoeDFRAh7gXQdRrSzHA55SAD0J/R3jNdSrVi//UVhxhSTsxllpHdr+5Jgf9oZP3XrgHAGZEghu5y8ngCni0GqIXc4HBGTSr3Ba97oP6tDrX629ZafbWzgSQVqASTVWP+r7TlEZEhkeuvVsdES27EJ93IRDQUm2nUHWyPJUXtwpdKeRlgX68giSDRgF1LaQzHIb6zy96Aupkm0S1iTwRaDf7lQN+6rFJXC9TPrHubexNSekpm2cIu4sA3sbj7475mg484H5i3Wz3/UpHof6dm02deyc/6kjc21f16/sOJ7ol/B3vv2+qTvFEVFFzfbrF8GIV3ABgMoFfK2kw11IfyCly7STcJ5g5Qjg43iQppVB/nqFh7CoC+9acuCSztx8d3NJpyXkkpNYxAkBPCBlAY4dP8gakAMzU3aQCObgLAMv1uA6lESCf6ktOIOe6zuBwnSKCCdiGCdgzyPfWeZjLllzLjCC41mEb/tEamzaA3l+gye42ZpcUCE0kj6jXeRkRLps69wsA9yfwrND/7U/x6scDNJUTY2PbyMT1Z3R26ZjMFHfqyu3u0N7aXe39lB0n12+no90ydhxND1htBvx98/39Q7yuAw/4YiW6U3X+/Yd8X9qYwT3l+AAOm2/0ECGu1eu/zuMDb65CHO8/t1Xcuf1eyK92O0oADnP/fWDPX8GmUH/edw4WiQ5JYD/ff12on/j2o9o6AqgO113SYVTXOspISJd1GhnfOqyZ1mWHgODbYiMAU/A47TsNSqkVgdYg5BW4Xv8aeRXiiOBwKPP02OxVM+Z/06xuU2UYu1+gyupVF5i+a3Dyd3vvnIDi7h0zty1CQ0RM8MgEngikWC0nDgZbFcinI/TjbW2wJ8f9xb0DT58mHpI7Bskwbrrp6t64ndef2NV3iv397RToZ1PUusV9xucfh/xvKOfdy45D09fl+Hd4/LlX/+DNE3Uy12km5BPgnUPoU517x7n9nPfXEL32UilOe/27TOvcBEjT5+qe2m/TREq2N9Ay7FUEDsP/2+AngNLR1z/l7YEJ8NMDNwH+VioXDN1lwDC/jgYZHQLAREym0h/OwIVQj0BVu3Q4mAG3gIjJW2PK7ZeAbwm2rGlEoFpyrF6dKiGY1X4CcO07wNRfEAhUE/RS+sDUU6A2EhoGp9q06uIk4pDRCSuBZINuFLoq0JVAR4FvHLop8BcZ9iJDX2ToFrCS7gP81zmJuNfJ94UPsr8Z3ZFL3MPuyvcVtRf0rY/3ll18x3av0Xo4iEjm4sU+OPcFvh1wJ0T4pJq9jdVwH0R7zUF3RQpmvmv6mcp4bxTzppZdAICYUzz4nKlGP3n5eZ5mqlUUinxDAHRTEjwCv6MWmw9VfWDn7REM3np1PwTgbJq0AwCWuiMDagIGCpCpNkQEeAhoGgcxYEswE8OKoRAhLidln2hqqgEsuitRDesJ8LY+wF6Xp54BIqvailuYiISJ9OWrPCy7SD0o3AAbBExTncWGRkXZCOQzgawL5KqgDAplmpT8SekPdbicXY+182+l8E2BXRd4NtjGYa8Uui2wl37qJ7TyJgANwom4TV83mUmk2gcVDcj+mnD/jmdnFvbmGv5fpd0nzz9+7v8qw3zgTuV/f6DOXKxw9al9lg48/qlQfSaDW3m7gRwOiuS1SoodIF1rErov9NlUgqs5+U0bbwjTbQyTyp8mcY5uAH6s/ute7q5auWyu5++H/rvPNgBUI4vAs1BZ19WS4KHqP4M/K+g81VvXTMdfao2zlgEZ06iRpSLW8Uagx1OuT/UaNXvKu6F6ZCUgtmoF7tYZgZiYAadYwU11dKGIuRIQA8Mcc42/zlHQEOyzq7xtI4c+BWqA0AZQw0SOSiaLi8ZHQ9koyqdb5I2gXGfka0GhaSwCqjLvTNAykY3P6whGBs8GJ65ViFcCfynAegReFPhgtRtyvYbjDLYd4Hh6R+ceE5GoB0ZAojq1/Rycv0U96sSb+w/u0ZF+FoAHbvrp52G7+xErHf3d7QOHvkW4/8YGHveTwh3PZbspj597ke4Q+XwaGrw/PHe3bgr1gVlMuy3W7Yt9rtMdIH+t93+dbrCfJpgedvXt5/PHpTzd2++YCHT6fdWd31GAI6aObqDNRNbXVS3DaQBzAz+fKHkRkBcKJkV8XIsQxgyDg3pHIIAWXOv6dJNOgwAUN2GQwx3MFKZQwAieOibxWlyxBPdIFF5cD9suEC2aSG0K1AakhsHmsOIYm7OmHw15oxg/LcjrjPxKMK4KSuDazhswARvQXFUgRY0oVGvZsAKeYEOu6URqYGMdk+CD1J6GjmEbAb4/1HlxXhbgL68BnZ7h6wGOx8Af/tM6JuTuXv0pxgtUf9nKcUcU3oTDcF/8RI5/T+Np1N1xzf5t8/5jC8DJkXvHot5sp6bTussYb1fzf5PNoN9X46WOvL2rZj979Do5h4P2Gm+8jr4FBfhdRZNTLb63cv8pjCeZwvI4l+1qpBAjoHLTcjvvM7V07Dz+zfHrxY9TDz8zMJUCnWZOArAEiBS+iFUzpwSc5xpFdD3oLAJk4LMAuwRAjthNwvSyenJmAMQ7r46pKklqPoXfdU5pp3o7U2BLBLt+Oaz6SNSnhDYRtwGhYUoTsIfuom9Gw7hV5M8GjCvBcJUxrgpGr7l6AaDuMAZkD9iaFcaog3yYqveegK2pgW8NtpiAvVH4MsC2CqwF/s1LeBbghQH/01fcpxTxYJDXd74HwqO6PA/oqY9X3eat6vjhrnh5v4knUgX/a5X93Wnglue/q2Z/H7OJu9kPQ/L7TMV1rOTfF8z3EQKNbqv5dx1/FvmOphunQL5T760+za8r7QE3611rXq8GcKxXIwSay3vztIUVb0Soc4TSjdB3orln32aghziJeNNrApDCrlxVX0+hOHrSxBNCCX4+8VOXAHZwEqJFPZ51C3gAsMzgs6b20ncC7hgaGlhfleqwCJPgFmpI7kXJAmnU3Zgu59pFpw1R+ex6uFo0ISxS8iYiNIFiYoru0OIYzi76ZjAMW8Xw2YBhJRheZWzXFdgKhwRGmQbiGDGkKAyAcoAMCvU6QEhB0D1g29bgi0oAM7B9q/AjYPsMbGaGqnoIASIyz8UIVdul5T/4wQ/2B+XcgP3EPXv7Bp4YABz9Is69+/VvnRNOgh94vac/1cm3/7pmYoRwTCJ0N/hnMe+eg3R2dp8Reey+u/wHrb50cijujP19YLvW0tluG6u11oNtptExB8eaH/ojm6OEGy1h0gr2vg8fgX6OGEKYBwUBKVVvGblO00VT3ZlA3iiIDUwgLBhoWjImMrj7oiFKBWEZoQTQ0okXbRW+OgGlC+S2VJF/MQ2waVMNKHqGlwREdyc4IsiI3MgIXGcHUiayreLTpTs3zNRGpJYpRkZyRygObS76djBs14rhx1ts14LtqxHrjWA4ArYUhU7AVq+0LAgQCIQJus21Y44B3Ro8EWRBk7p+47F9LcA3L2FZ4JPHtj1gI4TgdwH7z/7sz+4cbfe2djrHZyKy1/i8djd8qpb0Gkwu1m4EPpvHZt4n198D/wziU9PRnGrbPW7rfVM77+vAz6hjs+Ib6vhva8cef/e+k9ecff97HWL3CzQguTjN4T4Feu0lCZFmPaA2nUzb1/eA2NJcinMieNOSTSq2N4ms0/pDYz0RsQHNgpXgtEiEWKqnXjTkkeALo8AEXzSknYKXCxgDoW+hCdDWJh5KMAICog3scJ5aYJlgHeptllfjj1KbqI9MDXtsAsWWKSVGaxXYm2Ub+sGw2Si2n2yxWQs2E7C3DggcxQkagDwBu0zAlgnYBQJlgmwzlBjKgK4U1rXQ1Rp+0UA2Ct+28MUAWwv8m+/Criqw/QSwZ4/tP0tgv8luj86bir7MATHWlt55zLS8TeI+NfPtRrMcT7G1e72vsPkc+82gPvZgt5/g48E7N8uAghBPRA1+/JmYQU+IbncCFcCtyT5uNeUce3v43WLCoapfz60qOftf+66Q3qeW4N23YT6pC06TfMxT/IOZEJo6ZVeMXKfLioQQ6siRENiJ4T2YuyULT1+rI6bIxD0odi0VBih08L4hY5CfGREzwrKBdgJeLmGBgADwokXpFUz1NS1aqKgJEzlbnbknEmmoV8BlNfykb1uL5NxHDg3XMDwxkjlJftw/K47NVrBZKV6sM9ZXGetVwWoCdoGjEJCJdh47T8AuDhQEFCh0dCgKZAJ22QO2TcC2U8BODfyHGf5b3zjUvX8RgP0mO/0TWqE6niZwAupVyg7A7Hb0PddZsh627s65/g7fRwRwUgOYPT/dvDxYfUqgm+PimSSmZbba+XxrNt69WTvIbz7SJpLYD/nvCuNfN9ruLW2n6hPtBT17G+xNoDFHBvOYeY433pyYQBETiHnuB/AU2EPDdV6tQB4T1/7vlhEje0dMdb5QRr9k65nBAPXg0HYkgUCPm0CJ4I+YPBBwliBTUyQFAiIQFj1KJwAzPALUdzDKpuyOSDAuxAyYR9KOAFmNn5+1qbQBKcJDFzgkRkxMjTmV/GjxqDjWW/H1VaH12rCagH29EawDI7ujWK2xFwZK9l0oPgM7u6EEgjihjLmKbBOwy+Sxy/YG2DoBWydgYwL2/hRQ9b7V+QWhehOSHeXYv9B2rxx/NyrhdRs18F2uzzzJwAxMYyNvEcD+8gEB0B3LB2e0twkd/t0tT0SwA/2M2KOSoWOKTuiwAejOgTf++vV3WXWbDneqf0Fzjl/rV5W0dgEP1bn1d1NioQ7PpamXlbmCOzQTsBWIbagTYUbyGNk5MCiQt8ah7YOBQIsYPRD8rE8cCN51kL4L2juHSOC+Jz0roGWEMkALQVguUYIDvdScu+lQAsF5MCOqEgFnUAB5NPeGCShl2zssELRN0RpCagKlyNS5Y8wX3Xk2X41K65Vi9ePsq6uM6+vsV1vFxg0F5JmAkcilKCsxxqIQdoweUJiQs0ECVaCPBbbnscvkscsrhS0DdMqxbQ/Yvgfsgwfrlx3Yb7LXAr/IHZ19MQDttCzAbrZdSkAq2OX6mDszaCqp3TFTT+DDYVFvsvtM62XzEN9AN4A+iNF9F+I7bra5L6BPRQSnwvyJ2+aQfu7Eo8R+86u7wTF5fgoEiqHWmYl2Ig8lVOCDEVqyEKZf2THy0LKnlr1FDEzwpg/exuhtD+84ha4nWWxjbC9ZEsEvmDwxdBHgiUG9oEkELHqUxKDYwNuC2LTInE1i/VlA50AayLFQYs7lZR8Q2sCeCKFPAQ1TDBXYOVsTsvp2MKyuC12vBddX4tfX2V9tCzYOKyDKTi4myE7IXENxcSAz86hKxRV5sBqCE0MYyNygZIMtUHPyCdiyU8XfhRwBezcd6+5pmeSgPWD73yRgv8l++mG5EQRlR4mENFavP4f8MsekuGnPOjal2lKrr9fkAGD3Ax37kcJukM5+3o69CS7uOtgUAbxNzX62OHns3aEOPrd+YpjAzrUHE5GmgtXUNB7YQUBsJmAzOxOBGnIKDCJynrx2CIwYyELDaMbYhUXIzITIhKYLFgncxeDtkq1DDGeeqHsSciLCOcEaBi8vIYmAXhAj1bHfEQBv65DPkIvHAbE/5+slOy8iSb/arhdN431i7mMIDVMTmFp3jLlt2qy+HgzXa8X1J2tcX41yfa30cjVi4wRxRwG8EDA4ITN4LF6B7QgZ0PEG2CHPwJ48dl4NsIsGeQRs28IWA2Qqd4lO4tn//FWImYGZfS53AQ/AfpPd0bkHIjIKkcKtXro+Autye6ckjtIS5pGaZKiDAqdtS4PdT2QffBhQa++YRnAwagYJwAU3U7hKBXw42tnt5j3DsfB2uP3+L+2y+vS5hyA+ZfMxafe/yZtP+1M9f0Lk2vfqWsU4QkAISBCqP0zhtZmGwSGCInlIjKgphT545Ei8DIUZCMRo+oA2hyaeUYkaUmqJm8IIQBOiW3NBuUMIiYGeIndg6y65XDAh1QlwkDZmLRN4ECV36gPpRQLO1q/Wj7og58vGz5uGlk2ITaAuMV2q+Vgcq5wW46C4vs6++vFGr68zXl2Jv1wLNu4QdyvOYc61swMjsY0wZA8hi0kWDcWBzPBMbMLwvFJo13JebYNdGPKYoFuFLXwCdvXYduSxD7LNfWBPYPdfJPHsF91uAT8FJmYiZkYXY8x2c7UPOGC/z3KHZ3EgEvLevEgl1b8NTnfP7e/aBKCEPbBO+6oDMeHg13fn39fb1wx4r449RxERN0OG52loQj7MFXbNO3tRw7zI5Du8MwEITCDCVC4LMcwROzjV2hgBkRZUAAIzhDUk7j0HjSmkiNBGjyFQalu0oUXTR0vLiAh41yWmIhw701QCt020lhFSnaFFWwZIlGLnFtdoE8PborqwXCIDy+u0etIRPx1eri4XMV1cNHbeNLxsOLaRu8TUV2A/5ayeB/HrjeD602u9vs7+6lW2F5viW0cVxNxoZGB0+FgcQswjwNmBcRASc8pKKCYoFH20QgWNl04lr7awrYieX7TjVuELRzkBbPutr+2AvbNhGLzrugeP/TOy+w/LPbl3qL+jF0G7IXAFdbZDAAcEAKC2Z0wmB657h3E0h28jG9DXWRgOJ7/YI4XZCACXCvj91OG4FFYCI6odePK4J/BwZKQKeCbUGpc6uH4XR4yTFg5wG2pXSWJwCAjMCF104pAiJ6QuIMWIiNhEgrdPek8rouZpsMYTtSD0qV6yxACrB+rJgkqI5khDoSap0mbrMRB6lvFZH+hLm83qvSfL7UWXmstlh7MmpiZwnwI9VfOx2DMdxFbZsNoUvf7JVbm6Hu3quvjng9DayQXg0c2LO4oz5SL/f3vnriTXkZzhP7OqzqV7ugcDYEAyMBA3hA0ZegQ5dPkCMvQCegZ5fAa6smTvk8hZQyGXoMRg7GqXwJDo6zlVlZUpo87cMAAXpCJExuL8Tvecvkw7X+U9j2ZiiiAkM46ikkQ4mbfMZjFyJxpzBnHugsX9CKtga9yRlZzNOl7mGIELQwpPYK8S7ADgi0/vdn3NYP+y+mljuVd1pN4Dx8nitg4orPDCgDOcwHCcCG3ecO1TuHke8OMaHdDdcs3ftXfpDeMN4jqtchVWEN3Mf15VG4IHuGG4Yhyu3e87jXG87AhJQa2rCfnA4ODBAFznzXFPxPVM8SctGgvwfTDfe7RtMK8BLQhdU386F6BrYAEgXgAuC3tLcFrgxgyXD9m72gjzTP7w8vHpwj09XR1O16v+Qe+x6s9C63kRHC+L2pjVaBSzKPZykLJ/eUybXSrbbbTvY7EjzMSYI8ikKEeYRYbFRCxQTWo8Simp1G3NiR0nE0ujmKDxuQuc9tGqxW5D3GUrOUfruORYkl2MpzkI7NUe+u1L2JefV6udc0YI4Q7YV674DPavRz8/udd7IHHdjrAAI3oDi2Fgvs74X/nsV3fX7VD3Mb1NmYGg9REA+unnvekBDFYPhKz3B7IB0PSB60em2mtgeYoC3HS9AYUMorY2laxq6cy13pgAZg9mwHcdPBG8a+F6Rx6uuuVto40GWroKd2BgCVjguhhCGWQZ8Eng8lDccYBj2Gkj8enwp82j9cI/e3Cyf3x2QovG96v+vGm964PjruhHj7LadhTlKPpqSGV3+TpudlG2u4jLsZTBDBlMCWZSjCJgkZliEmSAsrKNMkoqjrOKRWKLRJrZd+kYU+k8pc3BSiqmq3MZd7mUderLMZtGn+1iXKQgzfuCbcBfV7nrr13vHMslEBHXLnPDVMtXvevyN1P2LBagdYQI4OTWW/ZMgFSv4FpvHAZXagGAb8qEtxUni91elQhvDgRqcafxhdp6GFw3vTBVq00ATzVxR762oZ44+M7XfegM+ODhew+vLfzSme+YGjgN2tLCV4vdECjUs4S41ADHJUGbY2YClo7o0/SHlw9PmnDxYDGsF03zaNnSquub3rvOMS1FP3G56D6K0ShlN6byx8vXcbsdZLOL8kNUHKddONFgWdUSQBPYJkw0CCzDaIxZihpFYo4kmrlv4zEm7XwfN+OoZyvEvYkMUXXNvRwOos/PSt7GqMWyHvKFffsC+PLzOoQ5g/1h6K3JPZratYPjJt7ypGmMBlzfqa7q7vKzG2c5cnX7rzN1U4i3nwLr1uMmK/jm8ze+cDoM6NgApwko3U3xbiqPuSXb9c4yNMRrM5Yw3eZ5cslXZI7qTSD8wsOPAr/0CASEjqmB16A17vaT5XZZOLCgTTH7DCw80W9yBfvp6WI4uwK7bZsuuN4zdaK/fTiBXUYp342p7C73h+02lc1ukO+j2gA1MaZoallBCdDI5KLBYoEmM4oFSDBKg2YhpUjiMnccvXIassr+OOrZY477KDLETtdc5LDZ6fOzXrbxoMWyfv2y2BeffXoVX09grzGOY53L9jPYH6L+4r3zrhiPe6hZ0vufybgumreuAg/cstyZ6rUpqL/tEcDdGlarSTLk9ur/w6yZpikJ3HvjRzfJde46uNo1Bm5a8wS4lYOrkFswQjvF146qK97W18hTLQCEk+n1lOBjKd4pTkLST+W714+a4J8+6ON5CzxcdVg1bdsH1zumRvS3ZxVsvQV23G6TbPZDvhzVRlPLYEqmJKqSwC6y0WimsYAq2FISwGkosYINzdxR9OZSEi2bw76sH3bxWEoZSqdrJ3I4Jr1Yt6khtSKmX79MbwE73ALb48WLF/b8+fMZ7FnXeq8YfyzAmEEW5e3vv72Mo73ZfskVeMPSAyIVbF+/ggCg1DlL6j0xnDIAkpauLLdrGnVEcCuHYARHQBOAtq0WfGG1EaUL4DDB7af3cKnPWweUAeJdBb5pND2TYXfusvtkQeV85e2s8e60DeEG7ItlFt2PUo5RdDsm2b3ajdvdIJvdmC+jlngDtolWyxyJMCYpAkYyoyiiSQzJjBJxjgTOzIjeugp2Hst60Y3HRGXIna5PRA7HohfrkArBStPoN5f5HtjOOaSUZrBn/Wy9F/hFgKG53+Ry50LjQKFadcpce+kawNQzE4HhlJf+2mJT09bJrdLUnnFPcADaFrbQCnQfwJ6BpgECAd0S0gzwnurfnmuLezjWop5j4MQDS9L48dLkSSt4esLxQQP3ILDrPPeOeSG6oCxlP4oeo5TdmGX7X/thux3iZj+WV0PKkdhlgJLBRFUTiCIRV7BtAttiEqFkTIkU0Rwl7yjt91paR3F/HHT9oBmPScoQO10jyiGKXlwsUhFYOTb6zWEGe9b/v96e3KvjleA34nlug/AevkbpoSbQvK9JM+fh+pAJAEfvuGNiC4WXxI4dHIH7vVPPQLcGewKvEswz0DbVOi/rfc4pTAm0jlD8lJTHEXB7UOtRVqzxo8bkvBU86VnPe+gE9qJabEpZLI5C+yiyG4+y/TrKdhfTdjeWywo2JSlQMowgRIASEcakJmYUIZbugi3RXEheJe0HLW3XxP0xTWDnMuRO+2HIqahdXCBFeWSFvX5zKPbFZ89nsGf9qvSjFr/xromK6+RY6xrXLU7hpvkW1zfZIXhHAPctOcehhYMnoM/QpofvW0h3gGsbIPSgdoHSjpPbfQpqEuQabAM6D6ycxidBy5O22F8Ce8yyi0fZvoh5uxvTdhfL5TGWbLBa1oImBx6uwc4mxhqLaDJBEtNk6hOxRHNIXuk9wR6t8FG/OUT74rPP3gl227Yz2LN+dXrHPH5dPzjdJRsstYz14KQhTzBtG2JmNHBh5euhcNJBPAF9RO0dR12wGAjOOxQ3rUhuR2Dl9PgkaPmoVfvkIaVHDfE6kO8D90TUSEGSQsModLgC++so2+0YJ7BzrjE2J9WSHfNgxrXclU3MSiymKRcVEEZTJGJEU9y44l0T98dBjyRl1TfjkIv2A89gz/og9KNZfXZEjmGrHvo3Brd0AUMXqGsgzQR426O0Ec6O9QBYP8a42pTh4ybbxwsujxZE7wYb+zHJ7njIu+9S2WyHuD2M+ftjLvfABtyNxTaLxTSlIpkIsahEx5RMkVLRooVS2zVxP6S7YMt9sGOM9i//MIM968PSPfC7lgtRycFxQjEigE4VzjewxyO0eYR0+mrcPurJf7yg8tECsg5oToPzXeAFEfXyCZmUsBul3AF7E9PmeEw//F/AHnMRGOf7YMs12Nsh6/PHY74C+3+2g335+efXDSrMbM45xBhnsGd9kLoD/t/+/SAdnmXvbDTSg8Limbf8T+f6umV0zTPXMaHLTxpNovtUym5IWsGOZbtJFexRNJaiBcyJjCJI411XvIKtqrFA808HO/5ksIG5QWXWrCvds/gqr6Pyg40q/XlM+u2ft8N/jGLjkGR3GNPl5RB/iKkkYkqqlk0p3wdb3wDbIpOPsJJNJUVxb4mx3w/s6WcagBnsWbN+pvztkbRSSv7nf/v3iId47dvw3y9ebuWPr4//ueh8Y4ClbNlMY8oqFWz8KNib/bFEV3TVN+N2PJa1eUnFbDsMM9izZv2CumPxnXP2j7/7XcT4d6/5zITRbHZjXBWwyzkjFy1vgn32sI1jknIb7IsLSVFGw12wb89jz2DPmvUL6l43nlndP/Gvv/99+/2fmvbhSeuCY8pFLYvaTVZc7OXxqNt4Xe66PbpzZ4jvCmwAM9izZv0KdA/8r776Cufn59T3PUIIpHWXPl1NcE2awZ41a9asWbNmzZo161et/wXHz8OvsqLhjQAAAABJRU5ErkJggg==";
|
|
14
12
|
const DEFAULT_PARAMS = {
|
|
15
13
|
...LIFETIME_DEFAULTS,
|
|
14
|
+
playbackMode: "follow",
|
|
16
15
|
orientation: "horizontal",
|
|
16
|
+
showGlow: true,
|
|
17
|
+
showOuter: true,
|
|
18
|
+
showCore: true,
|
|
17
19
|
orbitRadius: 0,
|
|
18
20
|
orbitSpeed: 7,
|
|
19
21
|
height: 0,
|
|
20
22
|
// 默认 0:真实跟随挂点(orbit>0 是演示用的幻影圆周轨道)
|
|
21
|
-
trailLength:
|
|
23
|
+
trailLength: 32,
|
|
22
24
|
worldLength: 4,
|
|
23
25
|
width: 1.01,
|
|
24
26
|
coreWidth: 0.4,
|
|
25
|
-
tailFadeStrength: 0
|
|
27
|
+
tailFadeStrength: 0,
|
|
26
28
|
tailFadeExponent: 1.35,
|
|
29
|
+
edgeSoftness: 0.16,
|
|
27
30
|
opacity: 1.35,
|
|
28
31
|
saturation: 1.45,
|
|
29
32
|
contrast: 1.32,
|
|
@@ -31,10 +34,12 @@ const DEFAULT_PARAMS = {
|
|
|
31
34
|
bloom: 0.9,
|
|
32
35
|
blendMode: "add",
|
|
33
36
|
flowSpeed: 5,
|
|
34
|
-
sparkRate: 20,
|
|
35
37
|
tint: { r: 0.4, g: 0.85, b: 1 }
|
|
36
38
|
// 青色能量,配新武器发光风
|
|
37
39
|
};
|
|
40
|
+
const TEXTURE_U_MIN = 0;
|
|
41
|
+
const TEXTURE_U_MAX = 1;
|
|
42
|
+
const HISTORY_DISTANCE_MARGIN = 1.4;
|
|
38
43
|
const TRAIL_VERTEX = `precision highp float;
|
|
39
44
|
attribute vec3 position;
|
|
40
45
|
attribute vec2 uv;
|
|
@@ -53,6 +58,7 @@ uniform float uContrast;
|
|
|
53
58
|
uniform float uAlphaScale;
|
|
54
59
|
uniform float uAlphaPower;
|
|
55
60
|
uniform float uBright;
|
|
61
|
+
uniform float uEdgeSoftness;
|
|
56
62
|
uniform float uTime;
|
|
57
63
|
uniform float uFlowSpeed;
|
|
58
64
|
void main(){
|
|
@@ -67,6 +73,8 @@ void main(){
|
|
|
67
73
|
float band = smoothstep(0.0, 0.12, phase) * (1.0 - smoothstep(0.12, 0.4, phase));
|
|
68
74
|
color *= 1.0 + band * 0.6 * step(0.0001, uFlowSpeed);
|
|
69
75
|
float alpha = pow(clamp(base.a, 0.0, 1.0), uAlphaPower) * vColor.a * uAlphaScale;
|
|
76
|
+
float edge = min(vUv.y, 1.0 - vUv.y);
|
|
77
|
+
alpha *= mix(1.0, smoothstep(0.0, max(0.0001, uEdgeSoftness), edge), step(0.0001, uEdgeSoftness));
|
|
70
78
|
gl_FragColor = vec4(color, clamp(alpha, 0.0, 1.0));
|
|
71
79
|
}`;
|
|
72
80
|
let shadersRegistered = false;
|
|
@@ -97,22 +105,26 @@ const weaponTrailEffectPackage = {
|
|
|
97
105
|
defaultParams: DEFAULT_PARAMS,
|
|
98
106
|
debugParams: [
|
|
99
107
|
...LIFETIME_DEBUG_PARAMS,
|
|
108
|
+
{ key: "playbackMode", label: "播放方式", kind: "enum", options: [
|
|
109
|
+
{ value: "follow", label: "跟随挂点" },
|
|
110
|
+
{ value: "orbit", label: "环绕预览" }
|
|
111
|
+
] },
|
|
100
112
|
{ key: "orientation", label: "拖尾朝向", kind: "enum", options: [
|
|
101
113
|
{ value: "horizontal", label: "水平面" },
|
|
102
114
|
{ value: "vertical", label: "竖直" }
|
|
103
115
|
] },
|
|
116
|
+
{ key: "showGlow", label: "显示外晕层", kind: "boolean" },
|
|
117
|
+
{ key: "showOuter", label: "显示主带层", kind: "boolean" },
|
|
118
|
+
{ key: "showCore", label: "显示亮芯层", kind: "boolean" },
|
|
104
119
|
{ key: "orbitRadius", label: "环绕半径", kind: "scale", min: 0, max: 5, step: 0.05 },
|
|
105
120
|
{ key: "orbitSpeed", label: "环绕速度", kind: "number", min: 0, max: 20, step: 0.1 },
|
|
106
|
-
{ key: "
|
|
107
|
-
{ key: "trailLength", label: "拖尾段数", kind: "number", min: 4, max: 48, step: 1 },
|
|
121
|
+
{ key: "trailLength", label: "拖尾段数", kind: "number", min: 4, max: 72, step: 1 },
|
|
108
122
|
{ key: "worldLength", label: "拖尾长度", kind: "scale", min: 0.5, max: 12, step: 0.1 },
|
|
109
123
|
{ key: "width", label: "拖尾宽度", kind: "scale", min: 0.1, max: 4, step: 0.01 },
|
|
110
124
|
{ key: "coreWidth", label: "亮芯宽度比", kind: "number", min: 0, max: 1, step: 0.01 },
|
|
111
125
|
{ key: "tailFadeStrength", label: "尾部淡出强度", kind: "number", min: 0, max: 1, step: 0.01 },
|
|
112
126
|
{ key: "tailFadeExponent", label: "尾部淡出曲线", kind: "number", min: 0.2, max: 4, step: 0.05 },
|
|
113
|
-
{ key: "
|
|
114
|
-
{ key: "saturation", label: "饱和度", kind: "number", min: 0, max: 3, step: 0.01 },
|
|
115
|
-
{ key: "contrast", label: "对比度", kind: "number", min: 0, max: 3, step: 0.01 },
|
|
127
|
+
{ key: "edgeSoftness", label: "横向软边", kind: "number", min: 0, max: 0.45, step: 0.01 },
|
|
116
128
|
{ key: "bright", label: "亮度(HDR)", kind: "number", min: 0.2, max: 4, step: 0.05 },
|
|
117
129
|
{ key: "bloom", label: "辉光强度", kind: "number", min: 0, max: 3, step: 0.05 },
|
|
118
130
|
{ key: "blendMode", label: "混合模式", kind: "enum", options: [
|
|
@@ -120,7 +132,6 @@ const weaponTrailEffectPackage = {
|
|
|
120
132
|
{ value: "combine", label: "正常(实心刃)" }
|
|
121
133
|
] },
|
|
122
134
|
{ key: "flowSpeed", label: "能量流动速度", kind: "number", min: 0, max: 4, step: 0.05 },
|
|
123
|
-
{ key: "sparkRate", label: "刃头火花/秒", kind: "number", min: 0, max: 80, step: 1 },
|
|
124
135
|
{ key: "tint", label: "颜色", kind: "color" }
|
|
125
136
|
],
|
|
126
137
|
create({ scene, root, position, params, renderingGroupId }) {
|
|
@@ -135,7 +146,7 @@ const weaponTrailEffectPackage = {
|
|
|
135
146
|
function makeMat(name, tint, bright) {
|
|
136
147
|
const m = new ShaderMaterial(name, scene, { vertex: "vfxWeaponTrail", fragment: "vfxWeaponTrail" }, {
|
|
137
148
|
attributes: ["position", "uv", "color"],
|
|
138
|
-
uniforms: ["worldViewProjection", "uTint", "uSaturation", "uContrast", "uAlphaScale", "uAlphaPower", "uBright", "uTime", "uFlowSpeed"],
|
|
149
|
+
uniforms: ["worldViewProjection", "uTint", "uSaturation", "uContrast", "uAlphaScale", "uAlphaPower", "uBright", "uEdgeSoftness", "uTime", "uFlowSpeed"],
|
|
139
150
|
samplers: ["mainTex"],
|
|
140
151
|
needAlphaBlending: true
|
|
141
152
|
});
|
|
@@ -146,6 +157,7 @@ const weaponTrailEffectPackage = {
|
|
|
146
157
|
m.setFloat("uAlphaScale", params.opacity);
|
|
147
158
|
m.setFloat("uAlphaPower", 0.82);
|
|
148
159
|
m.setFloat("uBright", bright);
|
|
160
|
+
m.setFloat("uEdgeSoftness", params.edgeSoftness);
|
|
149
161
|
m.setFloat("uTime", 0);
|
|
150
162
|
m.setFloat("uFlowSpeed", params.flowSpeed);
|
|
151
163
|
m.alphaMode = blend;
|
|
@@ -156,9 +168,14 @@ const weaponTrailEffectPackage = {
|
|
|
156
168
|
}
|
|
157
169
|
const tintC = new Color3(params.tint.r, params.tint.g, params.tint.b);
|
|
158
170
|
const coreC = Color3.Lerp(tintC, new Color3(1, 1, 1), 0.75);
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const
|
|
171
|
+
const bloomBoost = 1 + Math.max(0, params.bloom) * 0.25;
|
|
172
|
+
const hasOuter = params.showOuter !== false;
|
|
173
|
+
const hasCore = params.showCore !== false && params.coreWidth > 1e-3;
|
|
174
|
+
const hasGlow = params.showGlow !== false && params.bloom > 1e-3;
|
|
175
|
+
const outerMat = hasOuter ? makeMat("vfx_weaponTrail_outerMat", tintC, params.bright * bloomBoost) : null;
|
|
176
|
+
const coreMat = hasCore ? makeMat("vfx_weaponTrail_coreMat", coreC, params.bright * 1.6 * bloomBoost) : null;
|
|
177
|
+
const glowMat = hasGlow ? makeMat("vfx_weaponTrail_glowMat", tintC, params.bright) : null;
|
|
178
|
+
if (glowMat) glowMat.setFloat("uAlphaScale", params.opacity * 0.42 * Math.min(2.2, params.bloom));
|
|
162
179
|
function makeMesh(name, mat, ai) {
|
|
163
180
|
const m = new Mesh(name, scene);
|
|
164
181
|
m.material = mat;
|
|
@@ -170,63 +187,89 @@ const weaponTrailEffectPackage = {
|
|
|
170
187
|
m.alphaIndex = ai;
|
|
171
188
|
return m;
|
|
172
189
|
}
|
|
173
|
-
const
|
|
190
|
+
const glow = hasGlow ? makeMesh("vfx_weaponTrail_glow", glowMat, 9) : null;
|
|
191
|
+
const outer = hasOuter ? makeMesh("vfx_weaponTrail_outer", outerMat, 10) : null;
|
|
174
192
|
const core = hasCore ? makeMesh("vfx_weaponTrail_core", coreMat, 11) : null;
|
|
175
|
-
let glow = null;
|
|
176
|
-
if (params.bloom > 0) {
|
|
177
|
-
glow = new GlowLayer("vfx_weaponTrail_glow", scene, { blurKernelSize: 48 });
|
|
178
|
-
glow.intensity = params.bloom;
|
|
179
|
-
glow.addIncludedOnlyMesh(outer);
|
|
180
|
-
glow.referenceMeshToUseItsOwnMaterial(outer);
|
|
181
|
-
if (core) {
|
|
182
|
-
glow.addIncludedOnlyMesh(core);
|
|
183
|
-
glow.referenceMeshToUseItsOwnMaterial(core);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
let sparkPs = null;
|
|
187
|
-
const sparkEmitter = new Vector3();
|
|
188
|
-
if (params.sparkRate > 0) {
|
|
189
|
-
const c255 = `${Math.round(params.tint.r * 255)},${Math.round(params.tint.g * 255)},${Math.round(params.tint.b * 255)}`;
|
|
190
|
-
const flare = makeFlareTexture(scene, "vfx_weaponTrail_sparkTex", "255,255,255", c255);
|
|
191
|
-
sparkPs = new ParticleSystem("vfx_weaponTrail_sparks", 160, scene);
|
|
192
|
-
sparkPs.renderingGroupId = rgid;
|
|
193
|
-
sparkPs.particleTexture = flare;
|
|
194
|
-
sparkPs.emitter = sparkEmitter;
|
|
195
|
-
sparkPs.minSize = 0.07;
|
|
196
|
-
sparkPs.maxSize = 0.26;
|
|
197
|
-
sparkPs.minLifeTime = 0.12;
|
|
198
|
-
sparkPs.maxLifeTime = 0.4;
|
|
199
|
-
sparkPs.emitRate = params.sparkRate;
|
|
200
|
-
sparkPs.blendMode = ParticleSystem.BLENDMODE_ADD;
|
|
201
|
-
sparkPs.minEmitPower = 0.6;
|
|
202
|
-
sparkPs.maxEmitPower = 2.4;
|
|
203
|
-
sparkPs.direction1 = new Vector3(-1, -0.6, -1);
|
|
204
|
-
sparkPs.direction2 = new Vector3(1, 0.6, 1);
|
|
205
|
-
sparkPs.gravity = new Vector3(0, -3, 0);
|
|
206
|
-
sparkPs.color1 = new Color4(params.tint.r, params.tint.g, params.tint.b, 1);
|
|
207
|
-
sparkPs.color2 = new Color4(1, 1, 1, 1);
|
|
208
|
-
sparkPs.colorDead = new Color4(params.tint.r, params.tint.g, params.tint.b, 0);
|
|
209
|
-
sparkPs.start();
|
|
210
|
-
}
|
|
211
193
|
const targetCount = Math.max(2, Math.round(params.trailLength));
|
|
212
194
|
const raw = [];
|
|
213
195
|
const points = [];
|
|
214
|
-
for (let i = 0; i < 96; i++) raw.push(sample());
|
|
215
196
|
for (let i = 0; i < targetCount; i++) points.push(sample());
|
|
197
|
+
const pointPathT = [];
|
|
216
198
|
let rawCount = 0, angle = 0, time = 0;
|
|
217
|
-
let outerInit = false, coreInit = false;
|
|
199
|
+
let outerInit = false, coreInit = false, glowInit = false;
|
|
218
200
|
const cur = sample();
|
|
219
201
|
const mountPos = new Vector3();
|
|
220
202
|
const lastWidthAxis = new Vector3(0, 0, 1);
|
|
221
203
|
const tmpDir = new Vector3();
|
|
204
|
+
const tailDir = new Vector3(1, 0, 0);
|
|
222
205
|
const UP = new Vector3(0, 1, 0);
|
|
223
206
|
const positions = [], uvs = [], colors = [], indices = [];
|
|
207
|
+
function resolvePlaybackMode() {
|
|
208
|
+
if (params.playbackMode === "follow" || params.playbackMode === "orbit") return params.playbackMode;
|
|
209
|
+
return params.orbitRadius > 0 ? "orbit" : "follow";
|
|
210
|
+
}
|
|
211
|
+
function sampleMinDistance() {
|
|
212
|
+
return Math.max(3e-3, Math.min(0.04, params.worldLength / Math.max(16, targetCount * 3)));
|
|
213
|
+
}
|
|
214
|
+
function ensureRawCapacity(length) {
|
|
215
|
+
while (raw.length < length) raw.push(sample());
|
|
216
|
+
}
|
|
217
|
+
function resolveTailDirection() {
|
|
218
|
+
if (rawCount >= 2) {
|
|
219
|
+
const tail = raw[rawCount - 1].position;
|
|
220
|
+
const newer = raw[rawCount - 2].position;
|
|
221
|
+
tailDir.set(tail.x - newer.x, tail.y - newer.y, tail.z - newer.z);
|
|
222
|
+
if (tailDir.lengthSquared() > 1e-8) {
|
|
223
|
+
tailDir.normalize();
|
|
224
|
+
return tailDir;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const axis = rawCount > 0 ? raw[rawCount - 1].widthAxis : lastWidthAxis;
|
|
228
|
+
Vector3.CrossToRef(UP, axis, tailDir);
|
|
229
|
+
if (tailDir.lengthSquared() > 1e-8) {
|
|
230
|
+
tailDir.normalize();
|
|
231
|
+
return tailDir;
|
|
232
|
+
}
|
|
233
|
+
tailDir.set(1, 0, 0);
|
|
234
|
+
return tailDir;
|
|
235
|
+
}
|
|
236
|
+
function extrapolateTailSample(targetDist, availableDist, out) {
|
|
237
|
+
const tail = raw[rawCount - 1];
|
|
238
|
+
copySample(tail, out);
|
|
239
|
+
const extra = Math.max(0, targetDist - availableDist);
|
|
240
|
+
const dir = resolveTailDirection();
|
|
241
|
+
out.position.x += dir.x * extra;
|
|
242
|
+
out.position.y += dir.y * extra;
|
|
243
|
+
out.position.z += dir.z * extra;
|
|
244
|
+
}
|
|
245
|
+
function trimRawHistory() {
|
|
246
|
+
const maxDistance = Math.max(1, params.worldLength * HISTORY_DISTANCE_MARGIN + params.width * 2);
|
|
247
|
+
let total = 0;
|
|
248
|
+
let keep = rawCount;
|
|
249
|
+
for (let i = 0; i < rawCount - 1; i++) {
|
|
250
|
+
total += Vector3.Distance(raw[i].position, raw[i + 1].position);
|
|
251
|
+
if (total >= maxDistance) {
|
|
252
|
+
keep = i + 2;
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
rawCount = Math.min(rawCount, keep);
|
|
257
|
+
}
|
|
258
|
+
function insertRawSample(src) {
|
|
259
|
+
ensureRawCapacity(rawCount + 1);
|
|
260
|
+
for (let i = rawCount; i > 0; i--) copySample(raw[i - 1], raw[i]);
|
|
261
|
+
copySample(src, raw[0]);
|
|
262
|
+
rawCount += 1;
|
|
263
|
+
trimRawHistory();
|
|
264
|
+
}
|
|
224
265
|
function sampleEmitter(out) {
|
|
266
|
+
const playbackMode = resolvePlaybackMode();
|
|
267
|
+
const orbitRadius = playbackMode === "orbit" ? params.orbitRadius : 0;
|
|
225
268
|
const c = Math.cos(angle), s = Math.sin(angle);
|
|
226
269
|
out.position.set(
|
|
227
|
-
mountPos.x + c *
|
|
270
|
+
mountPos.x + c * orbitRadius,
|
|
228
271
|
mountPos.y + params.height,
|
|
229
|
-
mountPos.z + s *
|
|
272
|
+
mountPos.z + s * orbitRadius
|
|
230
273
|
);
|
|
231
274
|
if (params.orientation === "vertical") {
|
|
232
275
|
out.widthAxis.set(0, 1, 0);
|
|
@@ -245,17 +288,29 @@ const weaponTrailEffectPackage = {
|
|
|
245
288
|
}
|
|
246
289
|
out.widthAxis.copyFrom(lastWidthAxis);
|
|
247
290
|
}
|
|
291
|
+
function historyArcLength() {
|
|
292
|
+
let total = 0;
|
|
293
|
+
for (let i = 0; i < rawCount - 1; i++) total += Vector3.Distance(raw[i].position, raw[i + 1].position);
|
|
294
|
+
return total;
|
|
295
|
+
}
|
|
248
296
|
function resample() {
|
|
249
297
|
if (rawCount <= 0) return;
|
|
250
|
-
const
|
|
298
|
+
const historyLen = historyArcLength();
|
|
299
|
+
const target = Math.max(1e-3, Math.min(params.worldLength, historyLen));
|
|
251
300
|
let seg = 0, distBefore = 0;
|
|
252
301
|
for (let i = 0; i < targetCount; i++) {
|
|
253
302
|
const t = points[i];
|
|
254
|
-
|
|
303
|
+
const normalizedDist = i / (targetCount - 1);
|
|
304
|
+
const targetDist = target * normalizedDist;
|
|
305
|
+
pointPathT[i] = normalizedDist;
|
|
306
|
+
if (i === 0) {
|
|
255
307
|
copySample(raw[0], t);
|
|
256
308
|
continue;
|
|
257
309
|
}
|
|
258
|
-
|
|
310
|
+
if (rawCount === 1) {
|
|
311
|
+
extrapolateTailSample(targetDist, 0, t);
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
259
314
|
let found = false;
|
|
260
315
|
while (seg < rawCount - 1) {
|
|
261
316
|
const l = raw[seg], r = raw[seg + 1];
|
|
@@ -272,7 +327,7 @@ const weaponTrailEffectPackage = {
|
|
|
272
327
|
distBefore += segLen;
|
|
273
328
|
seg++;
|
|
274
329
|
}
|
|
275
|
-
if (!found)
|
|
330
|
+
if (!found) extrapolateTailSample(targetDist, distBefore, t);
|
|
276
331
|
}
|
|
277
332
|
}
|
|
278
333
|
function buildRibbon(mesh, halfWidth, wasInit) {
|
|
@@ -283,8 +338,10 @@ const weaponTrailEffectPackage = {
|
|
|
283
338
|
for (let i = 0; i < targetCount; i++) {
|
|
284
339
|
const s = points[i];
|
|
285
340
|
const t = i / (targetCount - 1);
|
|
286
|
-
const
|
|
287
|
-
const
|
|
341
|
+
const pathT = pointPathT[i] ?? t;
|
|
342
|
+
const u = TEXTURE_U_MIN + (TEXTURE_U_MAX - TEXTURE_U_MIN) * pathT;
|
|
343
|
+
const tailAlpha = Math.max(0, 1 - Math.pow(pathT, params.tailFadeExponent) * params.tailFadeStrength);
|
|
344
|
+
const alpha = tailAlpha;
|
|
288
345
|
const ox = s.widthAxis.x * halfWidth, oy = s.widthAxis.y * halfWidth, oz = s.widthAxis.z * halfWidth;
|
|
289
346
|
positions.push(s.position.x + ox, s.position.y + oy, s.position.z + oz, s.position.x - ox, s.position.y - oy, s.position.z - oz);
|
|
290
347
|
uvs.push(u, 0, u, 1);
|
|
@@ -313,22 +370,19 @@ const weaponTrailEffectPackage = {
|
|
|
313
370
|
const observer = scene.onBeforeRenderObservable.add(() => {
|
|
314
371
|
const dt = Math.min(scene.getEngine().getDeltaTime() / 1e3, 0.05);
|
|
315
372
|
time += dt;
|
|
316
|
-
angle += params.orbitSpeed * dt;
|
|
373
|
+
if (resolvePlaybackMode() === "orbit") angle += params.orbitSpeed * dt;
|
|
317
374
|
root.computeWorldMatrix(true);
|
|
318
375
|
mountPos.copyFrom(root.getAbsolutePosition());
|
|
319
376
|
sampleEmitter(cur);
|
|
320
|
-
if (rawCount === 0 || Vector3.Distance(cur.position, raw[0].position) >
|
|
321
|
-
for (let i = Math.min(rawCount, raw.length - 1); i > 0; i--) copySample(raw[i - 1], raw[i]);
|
|
322
|
-
copySample(cur, raw[0]);
|
|
323
|
-
rawCount = Math.min(rawCount + 1, raw.length);
|
|
324
|
-
}
|
|
377
|
+
if (rawCount === 0 || Vector3.Distance(cur.position, raw[0].position) > sampleMinDistance()) insertRawSample(cur);
|
|
325
378
|
resample();
|
|
326
379
|
const halfW = params.width * 0.5;
|
|
327
|
-
|
|
380
|
+
if (glow) glowInit = buildRibbon(glow, halfW * 2.2, glowInit);
|
|
381
|
+
if (outer) outerInit = buildRibbon(outer, halfW, outerInit);
|
|
328
382
|
if (core) coreInit = buildRibbon(core, halfW * params.coreWidth, coreInit);
|
|
329
|
-
outerMat
|
|
383
|
+
outerMat?.setFloat("uTime", time);
|
|
330
384
|
coreMat?.setFloat("uTime", time);
|
|
331
|
-
|
|
385
|
+
glowMat?.setFloat("uTime", time);
|
|
332
386
|
});
|
|
333
387
|
let disposed = false;
|
|
334
388
|
let ltTimer = 0;
|
|
@@ -337,11 +391,10 @@ const weaponTrailEffectPackage = {
|
|
|
337
391
|
disposed = true;
|
|
338
392
|
if (ltTimer) window.clearTimeout(ltTimer);
|
|
339
393
|
scene.onBeforeRenderObservable.remove(observer);
|
|
340
|
-
sparkPs?.stop();
|
|
341
|
-
sparkPs?.dispose();
|
|
342
394
|
glow?.dispose();
|
|
343
|
-
|
|
344
|
-
|
|
395
|
+
glowMat?.dispose();
|
|
396
|
+
outer?.dispose();
|
|
397
|
+
outerMat?.dispose();
|
|
345
398
|
core?.dispose();
|
|
346
399
|
coreMat?.dispose();
|
|
347
400
|
tex.dispose();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-
|
|
1
|
+
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
2
2
|
const schemaVersion = "vfx-effect-package/1.0";
|
|
3
3
|
const id = "build.particle.wood_crusher_sawdust";
|
|
4
4
|
const name = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-
|
|
1
|
+
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
2
2
|
const schemaVersion = "vfx-effect-package/1.0";
|
|
3
3
|
const id = "build.particle.wood_cutter_sawdust";
|
|
4
4
|
const name = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-
|
|
1
|
+
import { c as createManifestRuntimeEffectPackage } from "../../chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
2
2
|
const schemaVersion = "vfx-effect-package/1.0";
|
|
3
3
|
const id = "build.material.wood_peel_material_test";
|
|
4
4
|
const name = {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { V, c, a } from "./chunks/rendering-CV3nhygX.js";
|
|
2
2
|
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
|
|
3
3
|
import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
|
|
4
|
-
import { c as c2, c as c3 } from "./chunks/manifestRuntimePackage-
|
|
4
|
+
import { c as c2, c as c3 } from "./chunks/manifestRuntimePackage-Vgh-cH5X.js";
|
|
5
5
|
import { c as c4, f, a as a2, s } from "./chunks/legacy-particle-runtime-CbJYVxdd.js";
|
|
6
6
|
const VFX_GENERATION_PARAM_KEYS = {
|
|
7
7
|
offsetX: "__generation.offsetX",
|
package/dist/types.d.ts
CHANGED
|
@@ -22,14 +22,14 @@ export interface VfxResolvedInputs {
|
|
|
22
22
|
target?: AbstractMesh;
|
|
23
23
|
scalars?: Record<string, () => number>;
|
|
24
24
|
}
|
|
25
|
-
export type VfxParamValue = number | string | VfxColorValue;
|
|
25
|
+
export type VfxParamValue = number | string | boolean | VfxColorValue;
|
|
26
26
|
export type VfxParamValues = Record<string, VfxParamValue>;
|
|
27
27
|
export interface VfxColorValue {
|
|
28
28
|
r: number;
|
|
29
29
|
g: number;
|
|
30
30
|
b: number;
|
|
31
31
|
}
|
|
32
|
-
export type VfxParamKind = 'number' | 'color' | 'enum' | 'opacity' | 'lifetime' | 'scale';
|
|
32
|
+
export type VfxParamKind = 'number' | 'boolean' | 'color' | 'enum' | 'opacity' | 'lifetime' | 'scale';
|
|
33
33
|
export interface VfxParamDefinitionBase {
|
|
34
34
|
key: string;
|
|
35
35
|
label: string;
|
|
@@ -45,6 +45,9 @@ export interface VfxNumberParamDefinition extends VfxParamDefinitionBase {
|
|
|
45
45
|
export interface VfxColorParamDefinition extends VfxParamDefinitionBase {
|
|
46
46
|
kind: 'color';
|
|
47
47
|
}
|
|
48
|
+
export interface VfxBooleanParamDefinition extends VfxParamDefinitionBase {
|
|
49
|
+
kind: 'boolean';
|
|
50
|
+
}
|
|
48
51
|
export interface VfxEnumParamOption {
|
|
49
52
|
value: string;
|
|
50
53
|
label: string;
|
|
@@ -53,7 +56,7 @@ export interface VfxEnumParamDefinition extends VfxParamDefinitionBase {
|
|
|
53
56
|
kind: 'enum';
|
|
54
57
|
options: VfxEnumParamOption[];
|
|
55
58
|
}
|
|
56
|
-
export type VfxParamDefinition = VfxNumberParamDefinition | VfxColorParamDefinition | VfxEnumParamDefinition;
|
|
59
|
+
export type VfxParamDefinition = VfxNumberParamDefinition | VfxColorParamDefinition | VfxBooleanParamDefinition | VfxEnumParamDefinition;
|
|
57
60
|
export interface VfxEffectPackageContext<PParams extends VfxParamValues = VfxParamValues> {
|
|
58
61
|
scene: Scene;
|
|
59
62
|
root: TransformNode;
|
package/package.json
CHANGED