Quick answer: 8-bit framebuffer has 256 levels per channel and bands on smooth gradients. Enable HDR rendering in Project Settings, add a Dither effect via Environment, and ensure the viewport uses 16-bit float internally.
Here is how to fix Godot exports showing visible color banding on smooth gradients (sky, fog, lighting). The editor looks smooth; the build shows stripes. The cause is the limited per-channel resolution of the default 8-bit framebuffer; the fix is HDR rendering with dithering.
The Symptom
Smooth gradients (sky, fog, glow) show visible bands of distinct colors instead of continuous transitions. Most apparent on dark scenes or subtle gradients.
What Causes This
8-bit per channel. 256 levels is enough for crisp colors but visible as steps in smooth gradients.
No dithering. Dither breaks up bands by adding controlled noise that the eye blends.
Tone-mapping clipping. Bright HDR ranges crushed to 8-bit produces visible quantization.
The Fix
Step 1: Enable HDR rendering. Open Project Settings → Rendering → Viewport. Enable Use HDR 2D (or for 3D, ensure Tonemap is set; HDR 3D is on by default).
Step 2: Enable dithering on the Environment. Open the WorldEnvironment’s Environment resource. Under Adjustments or Tonemap, enable any available dither option. Some Godot versions have environment.use_debanding = true.
Step 3: Set framebuffer format. In Project Settings, ensure Render > Driver > Viewport ’s Texture format includes a 16-bit float option for HDR. The renderer needs internal precision higher than 8-bit to benefit from HDR.
Step 4: Tune glow. Glow with very high intensity exacerbates banding. Lower glow strength or use a more refined glow filter to reduce flatness.
Step 5: Verify in build. Export and run on the target device. Editor preview can use different rendering paths; always validate the actual export.
Per-Shader Dithering
For specific shader gradients, add tiny noise in the fragment:
// Custom shader fragment
void fragment() {
float dither = fract(sin(dot(FRAGCOORD.xy, vec2(12.9898, 78.233))) * 43758.5453);
COLOR = base_color + (dither - 0.5) / 256.0;
}
Adds sub-pixel noise that breaks up bands at the cost of slight grain.
“HDR rendering plus dithering eliminate banding. 8-bit framebuffer is the bottleneck; bypass it with 16-bit internal precision.”
Related Issues
For Light2D shadow setup, see Light2D Shadow TileMap. For shader uniform updates, see Shader Uniform Updates.
HDR on. Dither on. 16-bit float fb. Bands smooth out.