FlowingFireworks3DPass 与 FlowingLight3DPass 配套使用,在每条流光线条的「尾部位置」(渐变淡出处)持续喷射出烟花状向四周发散的粒子,适合为流光拖尾增加飞溅火花、星点爆裂等增强效果。FlowingFireworks3DPass 类及 FireworksLine 数据结构。Definition: FlowingFireworks3DPass
FlowingFireworks3DPass 继承自 FivePass,与 FlowingLight3DPass 共享同一套线条数据结构(points / totalLength / duration / startTime / tailLengthRatio),并额外提供烟花粒子调优参数。核心接口如下:
import * as THREE from 'three';
import { FivePass } from './pass';
import { type Camera } from '../../../core/camera';
type FireworksLine = {
id?: string; // 可选的唯一标识符,不传则自动生成 UUID
points: THREE.Vector3[]; // 世界坐标系路径点
totalLength: number; // 路径总长度(世界单位)
color: THREE.Color; // 粒子颜色
opacity?: number; // 粒子不透明度(0-1)
tailLengthRatio?: number; // 尾巴长度比例(0-1),默认 0.2,与 FlowingLight3DPass 含义一致
duration?: number; // 动画周期(毫秒),默认 1000
startTime?: number; // 线条开始时间(毫秒),默认使用当前内部时间
// ---- 烟花粒子调优参数(可选) ----
particleCount?: number; // 该线条的粒子池大小,默认 200
emissionRate?: number; // 每秒发射的粒子数量,默认 300
spread?: number; // 扩散尺度(世界单位),默认 0.1
particleSize?: number; // 粒子尺寸(世界单位),默认 spread * 0.12
particleLife?: number; // 粒子最大寿命(秒),默认 0.5
gravity?: THREE.Vector3; // 粒子加速度(世界单位/秒²),默认沿 -Y 缓慢下落
leadRatio?: number; // 发射点相对尾部向前(头部方向)的提前比例,默认 0.04
};
export class FlowingFireworks3DPass extends FivePass {
constructor(camera: Camera);
// 批量设置路径列表(替换所有现有线条)
public setLines(lines: FireworksLine[]): void;
// 追加一条或多条线,返回生成的 id 数组
public addLine(...lines: FireworksLine[]): string[];
// 按 id 移除一条或多条线,返回实际移除的数量
public removeLine(...ids: string[]): number;
// 修改单条线的参数(通过 id),支持部分更新
public setLine(params: { id: string } & Partial<Omit<FireworksLine, 'id'>>): void;
public render(
renderer: THREE.WebGLRenderer,
writeBuffer: THREE.WebGLRenderTarget,
readBuffer: THREE.WebGLRenderTarget,
deltaTime: number,
maskActive?: boolean,
): void;
public dispose(): void;
}
该 Pass 的粒子发射点与 FlowingLight3DPass 的「尾部位置」(tailPosWorld)保持一致:
tailLengthRatio 表示从头部到渐变结束所占路径比例(默认 0.2)。粒子在「渐变结束的位置」喷射,即 headPos - tailLengthRatio * totalLength。FlowingLight3DPass 配置完全相同的线条数据(points/totalLength/duration/startTime/tailLengthRatio),即可让烟花精准跟随流光尾部。由于尾部沿路径滞后于头部,在视觉上粒子有时会显得「晚一拍」。leadRatio 让发射点相对尾部向头部方向提前一小段(占 totalLength 的比例,默认 0.04),使火花出现时机更早。提前量会被限制在当前尾长以内,不会越过头部。设为 0 即严格在尾部位置喷射。
每个粒子在 CPU 端发射时仅写入「出生世界坐标 / 初速度 / 加速度 / 出生时间 / 寿命」等属性,后续运动完全在顶点着色器中按 p = p0 + v·t + ½·a·t² 积分计算,并随寿命淡出与缩小。CPU 每帧只需计算尾部位置并发射少量新粒子,性能开销低。
每条线条拥有独立的粒子池(particleCount),按环形缓冲循环复用槽位。emissionRate(粒子/秒)结合每帧 deltaTime 决定发射数量,寿命到期的粒子自动被新粒子覆盖。
粒子使用 AdditiveBlending 渲染到离屏缓冲并累加,再叠加到场景输出,自然形成重叠处更亮的发光效果。粒子为圆形柔光点,中心亮、边缘柔和。
与 FlowingLight3DPass 一致,Pass 自动同步相机投影/视图矩阵,并根据 readBuffer 尺寸自动调整离屏渲染目标,适配高 DPR 屏幕。
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string |
自动生成 UUID | 唯一标识符,用于 setLine 更新单条线。 |
|
points |
THREE.Vector3[] |
✓ | - | 世界坐标系路径点数组。至少 2 个点。 |
totalLength |
number |
✓ | - | 路径总长度(世界单位)。通常为相邻点间距离之和。 |
color |
THREE.Color |
✓ | - | 粒子颜色(RGB)。 |
opacity |
number |
1.0 |
粒子不透明度(0-1)。 | |
tailLengthRatio |
number |
0.2 |
尾巴长度比例(0-1)。决定粒子喷射点(渐变结束处)相对头部的距离。 | |
duration |
number |
1000 |
动画周期(毫秒)。尾部完成一个循环所需时长。 | |
startTime |
number |
当前内部时间 | 线条开始时间(毫秒)。可用于多条线错开起始时间。 | |
particleCount |
number |
200 |
该线条粒子池大小。越大可同时存在的火花越多。 | |
emissionRate |
number |
300 |
每秒发射的粒子数量。控制火花密度。 | |
spread |
number |
0.1 |
扩散尺度(世界单位)。控制火花向四周飞散的范围。 | |
particleSize |
number |
spread * 0.12 |
粒子尺寸(世界单位)。 | |
particleLife |
number |
0.5 |
粒子最大寿命(秒)。越长火花拖得越远。 | |
gravity |
THREE.Vector3 |
沿 -Y 缓慢下落 | 粒子加速度(世界单位/秒²)。可制造下坠或上升效果。 | |
leadRatio |
number |
0.04 |
发射点相对尾部的提前比例(占 totalLength)。增大可让火花更早出现,0 表示严格在尾部。 |
注意:
spread/particleSize/gravity均为世界坐标单位,需要结合场景尺度调整。默认值适配米级小场景,大场景应相应放大。
constructor(camera: Camera)初始化 Pass,需传入相机以获取投影矩阵和视图矩阵。
setLines(lines: FireworksLine[])批量设置路径列表,替换所有现有线条。
自动生成 ID: 没有 id 时自动生成 UUID。
自动设置 startTime: 没有 startTime 时使用当前内部时间。
pass.setLines([{
points: path,
totalLength: 12,
color: new THREE.Color(0xff6600),
duration: 3000,
tailLengthRatio: 0.2,
}]);
addLine(...lines: FireworksLine[]): string[]追加一条或多条线,返回新增线条的 id 数组,不影响已有线条。
removeLine(...ids: string[]): number按 id 移除一条或多条线,返回实际移除的数量。id 不存在时输出警告。
setLine(params: { id: string } & Partial<Omit<FireworksLine, 'id'>>)通过 id 部分更新单条线。
性能说明:
points、color、totalLength、duration、spread、gravity 等)会在下一帧发射时即时生效,无需重建。particleCount 改变时才会重建粒子缓冲。// 即时生效,无需重建
pass.setLine({ id: 'line-1', color: new THREE.Color(0x00ff00), emissionRate: 500 });
// 改变粒子池大小,会重建缓冲
pass.setLine({ id: 'line-1', particleCount: 400 });
render(...)由 EffectComposer 自动调用,无需手动调用。自动同步相机矩阵与渲染目标尺寸。
dispose()释放粒子缓冲、着色材质、渲染目标等资源,销毁 Pass 时必须调用。
烟花跟随流光尾部的标准用法:为两个 Pass 配置相同的线条数据。
import { Five } from '@realsee/five';
import { FlowingLight3DPass, FlowingFireworks3DPass } from '../../lib/five/renderer/postprocessing';
import { calculatePath3DLength } from '@realsee/five/plugins';
import * as THREE from 'three';
const five = new Five();
const flowingLight = new FlowingLight3DPass(five.camera);
const fireworks = new FlowingFireworks3DPass(five.camera);
const path = [
new THREE.Vector3(-5, 0, 0),
new THREE.Vector3(-2, 3, 2),
new THREE.Vector3(2, 3, -2),
new THREE.Vector3(5, 0, 0),
];
const lineData = {
points: path,
totalLength: calculatePath3DLength(path),
color: new THREE.Color(0xff00ee),
duration: 8000,
tailLengthRatio: 0.2,
};
flowingLight.setLines([lineData]);
fireworks.setLines([lineData]); // 相同数据 => 烟花精准跟随流光尾部
// 注意添加顺序:烟花叠加在流光之上
five.addPass(flowingLight);
five.addPass(fireworks);
function animate() {
requestAnimationFrame(animate);
five.render();
}
animate();
const fireworks = new FlowingFireworks3DPass(camera);
fireworks.setLines([
{
points: [new THREE.Vector3(0, 0, 0), new THREE.Vector3(10, 5, 0)],
totalLength: 11,
color: new THREE.Color(0xff0000),
duration: 2000,
},
{
points: [new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 10, 5)],
totalLength: 12,
color: new THREE.Color(0x00ff00),
duration: 2500,
startTime: 500,
},
]);
fireworks.setLines([{
points: path,
totalLength: calculatePath3DLength(path),
color: new THREE.Color(0xffaa00),
duration: 6000,
emissionRate: 600, // 更密集
spread: 0.25, // 飞散更广
particleLife: 0.9, // 拖得更远
particleSize: 0.04,
gravity: new THREE.Vector3(0, -0.5, 0), // 明显下坠
leadRatio: 0.08, // 出现更早
}]);
// 视觉上火花偏晚 => 增大 leadRatio 让其更早出现
pass.setLine({ id: lineId, leadRatio: 0.1 });
// 严格落在流光尾部(渐变结束处)
pass.setLine({ id: lineId, leadRatio: 0 });
color / opacity 非全透明;确认已调用 addPass。emissionRate 或 particleCount(注意 particleCount 是上限,过小会限制同时存在的粒子数)。spread(世界单位),需结合场景尺度。leadRatio(增大更早,0 严格在尾部)。points/totalLength/duration/startTime/tailLengthRatio。gravity 向量;默认沿 -Y(世界上方向取决于场景坐标系)。particleCount),不会随时间增长,显存稳定。emissionRate × particleCount 会增加片元填充率,建议按需调节。particleCount 与 emissionRate,避免不必要的高密度。spread / particleSize,小场景调小,保持视觉比例。setLine 而非 setLines 更新单条线;除 particleCount 外的修改无需重建。pass.enabled = false 禁用。addPass 烟花 Pass,使火花叠加在流光之上。spread / particleSize / gravity 为世界单位,totalLength 也是世界单位,不要混用像素。emissionRate 失效。dispose(),避免 GPU 资源泄漏。tags: [烟花, 火花, 粒子, 流光拖尾, 发散, 爆裂, 特效, postprocessing, effect, fireworks, particle, sparks, flowing, pass, rendering, worldspace, 3d, world-space, additive, gpu-particles]