jame581 / shader-basics
Use when implementing shaders — Godot shader language, visual shaders, common visual recipes, and post-processing effects
Shaders in Godot 4.3+
All examples target Godot 4.3+ with no deprecated APIs.
Related skills: animation-system for shader-driven effects like hit flash, godot-optimization for shader performance considerations, camera-system for post-processing camera effects, 2d-essentials for 2D lighting, pixel-art shaders, and CanvasTexture normal maps, 3d-essentials for spatial shaders and environment materials, particles-vfx for custom particle shaders, tween-animation for animating shader parameters at runtime.
1. Core Concepts
Shader Types
| Shader Type | Applied To | Use For |
|---|---|---|
canvas_item | 2D nodes (Sprite2D, Control, etc.) | 2D effects — outlines, dissolve, color swap |
spatial | 3D meshes (MeshInstance3D) | 3D materials — water, terrain, toon shading |
particles | GPUParticles2D/3D | Custom particle behavior |
sky | WorldEnvironment | Procedural sky rendering |
fog | FogVolume | Volumetric fog effects |
Shader vs ShaderMaterial
Shader (.gdshader) → The code (GLSL-like language)
ShaderMaterial → Instance of a shader with specific uniform values
CanvasItemMaterial / StandardMaterial3D → Built-in materials (no code needed)Multiple nodes can share the same Shader but have different ShaderMaterial instances with different uniform values (e.g., same dissolve shader but different dissolve progress per enemy).
Creating a Shader
- Select a node (e.g., Sprite2D)
- In Inspector → Material → New ShaderMaterial
- On the ShaderMaterial → Shader → New Shader
- Edit the
.gdshaderfile in the built-in editor
Or create a .gdshader file directly in the FileSystem dock.
2. Godot Shader Language Basics
Godot uses a GLSL ES 3.0-like language with Godot-specific additions.
Minimal Canvas Item Shader
shader_type canvas_item;
void fragment() {
// COLOR is the output pixel color
// TEXTURE is the sprite's texture
// UV is the texture coordinate (0,0 top-left to 1,1 bottom-right)
vec4 tex = texture(TEXTURE, UV);
COLOR = tex;
}Minimal Spatial Shader
shader_type spatial;
void fragment() {
// ALBEDO is the base color (vec3)
ALBEDO = vec3(0.8, 0.2, 0.2);
}Built-in Variables (canvas_item)
| Variable | Type | Description |
|---|---|---|
UV | vec2 | Texture coordinates |
COLOR | vec4 | Output color (set this in fragment()) |
TEXTURE | sampler2D | The node's texture |
VERTEX | vec2 | Vertex position (in vertex()) |
TIME | float | Elapsed time in seconds |
SCREEN_UV | vec2 | Screen-space UV (for screen effects) |
SCREEN_TEXTUREwas removed in Godot 4.0. To read the screen, declare a uniform:uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
Built-in Variables (spatial)
| Variable | Type | Description |
|---|---|---|
ALBEDO | vec3 | Base surface color |
METALLIC | float | Metallic value (0.0–1.0) |
ROUGHNESS | float | Roughness value (0.0–1.0) |
NORMAL | vec3 | Surface normal (for normal mapping) |
EMISSION | vec3 | Emissive color |
ALPHA | float | Transparency (enable in render mode) |
VERTEX | vec3 | Vertex position (in vertex()) |
Uniforms (Shader Parameters)
Uniforms expose shader values to the Inspector and code.
shader_type canvas_item;
uniform float speed : hint_range(0.0, 10.0, 0.1) = 1.0;
uniform vec4 tint_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform sampler2D noise_texture : filter_linear_mipmap;
void fragment() {
vec4 tex = texture(TEXTURE, UV);
COLOR = tex * tint_color;
}Common Uniform Hints
| Hint | Type | Description |
|---|---|---|
hint_range(min, max, step) | float/int | Slider in Inspector |
source_color | vec4 | Color picker in Inspector |
filter_linear_mipmap | sampler2D | Texture filtering mode |
repeat_enable | sampler2D | Allow texture tiling |
hint_normal | sampler2D | Treat as normal map |
Setting Uniforms from Code
GDScript
var mat: ShaderMaterial = $Sprite2D.material
mat.set_shader_parameter("speed", 2.0)
mat.set_shader_parameter("tint_color", Color.RED)C#
var mat = GetNode<Sprite2D>("Sprite2D").Material as ShaderMaterial;
mat.SetShaderParameter("speed", 2.0f);
mat.SetShaderParameter("tint_color", Colors.Red);3. Common 2D Shader Recipes
The canvas_item recipes most projects need: dissolve (noise + edge glow), outline (sample neighbors, expand alpha), flash-white (uniform-driven hit effect), color swap (palette shift), scrolling UV (water/lava/clouds), wave distortion.
See [references/2d-shader-recipes.md](references/2d-shader-recipes.md) for complete shader code for all six recipes.
4. Common 3D Shader Recipes
Spatial-shader recipes: toon/cel shading (banded NdotL), rim lighting / Fresnel (1 - NdotV), simple water surface (UV scroll + normal-map blend + Fresnel).
See [references/3d-shader-recipes.md](references/3d-shader-recipes.md) for the full shader source for each recipe.
5. Visual Shaders
Visual shaders provide a node-based graph editor — no code required.
When to Use Visual Shaders
| Use Visual Shaders When | Use Code Shaders When |
|---|---|
| Prototyping effects quickly | Complex math or branching logic |
| Artists need to tweak values | Need precise control over every line |
| Learning shader concepts | Performance-critical shaders |
| Simple effects (color adjust, UV scroll) | Loops or advanced techniques |
Creating a Visual Shader
- Select node → Inspector → Material → New ShaderMaterial
- Shader → New VisualShader
- Click the shader to open the Visual Shader editor
- Add nodes from the palette, connect pins
- Output nodes (Output, FragmentOutput) are pre-placed
Key Visual Shader Nodes
| Node | Purpose |
|---|---|
Texture2D | Sample a texture |
ColorConstant | Solid color value |
VectorOp | Math operations on vectors |
ScalarOp | Math operations on floats |
Mix | Lerp between two values |
Step / SmoothStep | Threshold / smooth threshold |
Time | Current time (for animation) |
UV | Texture coordinates |
Input (custom) | Expose a uniform to Inspector |
Visual shaders compile to the same GPU code as written shaders. There is no performance difference.
Godot 4.7+: Two new spatial
Inputnodes —in_shadow_pass(vertex/fragment; maps to theIN_SHADOW_PASSbuilt-in,truewhen the shader is being rendered in a shadow mapping pass — render objects differently in shadow maps than in the regular pass) andspecular_amount(light(); maps toSPECULAR_AMOUNT—2.0×light_specularfor OmniLight3D/SpotLight3D,1.0for DirectionalLight3D).
⚠‹VARIATION SELECTOR U+FE0F› Changed in Godot 4.7: The
LinearToSRGBvisual shader node no longer clamps its output to[0.0, 1.0]when using the Forward+ or Mobile renderer — HDR values above1.0now pass through. Graphs that relied on the implicit clamp produce different output; add an explicitClampnode to restore the old behavior. See the 4.7 migration guide.
6. Post-Processing Effects
The standard pattern: full-rect ColorRect with a canvas_item shader on top of the gameplay canvas. For 3D, use a WorldEnvironment Adjustment, Glow, or custom shader. For chained effects, render the world to a SubViewport then sample its texture in a final shader pass.
See [references/post-processing.md](references/post-processing.md) for the ColorRect overlay pattern, vignette + CRT/scanline shader source, the SubViewport pipeline, and WorldEnvironment 3D post-processing notes.
7. Compositor Effects (Godot 4.3+)
CompositorEffect runs custom render passes within Godot's render pipeline (post-tonemap or pre-tonemap). Use when ColorRect overlays aren't enough — multi-pass effects, depth-aware effects, custom AO/SSR variants. Heavier setup than a screen-space shader; reach for it only when needed.
See [references/compositor-effects.md](references/compositor-effects.md) for setup, a custom CompositorEffect GDScript example, and built-in Compositor use cases.
8. Render Modes
Render modes go on the first line after shader_type and control how the shader interacts with the rendering pipeline.
Canvas Item Render Modes
shader_type canvas_item;
render_mode unshaded; // Ignore all lighting
render_mode light_only; // Only visible where lit
render_mode blend_add; // Additive blending (glow, fire)
render_mode blend_mix; // Standard alpha blending (default)
render_mode blend_premul_alpha; // Pre-multiplied alphaSpatial Render Modes
shader_type spatial;
render_mode unshaded; // No lighting calculations
render_mode cull_disabled; // Render both sides of faces
render_mode depth_draw_always; // Always write to depth buffer
render_mode specular_toon; // Toon specular model
render_mode diffuse_toon; // Toon diffuse model
render_mode blend_add; // Additive blending9. Stencil Buffer Effects (Godot 4.5+)
Godot 4.5 exposes stencil write/read in spatial shaders via the stencil_mode statement (stencil_mode write, 1; / stencil_mode read, compare_equal, 1;) and on StandardMaterial3D (Stencil: Outline / X-Ray / Custom), across all rendering backends. canvas_item shaders have no stencil modes. Enables portals, X-ray vision, outline masks, and holes-in-geometry effects that previously required compositor-level work.
See [references/stencil-buffer.md](references/stencil-buffer.md) for the
stencil_modereference and the X-ray vision portal worked example.
10. SMAA Antialiasing (Godot 4.5+)
Sub-pixel Morphological Antialiasing (SMAA 1x) is a built-in post-processing AA mode added in Godot 4.5. It produces clearer results than FXAA at a slightly higher performance cost, and is much cheaper than MSAA.
Enabling SMAA
- Open Project Settings
- Navigate to Rendering → Anti Aliasing → Quality
- Set Screen Space AA to SMAA
SMAA can be combined with MSAA (for geometry edge aliasing) or used standalone. It does not require any shader code changes.
| AA Mode | Sharpness | GPU cost | Ghosting |
|---|---|---|---|
| Disabled | N/A | None | None |
| FXAA | Low (blurry) | Very low | Low |
| SMAA | High | Low (slightly above FXAA) | Very low |
| TAA | Medium (slight blur) | Medium | Possible |
| MSAA 4x | High | High | None |
When to use SMAA: Prefer SMAA over FXAA for most desktop projects — it delivers noticeably sharper text and thin edges for a slightly higher cost. Combine SMAA + MSAA 2x for best quality at moderate cost.
The project setting is read at startup only. To switch at runtime set get_viewport().screen_space_aa = Viewport.SCREEN_SPACE_AA_SMAA (C#: GetViewport().ScreenSpaceAA = Viewport.ScreenSpaceAAEnum.Smaa). Forward+ and Mobile only — not Compatibility.
11. Shader Baker — Export-time Pre-compilation (Godot 4.5+)
The Shader Baker converts project shaders to the target driver's format at export time, which shortens first-launch load — most on macOS/iOS (Metal) and Windows (D3D12), where that conversion is slow. It does not remove pipeline-compilation stutter the first time a material renders, works only on the Forward+ and Mobile renderers, and bakes only for drivers the exporting machine's OS supports. Enable it per export preset for release builds; leave it off for development.
See [references/shader-baker.md](references/shader-baker.md) for enabling steps and the with/without comparison.
12. Common Pitfalls
| Symptom | Cause | Fix |
|---|---|---|
| Shader has no visible effect | Material not assigned or shader not saved | Check node's Material property in Inspector |
| Transparent parts render as black | Alpha not handled in shader | Set COLOR.a = tex.a; and use appropriate blend mode |
| Uniform doesn't appear in Inspector | Typo in uniform name or wrong type | Re-save the shader; check for compilation errors |
| Texture appears stretched/tiled | Missing repeat_enable or wrong UV scale | Add repeat_enable hint to sampler2D uniform |
| Shader works in editor but not in game | Screen texture uniform needs backbuffer | Use hint_screen_texture on a sampler2D uniform (Godot 4.x) |
| Performance drops with many shaders | Each unique shader = draw call break | Share ShaderMaterial instances; use uniforms for variation |
| Screen-space UV is wrong | SCREEN_UV not available in some contexts | Ensure the node is rendered in the correct viewport |
| Visual shader node missing | Node was renamed or removed in newer Godot version | Check Godot docs for the current node name |
⚠‹VARIATION SELECTOR U+FE0F› Changed in Godot 4.7:
textureQueryLod()is available only in the fragment shader, and Godot 4.7 enforces this with a compile error — shaders calling it fromvertex()stop compiling after upgrading. Move the call intofragment(). See GH-118962.
13. Implementation Checklist
- [ ] Shader type matches the node type (
canvas_itemfor 2D,spatialfor 3D) - [ ] Uniforms use appropriate hints (
hint_range,source_color,filter_linear_mipmap) - [ ] Shared visual effects use the same Shader resource with separate ShaderMaterial instances
- [ ] Post-processing shaders are on a CanvasLayer (2D) or WorldEnvironment (3D), not on game objects
- [ ]
TEXTUREis sampled in canvas_item shaders (otherwise sprite content is lost) - [ ] Alpha-transparent shaders set
COLOR.acorrectly and useblend_mixrender mode - [ ] Animated shader parameters (dissolve, flash) are driven by Tweens or AnimationPlayer, not
_process - [ ] Screen-reading shaders use
hint_screen_textureon asampler2Duniform (Godot 4.x approach) - [ ] Complex shaders are profiled with the Godot profiler to check GPU frame time
- [ ] Stencil effects use two-pass materials (write pass first, read pass second) with correct render priority (Godot 4.5+)
- [ ] SMAA is preferred over FXAA for desktop builds (sharper edges, slightly higher cost) — set in Project Settings → Rendering → Anti Aliasing (Godot 4.5+)
- [ ] Shader Baker is enabled in release presets for D3D12 and Metal targets to shorten first-launch load (Forward+/Mobile only; Godot 4.5+)