Appearance
fire
体积火焰插件,基于 Three.js 官方 webgpu_volume_fire 示例封装。插件在 GPU 上运行 3D 流体模拟,并通过独立的 volumetric pass 叠加到 Viewer.renderPipeline output effect 链中,提供火焰、烟雾、扰动、阴影和动态点光源效果。
typescript
import { Vector3 } from 'three/webgpu';
import { FireEffect } from 'u-space/plugins/fire';
const fire = new FireEffect(viewer, {
position: new Vector3(0, 0, 0),
size: new Vector3(12, 12, 24),
fireIntensity: 40,
smokeLifespan: 3.5,
});
fire.enable();能力
- 按官方示例的 semi-Lagrangian advection、curl noise、buoyancy、Jacobi pressure projection 流程模拟体积火焰和烟雾。
- 使用 3D storage texture 保存速度、密度、温度、压力和 curl noise 数据。
- 默认使用
TeapotGeometry(0.8, 28)作为 emitter 采样几何;也可以传入业务对象和自定义BufferGeometry。 - 通过
RenderPipeline.addOutputEffect()叠加体积结果,不占用业务侧的setOutputComposer()。 - 内置 spot light 和 point light:spot light 负责体积阴影方向,point light 跟随火焰核心投射暖色动态光照。
- 监听
cameraChange,相机对象切换后会重建 fire 自己的 volumetric pass。
API
new FireEffect(viewer, options?)
创建火焰效果实例。构造函数不会立即往场景写入模拟资源;调用 enable() 后才会创建体积盒、storage texture、compute pass、灯光和 output effect。
enable(options?)
开启火焰效果。重复调用时等同于 update(options)。启用期间会把 viewer.frameloop 临时切到 always,关闭时恢复启用前的值。
typescript
fire.enable({
position: new Vector3(0, 0, 0),
size: new Vector3(12, 12, 24),
renderResolution: 0.5,
});update(options?)
更新火焰参数。大多数视觉和模拟强度参数会通过 uniform 直接生效。gridSize、emitterGeometry、volumeLayer 或 raymarchSteps 改变时会重建相关资源。
typescript
fire.update({
emitTemperature: 6,
emitDensity: 8,
emitterRadius: 1.4,
smokeLifespan: 6,
});setPosition(position)
更新体积盒底部中心位置。等同于 update({ position })。
setEmitter(emitter, geometry?)
设置驱动 emitter 的对象和采样几何。emitter 的 matrixWorld 会在每帧写入模拟;如果只想使用默认内部 emitter,可以传入 null。
reset()
清空当前模拟状态并重新创建模拟资源。
disable()
关闭火焰效果,移除 beforeRender / cameraChange 监听、output effect、体积盒、灯光、storage texture 和 compute pass,并恢复启用前的 viewer.frameloop。
dispose()
关闭效果并释放插件持有的默认 emitter geometry。
Options
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
position | Vector3 | (0, 0, 0) | 体积盒底部中心世界坐标 |
size | Vector3 | (12, 12, 24) | 体积盒世界尺寸,也是烟雾扩散的约束范围 |
gridSize | { x?: number; y?: number; z?: number } | { x: 100, y: 100, z: 200 } | 3D 模拟网格尺寸,越大越细腻也越耗显存 |
volumeLayer | number | 10 | 体积盒所在 layer,用于隔离 volumetric pass |
emitterGeometry | BufferGeometry | null | TeapotGeometry(0.8, 28) | emit pass 采样的几何顶点 |
emitter | Object3D | null | 内部 Object3D | 驱动 emitter matrix 和扰动速度的对象 |
emitterRadius | number | 1 | emitter 移动时影响流场的半径,作为 uniform 更新 |
simulate | boolean | true | 是否推进流体模拟 |
simSpeed | number | 1.2 | 模拟速度倍率 |
pressureIterations | number | 2 | Jacobi pressure projection 次数,会自动向上限制为正偶数 |
raymarchSteps | number | 16 | 体积 raymarch 步数,改变后会重建体积材质 |
renderResolution | number | 0.5 | volumetric pass 分辨率倍率,范围 0.1..1 |
denoise | boolean | true | 是否对体积 pass 做 Gaussian blur |
denoiseStrength | number | 0.5 | 降噪强度 |
bloom | boolean | true | 是否对火焰输出追加 bloom |
bloomStrength | number | 0.1 | bloom 强度 |
bloomRadius | number | 1 | bloom 半径 |
bloomThreshold | number | 0.5 | bloom 阈值 |
smokeLifespan | number | 3.5 | 烟雾寿命,越大烟雾保留越久 |
smokeIntensity | number | 1 | 烟雾散射可见度倍率 |
smokeColor | ColorRepresentation | 0xffffff | 烟雾散射颜色 |
fireLifespan | number | 1.3 | 火焰温度衰减时间 |
turbulence | number | 3.2 | 火焰和烟雾湍流强度 |
turbulenceDecay | number | 0.1 | 湍流随年龄衰减速度 |
turbulenceFrequency | number | 10 | curl noise 频率 |
buoyancy | number | 3 | 热浮力 |
velocityDamping | number | 0.25 | 速度阻尼 |
emitDensity | number | 7 | emitter 注入密度 |
emitTemperature | number | 5.5 | emitter 注入温度 |
motionBoost | number | 0.25 | emitter 移动带来的额外发射量 |
windStrength | number | 6.5 | emitter 移动对流场的扰动强度 |
fireIntensity | number | 40 | 火焰发光强度 |
glowSpread | number | 5 | 火焰亮度扩散范围 |
fireHue | number | 0 | 火焰色相偏移,单位为度 |
saturation | number | 1.1 | 输出饱和度 |
fireStartColor | ColorRepresentation | 0xffe68c | 高温火焰颜色 |
fireMidColor | ColorRepresentation | 0xff7305 | 中段火焰颜色 |
fireEndColor | ColorRepresentation | 0xff0000 | 低温火焰颜色 |
phaseAsymmetry | number | 0 | Henyey-Greenstein 相函数 g 值 |
powderStrength | number | 0.59 | powder effect 强度 |
multiScattering | number | 1 | 多次散射近似强度 |
shadowAbsorption | number | 2 | 体积阴影吸收系数 |
shadowAmbient | number | 0.5 | 阴影环境补光 |
keyLight | boolean | true | 是否创建体积阴影 spot light |
pointLight | boolean | true | 是否创建火焰动态点光源 |
pointLightIntensity | number | 1 | 动态点光源强度 |
pointLightDistance | number | 40 | 动态点光源距离 |
Emitter
如果不设置 emitterGeometry,插件会创建一个内部 TeapotGeometry(0.8, 28),这和官方示例保持一致。emit pass 会遍历该几何的 position 顶点,把密度和温度写入体积纹理。传入自定义 emitterGeometry 时,该几何必须包含 position attribute。
如果不设置 emitter,插件会使用内部 Object3D,并把它放在 position 位置。传入业务对象后,插件每帧读取该对象的 matrixWorld 和世界位置变化,移动速度会影响流场扰动和额外发射量。
typescript
const fire = new FireEffect(viewer, {
emitter: torchMesh,
emitterGeometry: torchFlameGeometry,
emitterRadius: 0.8,
});光源与体积范围
火焰本体不是场景里的普通透明 mesh 直接混合,而是先放在 volumeLayer 的体积盒里单独渲染,再通过 output effect 叠加到主场景。烟雾和火焰的可见范围由 position + size 定义的体积盒限制,超出盒子的密度会在边界处淡出。要让烟雾扩散范围更大,优先增大 size;要提升细节,再同步增大 gridSize。
插件会按需创建两个光源:
FireEffect.keyLight:SpotLight,用于体积阴影方向和烟雾散射计算。FireEffect.pointLight:PointLight,跟随 emitter / 火焰核心移动,并通过 TSLcolorNode产生随温度、密度和噪声变化的暖色照明。
如果业务场景已经有自己的灯光,可以通过 keyLight: false 或 pointLight: false 关闭插件内置光源。
与 RenderPipeline 的关系
FireEffect 使用 viewer.renderPipeline.addOutputEffect() 和 removeOutputEffect() 接入输出链。它不会调用 setOutputComposer(),因此不会覆盖业务或其他插件的 output effects。注意如果业务主动设置自定义 setOutputComposer(),RenderPipeline 会按自定义 composer 的语义跳过 output effects,火焰叠加也会被跳过。
renderResolution 只影响独立 volumetric pass 的分辨率;主场景分辨率仍由 Viewer 和 renderer 控制。启用 denoise 和 bloom 时,插件会在 output effect 内创建并释放对应节点。
示例
示例页见 examples/test_fire.html。本地运行时先构建插件:
bash
pnpm build:plugins -- plugins/fire然后通过本地静态服务访问:
text
http://127.0.0.1:5174/examples/test_fire.html