Separate flame from heat
Treat visible flame, emissive color, and screen distortion as separate layers. If all three are driven by the same noisy mask, the effect becomes muddy fast.
UE5 / Recipe / Stylized Surface
A stylized fire and heat material built from vertical flow, flame masks, hot color ramps, soft alpha, and optional distortion. It should feel alive, but still be readable from a gameplay camera.
Treat visible flame, emissive color, and screen distortion as separate layers. If all three are driven by the same noisy mask, the effect becomes muddy fast.
01
02
03
Even stylized fire needs upward rhythm. The large shapes should climb. Smaller noise can twist or flicker, but if everything moves randomly, the viewer reads it as TV static.
Heat wobble should be visible only when it helps the shot. Too much distortion makes silhouettes behind the fire unreadable and can feel expensive even when it is not.
04
Use a vertical gradient multiplied by broad noise. The bottom should stay stronger; the top should break apart. This gives the flame a clear root and a softer tip.
Pan one broad noise slowly upward and one smaller noise slightly sideways. The cross-motion makes the flame feel alive without losing direction.
The alpha edge should be soft enough to layer. The emissive core can stay sharp. If both use the exact same mask, the fire often looks like a sticker.
Use a ramp from dark red to orange to yellow-white. Keep the hottest value small and centered so bloom does not flatten the entire card.
Distortion can use the same motion family but a lower contrast mask. Give it a separate intensity control and a cheap off switch.
05
06
float2 uvA = uv + float2(0.0, -time * flowSpeed);
float2 uvB = uv * detailTiling + float2(time * sideDrift, -time * detailSpeed);
float vertical = saturate(1.0 - uv.y);
float broad = Texture2DSample(noiseTex, noiseTexSampler, uvA).r;
float detail = Texture2DSample(noiseTex, noiseTexSampler, uvB).g;
float flameMask = saturate(vertical * broad + detail * flickerAmount);
float alpha = smoothstep(alphaMin, alphaMax, flameMask);
float heat = smoothstep(coreMin, coreMax, flameMask);
float3 color = lerp(coolColor, hotColor, heat);
float3 emissive = color * lerp(edgeEmission, coreEmission, heat);
float2 distortionOffset = (detail - 0.5) * distortionStrength * alpha;
return float4(emissive, alpha);
07
A hero campfire can afford more layers than twenty background torches. Keep a low-cost instance with fewer samples and no distortion.
Fire often gets expensive because of large translucent cards stacked in the same screen area. Profile overdraw before shaving tiny math nodes.
Tune the ramp in the final post-process setup. A beautiful orange ramp can become flat yellow-white when bloom and exposure are active.
08