This version is the production tuning surface for the same idea. It uses the WebGL / GLSL path from `three-fluid-fx`, where the effect is built with EffectComposer passes, ShaderMaterial uniforms, and WebGL render targets.
Live demo
What this demo teaches
Distortion doesn't paint colors; it bends light. The fluid's velocity field acts as a screen-space UV displacement map, warping the typography and 3D objects underneath it exactly where the cursor drags them. In this variant, the relevant fluid output is Texture objects: velocityTexture, densityTexture, and dyeTexture when dye is enabled.
- Understand why distortion reads flow instead of drawing fluid color.
- Know how intensity, splatForce, and dissipation affect perceived refraction.
- Choose the right distortion family for heat haze, glass, chromatic smear, or water.
Implementation path
- Render a scene texture
The distortion needs pixels to refract. In WebGL that usually means an EffectComposer chain; in TSL it means a scene node in the RenderPipeline.
- Sample the fluid flow
The main signal is the velocity stored in the fluid output. Strong gestures create larger UV offsets.
- Clamp the visual gain
Distortion becomes ugly faster than overlays. Keep intensity modest and tune the solver force separately.
- Full scope
It keeps the core render path but adds controls, style choices, background handling, and parameters that matter when shipping the effect.
import { FluidSimulation, SimpleDistortionPass } from 'three-fluid-fx'
const fluid = new FluidSimulation(renderer)
const distortion = new SimpleDistortionPass(fluid)
distortion.intensity = 0.08
composer.addPass(renderScene)
composer.addPass(distortion) Parameters to tune
| Parameter | What it controls | How to tune it |
|---|---|---|
intensity | Amount of UV displacement applied to the scene. | Start low. Raise until motion is visible but edges do not tear. |
splatForce | How much pointer motion enters the velocity field. | Use force for interaction feel, then use intensity for final visual scale. |
velocityDissipation | How long the refractive motion keeps moving. | High values feel like glass or water. Lower values feel like quick heat shimmer. |
densityDissipation | Mask lifetime for density-aware distortion styles. | Raise it for water and chromatic effects that use density as a height or visibility mask. |
Source landmarks
Start from examples/glsl/full/distortion/main.ts. These are the parts worth reading first:
- Composer or RenderPipeline setup.
- Which distortion style is selected.
- The shader or node path that turns flow into UV offsets.
- Time uniform updates for animated water and caustics.
Production notes
- Keep distortion below the threshold where text becomes unreadable.
- For UI overlays, prefer heat-haze intensity over strong chromatic split.
- For water, use larger splats and slower density decay so the surface has body.