Shaders from GDScript
Godot shaders use a GLSL-like language in .gdshader files.
32.1 Godot shading language
Godot shaders use a GLSL-like language in .gdshader files. Each shader declares a type:
2D sprites, UI, tilemaps GPU particle processing Volumetric fog volumes
// res://shaders/hit_flash.gdshader
shader_type canvas_item;
uniform vec4 flash_color : source_color = vec4(1.0);
uniform float flash_amount : hint_range(0.0, 1.0) = 0.0;
void fragment() {
vec4 tex = texture(TEXTURE, UV);
COLOR = vec4(mix(tex.rgb, flash_color.rgb, flash_amount), tex.a);
}32.2 Controlling shaders from GDScript
@onready var sprite: Sprite2D = $Sprite2D
var mat: ShaderMaterial
func _ready() -> void:
mat = sprite.material as ShaderMaterial
# If several instances share the material, make it unique first:
# sprite.material = sprite.material.duplicate() (or enable resource_local_to_scene)
func hit_flash() -> void:
mat.set_shader_parameter("flash_amount", 1.0)
var tween := create_tween()
tween.tween_method(func(v: float): mat.set_shader_parameter("flash_amount", v), 1.0, 0.0, 0.2)
# or tween the property path directly:
# tween.tween_property(mat, "shader_parameter/flash_amount", 0.0, 0.2)
func set_up_in_code() -> void:
var shader := preload("res://shaders/hit_flash.gdshader")
var m := ShaderMaterial.new()
m.shader = shader
m.set_shader_parameter("flash_color", Color.RED)
sprite.material = m
print(m.get_shader_parameter("flash_amount"))32.3 3D example: dissolve
shader_type spatial;
uniform sampler2D albedo_tex : source_color;
uniform sampler2D noise_tex;
uniform float dissolve : hint_range(0.0, 1.0) = 0.0;
uniform vec4 edge_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);
void fragment() {
float n = texture(noise_tex, UV).r;
if (n < dissolve) {
discard;
}
ALBEDO = texture(albedo_tex, UV).rgb;
EMISSION = edge_color.rgb * step(n, dissolve + 0.05) * 4.0;
}func dissolve_out(mesh: MeshInstance3D) -> void:
var m := mesh.get_active_material(0) as ShaderMaterial
create_tween().tween_property(m, "shader_parameter/dissolve", 1.0, 1.5)32.4 Global and per-instance uniforms
global uniform vec3 wind_direction; // defined in Project Settings → Globals → Shader Globals
instance uniform vec4 tint : source_color = vec4(1.0); // spatial shaders: per-instance valueRenderingServer.global_shader_parameter_set("wind_direction", Vector3(1, 0, 0.5))
$Tree.set_instance_shader_parameter("tint", Color.GREEN) # GeometryInstance3D, no material duplication32.5 Visual shaders and other options
VisualShader: node-based editor producing the same shaders; good for artists.
Convert a StandardMaterial3D to a ShaderMaterial (right-click → Convert) to see generated code.
Screen-reading effects: uniform sampler2D screen_tex : hint_screen_texture; in a full-screen ColorRect on a CanvasLayer for post-processing.
CompositorEffect (4.3+) for custom rendering passes in Forward+/Mobile.
32.6 Compute shaders (RenderingDevice)
Available with the Forward+ and Mobile renderers (not Compatibility).
Godot 3 note: set_shader_param() became set_shader_parameter(); hint_color became source_color; SCREEN_TEXTURE became a hint_screen_texture uniform.
// res://compute/double.glsl
#[compute]
#version 450
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
layout(set = 0, binding = 0, std430) restrict buffer DataBuffer {
float data[];
} buf;
void main() {
buf.data[gl_GlobalInvocationID.x] *= 2.0;
}func run_compute() -> void:
var rd := RenderingServer.create_local_rendering_device()
var spirv: RDShaderSPIRV = load("res://compute/double.glsl").get_spirv()
var shader := rd.shader_create_from_spirv(spirv)
var input := PackedFloat32Array()
input.resize(64)
for i in 64: input[i] = i
var bytes := input.to_byte_array()
var buffer := rd.storage_buffer_create(bytes.size(), bytes)
var uniform := RDUniform.new()
uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
uniform.binding = 0
uniform.add_id(buffer)
var uniform_set := rd.uniform_set_create([uniform], shader, 0)
var pipeline := rd.compute_pipeline_create(shader)
var list := rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(list, pipeline)
rd.compute_list_bind_uniform_set(list, uniform_set, 0)
rd.compute_list_dispatch(list, 1, 1, 1) # 1 workgroup × 64 invocations
rd.compute_list_end()
rd.submit()
rd.sync()
var output := rd.buffer_get_data(buffer).to_float32_array()
print(output.slice(0, 8)) # [0, 2, 4, 6, 8, 10, 12, 14]
rd.free_rid(buffer)
rd.free()