Skip to content

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 直接生效。gridSizeemitterGeometryvolumeLayerraymarchSteps 改变时会重建相关资源。

typescript
fire.update({
  emitTemperature: 6,
  emitDensity: 8,
  emitterRadius: 1.4,
  smokeLifespan: 6,
});

setPosition(position)

更新体积盒底部中心位置。等同于 update({ position })

setEmitter(emitter, geometry?)

设置驱动 emitter 的对象和采样几何。emittermatrixWorld 会在每帧写入模拟;如果只想使用默认内部 emitter,可以传入 null

reset()

清空当前模拟状态并重新创建模拟资源。

disable()

关闭火焰效果,移除 beforeRender / cameraChange 监听、output effect、体积盒、灯光、storage texture 和 compute pass,并恢复启用前的 viewer.frameloop

dispose()

关闭效果并释放插件持有的默认 emitter geometry。

Options

参数类型默认值说明
positionVector3(0, 0, 0)体积盒底部中心世界坐标
sizeVector3(12, 12, 24)体积盒世界尺寸,也是烟雾扩散的约束范围
gridSize{ x?: number; y?: number; z?: number }{ x: 100, y: 100, z: 200 }3D 模拟网格尺寸,越大越细腻也越耗显存
volumeLayernumber10体积盒所在 layer,用于隔离 volumetric pass
emitterGeometryBufferGeometry | nullTeapotGeometry(0.8, 28)emit pass 采样的几何顶点
emitterObject3D | null内部 Object3D驱动 emitter matrix 和扰动速度的对象
emitterRadiusnumber1emitter 移动时影响流场的半径,作为 uniform 更新
simulatebooleantrue是否推进流体模拟
simSpeednumber1.2模拟速度倍率
pressureIterationsnumber2Jacobi pressure projection 次数,会自动向上限制为正偶数
raymarchStepsnumber16体积 raymarch 步数,改变后会重建体积材质
renderResolutionnumber0.5volumetric pass 分辨率倍率,范围 0.1..1
denoisebooleantrue是否对体积 pass 做 Gaussian blur
denoiseStrengthnumber0.5降噪强度
bloombooleantrue是否对火焰输出追加 bloom
bloomStrengthnumber0.1bloom 强度
bloomRadiusnumber1bloom 半径
bloomThresholdnumber0.5bloom 阈值
smokeLifespannumber3.5烟雾寿命,越大烟雾保留越久
smokeIntensitynumber1烟雾散射可见度倍率
smokeColorColorRepresentation0xffffff烟雾散射颜色
fireLifespannumber1.3火焰温度衰减时间
turbulencenumber3.2火焰和烟雾湍流强度
turbulenceDecaynumber0.1湍流随年龄衰减速度
turbulenceFrequencynumber10curl noise 频率
buoyancynumber3热浮力
velocityDampingnumber0.25速度阻尼
emitDensitynumber7emitter 注入密度
emitTemperaturenumber5.5emitter 注入温度
motionBoostnumber0.25emitter 移动带来的额外发射量
windStrengthnumber6.5emitter 移动对流场的扰动强度
fireIntensitynumber40火焰发光强度
glowSpreadnumber5火焰亮度扩散范围
fireHuenumber0火焰色相偏移,单位为度
saturationnumber1.1输出饱和度
fireStartColorColorRepresentation0xffe68c高温火焰颜色
fireMidColorColorRepresentation0xff7305中段火焰颜色
fireEndColorColorRepresentation0xff0000低温火焰颜色
phaseAsymmetrynumber0Henyey-Greenstein 相函数 g 值
powderStrengthnumber0.59powder effect 强度
multiScatteringnumber1多次散射近似强度
shadowAbsorptionnumber2体积阴影吸收系数
shadowAmbientnumber0.5阴影环境补光
keyLightbooleantrue是否创建体积阴影 spot light
pointLightbooleantrue是否创建火焰动态点光源
pointLightIntensitynumber1动态点光源强度
pointLightDistancenumber40动态点光源距离

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.keyLightSpotLight,用于体积阴影方向和烟雾散射计算。
  • FireEffect.pointLightPointLight,跟随 emitter / 火焰核心移动,并通过 TSL colorNode 产生随温度、密度和噪声变化的暖色照明。

如果业务场景已经有自己的灯光,可以通过 keyLight: falsepointLight: false 关闭插件内置光源。

与 RenderPipeline 的关系

FireEffect 使用 viewer.renderPipeline.addOutputEffect()removeOutputEffect() 接入输出链。它不会调用 setOutputComposer(),因此不会覆盖业务或其他插件的 output effects。注意如果业务主动设置自定义 setOutputComposer(),RenderPipeline 会按自定义 composer 的语义跳过 output effects,火焰叠加也会被跳过。

renderResolution 只影响独立 volumetric pass 的分辨率;主场景分辨率仍由 Viewer 和 renderer 控制。启用 denoisebloom 时,插件会在 output effect 内创建并释放对应节点。

示例

示例页见 examples/test_fire.html。本地运行时先构建插件:

bash
pnpm build:plugins -- plugins/fire

然后通过本地静态服务访问:

text
http://127.0.0.1:5174/examples/test_fire.html

u-space docs