Twirl Smoke volume shader preset
Twirl Smoke shows how a shader can look volumetric without marching through a full 3D density field. It warps 2D coordinates around the center, samples layered value noise, then maps the result into a smoky color ramp.
This preset is useful when you want a visual smoke effect that stays lighter than true 3D ray marching. It still stresses fragment work through noise lookups and coordinate transforms, but it avoids per-pixel depth traversal.
Performance factors
Noise layers
Each extra octave adds repeated hash and interpolation work per pixel.
Coordinate warping
Trigonometric functions in the twirl are more expensive than simple UV transforms.
No ray loop
The preset is usually lighter than real 3D clouds because it does not march along depth.
Editable parameters
Twirl strength
Higher strength changes the visual flow but also leans on trigonometric math.
Noise scale
Higher scale creates tighter details that can alias on small screens.
Smoke threshold
Lower thresholds fill more of the screen and make the effect brighter.
Best fit
- Fast smoke previews
- Mobile-friendly visual experiments
- Comparing 2D shader pressure against true volume presets
Shader preview
#version 300 es
precision highp float;
out vec4 outColor;
in vec2 v_uv;
uniform float u_time; uniform vec2 u_resolution;
float hash(vec2 p){p=fract(p*vec2(123.34,345.45));p+=dot(p,p+34.345);return fract(p.x*p.y);}
float noise(vec2 p){ vec2 i=floor(p); vec2 f=fract(p); f=f*f*(3.0-2.0*f);
float a=hash(i), b=hash(i+vec2(1,0)), c=hash(i+vec2(0,1)), d=hash(i+vec2(1,1));
return mix(mix(a,b,f.x), mix(c,d,f.x), f.y);
}
void main(){
vec2 uv = v_uv;
vec2 p = (uv*2.0-1.0);
p.x *= u_resolution.x/u_resolution.y;
float r = length(p);
float ang = atan(p.y,p.x) + 0.8*sin(u_time*0.5) + 2.5*r;