@fps-games/vfx 0.3.4 → 0.3.5
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 +12 -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/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/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/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,18 @@
|
|
|
12
12
|
|
|
13
13
|
<!-- release.mjs 在此行下方插入新版本区块 -->
|
|
14
14
|
|
|
15
|
+
## v0.3.5 — 2026-07-01
|
|
16
|
+
|
|
17
|
+
### 改动
|
|
18
|
+
- fix(weapon-trail): 拖尾按实际历史弧长映射,消除运动采样不足导致的截断
|
|
19
|
+
- feat(weapon-trail): refine layered trail controls
|
|
20
|
+
- feat(weapon-trail): 默认关闭刃头火花 (sparkRate 20→0)
|
|
21
|
+
- feat(weapon-trail): 软边加色外晕 ribbon 替代 GlowLayer 的柔光晕
|
|
22
|
+
- perf(weapon-trail): 去掉 per-instance GlowLayer,bloom 折进 additive 亮度 (#11 L-D)
|
|
23
|
+
|
|
24
|
+
### 特效
|
|
25
|
+
- 无新增 / 删除(仍 37 个)。
|
|
26
|
+
|
|
15
27
|
## v0.3.4 — 2026-06-30
|
|
16
28
|
|
|
17
29
|
### 改动
|
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,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 = {
|
|
@@ -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,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";
|
|
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