Synthwave Shader: How it Works
Related Post: Synthwave Shader
Shader Configuration
shader_type spatial;
render_mode unshaded, depth_draw_always, cull_disabled;
spatial
: This indicates it's a 3D shader designed to work with spatial nodes in Godot.unshaded
: This mode tells the shader to ignore scene lighting. The colors defined in the shader are the final colors, which is ideal for the flat, glowing look of synthwave grids.depth_draw_always
: This ensures the object using this shader is always drawn, regardless of depth testing. This can make the grid appear "on top" of other objects, contributing to the retro effect.cull_disabled
: This disables backface culling. Normally, triangles facing away from the camera aren't drawn. Disabling this ensures that if you use this shader on a flat plane, it's visible from both above and below.
Uniform Parameters
These are variables exposed in the Godot editor, allowing you to customize the shader's appearance without editing the code:
grid_color
: Sets the color of the grid lines.background_color
: Defines the color of the space between the grid lines.line_thickness
: Controls the width of the grid lines in world units.grid_spacing
: Determines the distance between adjacent grid lines in world units.glow_strength
: Adjusts the intensity and falloff of the glow effect around the lines. A higher value creates a sharper, more intense glow.
Vertex Function
varying vec3 world_pos;
void vertex() {
world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
- This function runs for each vertex of the mesh the shader is applied to.
- It calculates the vertex's position in world space by transforming the local vertex position (
VERTEX
) using the object'sMODEL_MATRIX
. - The resulting
world_pos
is passed to the fragment shader via avarying
variable. This allows the fragment shader to know the exact world location of the pixel it's currently processing.
Grid Line Function (filtered_grid
)
float filtered_grid(float coord, float spacing, float thickness) {
float coord_mod = mod(coord, spacing);
float dist = min(coord_mod, spacing - coord_mod);
float scale = fwidth(coord);
return smoothstep(thickness + scale, thickness - scale, dist);
}
This helper function calculates the intensity of a grid line at a specific coordinate (coord
):
mod(coord, spacing)
: Finds the position within a single grid cell (from 0 tospacing
).min(coord_mod, spacing - coord_mod)
: Calculates the shortest distance from the current point to the nearest grid line boundary within that cell.fwidth(coord)
: Estimates the change in the coordinate across a single pixel. This is crucial for anti-aliasing.smoothstep(thickness + scale, thickness - scale, dist)
: Creates a smooth transition between 0 (outside the line) and 1 (inside the line) based on the distance (dist
). The range is adjusted byscale
(pixel size) andthickness
to create soft edges instead of sharp, aliased lines.
Fragment Shader
float grid_x = filtered_grid(world_pos.x, grid_spacing, line_thickness);
float grid_z = filtered_grid(world_pos.z, grid_spacing, line_thickness);
- Calls the
filtered_grid
function separately for the world X and Z coordinates to determine the intensity contribution from vertical and horizontal lines, respectively. It ignores the Y coordinate, effectively projecting the grid onto the XZ plane.
float line_intensity = max(grid_x, grid_z);
- Combines the intensities. If a pixel is close to either a horizontal or a vertical line, it takes the maximum intensity, ensuring intersections are bright.
float glow = pow(line_intensity, glow_strength);
- Applies the glow effect. Raising the
line_intensity
to the power ofglow_strength
enhances the brightness near the center of the lines and creates a non-linear falloff.
ALBEDO = mix(background_color.rgb, grid_color.rgb, glow);
- Blends between the
background_color
andgrid_color
using the calculatedglow
value as the mixing factor. Whereglow
is 1, the color isgrid_color
; whereglow
is 0, it'sbackground_color
. Values between 0 and 1 create the smooth gradient effect.ALBEDO
is the final base color output for the pixel.
ALPHA = 1.0;
- Sets the pixel's opacity to fully opaque.
Summary
This shader effectively:
- Draws an infinite 2D grid projected onto the XZ plane in world space.
- Uses world-space coordinates, so the grid remains stationary as objects move through it.
- Creates glowing lines with customizable color, thickness, spacing, and glow intensity.
- Implements anti-aliasing using
fwidth
andsmoothstep
for clean, smooth line edges. - Renders independently of scene lighting (
unshaded
) and can draw over other objects (depth_draw_always
), making it suitable for stylized retro or sci-fi visuals, particularly for ground planes.
Full Shader Code
Here is the complete Godot shader code (.gdshader
file):
shader_type spatial;
render_mode unshaded, depth_draw_always, cull_disabled;
uniform vec4 grid_color : source_color = vec4(0.0, 0.3, 0.8, 1.0);
uniform vec4 background_color : source_color = vec4(0.02, 0.0, 0.05, 1.0);
uniform float line_thickness = 0.02;
uniform float grid_spacing = 2.5;
uniform float glow_strength = 1.3;
varying vec3 world_pos;
void vertex() {
world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
float filtered_grid(float coord, float spacing, float thickness) {
float coord_mod = mod(coord, spacing);
float dist = min(coord_mod, spacing - coord_mod);
float scale = fwidth(coord);
return smoothstep(thickness + scale, thickness - scale, dist);
}
void fragment() {
float grid_x = filtered_grid(world_pos.x, grid_spacing, line_thickness);
float grid_z = filtered_grid(world_pos.z, grid_spacing, line_thickness);
float line_intensity = max(grid_x, grid_z);
float glow = pow(line_intensity, glow_strength);
ALBEDO = mix(background_color.rgb, grid_color.rgb, glow);
ALPHA = 1.0;
}