smoke
smoke(pointer : THREE.Vector2, simRes : number, dyeRes : number, iterations : number, densityDissipation : number, velocityDissipation : number, pressureDissipation : number, curlStrength : number, pressureFactor : number, radius : number, useBoundaries : boolean, pointerScale : number, neighborStride : number, speedFactor : number) : NodeSmoke Simulation (TSL) – a 2D velocity–pressure solver that runs in screen space.
Turns a fullscreen pass into a stylized, real-time smoke/ink flow using WebGPU compute through Three.js TSL. Uses StorageTexture resources and takes advantage of Tier2 read–write access whenever the adapter exposes it. It owns and ping-pongs its internal textures (velocity, pressure, density, curl, divergence) and updates itself every frame when used in a PostProcessing chain.
Features
- Semi-Lagrangian advection for velocity and density
- Vorticity confinement (curl) and divergence-free projection (pressure solve)
- Configurable dissipation, pressure iterations and curl strength
- Optional pointer-driven splats via a
vec2uniform (no global dispatcher) - Drop-in for post-processing:
postProcessing.outputNode = smoke(pointer, 128, 512, ...)
Example: Basic postprocessing setup
Example: Interactive pointer-driven splats
import * as THREE from 'three/webgpu';
import { smoke } from '@three-blocks/core';
const pointer = new THREE.Vector2();
// Pass pointer as first argument - motion automatically injects splats
const fluidNode = smoke(pointer, 128, 512, 3, 0.97, 0.98, 0.8, 20, 0.2, 0.1, true, 45);
// Update pointer on mouse move (NDC coordinates: -1 to +1)
document.addEventListener('mousemove', (e) => {
pointer.x = (e.clientX / window.innerWidth) * 2 - 1;
pointer.y = -(e.clientY / window.innerHeight) * 2 + 1;
});
Parameters
pointeroptionalTHREE.Vector2NDC-like pointer in [-1, 1]; when present, motion injects splats.
simResoptionalnumberSquare resolution for velocity/pressure buffers.
Default is
Default is
128.dyeResoptionalnumberSquare resolution for density buffer.
Default is
Default is
512.iterationsoptionalnumberPressure Jacobi iterations per solve.
Default is
Default is
3.densityDissipationoptionalnumberDensity dissipation factor in [0, 1].
Default is
Default is
0.97.velocityDissipationoptionalnumberVelocity dissipation factor in [0, 1].
Default is
Default is
0.98.pressureDissipationoptionalnumberDamp factor for pressure clear step.
Default is
Default is
0.8.curlStrengthoptionalnumberVorticity confinement scale.
Default is
Default is
20.pressureFactoroptionalnumberPressure factor constant in Jacobi updates.
Default is
Default is
0.2.radiusoptionalnumberGaussian splat radius in UV^2. Increase for larger splats.
Default is
Default is
0.1.useBoundariesoptionalbooleanMirror-velocity boundary conditions at screen edges.
Default is
Default is
true.pointerScaleoptionalnumberMultiplier applied to pointer delta when generating splats.
Default is
Default is
45.neighborStrideoptionalnumberMultiplier for curl/divergence/pressure neighbor texel offsets.
Default is
Default is
1.speedFactoroptionalnumberScales sub-stepping relative to frame time (lower = more substeps).
Default is
Default is
1.Returns
Node — Color node sampling the current dye texture of the fluid simulation.Example
import * as THREE from 'three/webgpu';
import { smoke } from '@three-blocks/core';
const renderer = new THREE.WebGPURenderer();
await renderer.init();
const postProcessing = new THREE.PostProcessing(renderer);
const pointer = new THREE.Vector2();
// smoke(pointer, simRes, dyeRes, iterations, densityDissipation, velocityDissipation,
// pressureDissipation, curlStrength, pressureFactor, radius, useBoundaries, pointerScale)
const fluidNode = smoke(pointer, 128, 512, 3, 0.97, 0.98, 0.8, 20, 0.2, 0.1, true, 45);
postProcessing.outputNode = fluidNode;
renderer.setAnimationLoop(() => postProcessing.render());