Introduction to Shaders in Godot 4
Discover the art of game customization with shaders in Godot 4. Learn to craft your visual effects, from texture color manipulation to sprite animations, in this guide to writing fragment and vertex shaders. By Eric Van de Kerckhove.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Introduction to Shaders in Godot 4
45 mins
- Getting Started
- What Is a Shader?
- Types of Shaders
- Basics of Texture Manipulation
- Fragment Shaders
- Overwriting Colors
- Manipulating Colors
- Vertex Function
- Moving Vertices
- Using Time
- Time to S(h)ine
- Selective Movement With If-Statements
- Circular Movement
- Getting the Dimensions of a Sprite
- Making Shaders Customizable
- Improving the Sway Shader
- Using Code to Set Shader Parameters
- Shader Hinting
- Combining Vertex and Fragment Functions
- Bonus Shaders
- Where to Go From Here?
Shaders are powerful tools that allow developers to customize the look and feel of their games in endless ways. This article will go over the basics of writing fragment and vertex shaders in Godot 4. You’ll learn techniques to create your own visual effects. From manipulating texture colors to animating sprites, you’ll discover all the building blocks you need to start experimenting with shaders in your own projects.
Getting Started
To follow along with this tutorial, download the project materials via the Download materials link at the top or bottom of the page. Inside the ZIP file, you’ll find a starter and a final folder, both containing a project folder named ShaderIntroduction.
Begin by opening the starter project in Godot. You should see an empty main scene with a Node2D node named Main at its root. This is where’ll you’ll add sprites to experiment with shaders.
The starter project comes with a set of resources in the form of sprites. You can find these in the textures folder, along with the default Godot icon and a simple, colorful image at the root of the file system.
As you can see, there’s not much going on yet, but you’ll get to it soon!
What Is a Shader?
Before writing any shaders, it’s important to understand what they are. A shader is a set of instructions that runs on your graphics card and defines the appearance of rendered objects like sprites and 3D objects. Modern rendering pipelines make heavy use of shaders to create effects like specular lighting, volumetric fog and post-processing effects.
Besides creating impressive visual effects, you can also use shaders to manipulate the look and feel of your game. You can make trees sway in the wind, or sprites blink when they get hit, for example. These little programs can add a lot of life to your projects.
One of the features that make shaders special is their ability to run in parallel. Instead of a classic program that runs on the CPU and has to finish its tasks one after the other, a shader can do many tasks at the same time. This is crucial, as shaders often manipulate every single pixel on your screen or every vertex of a complex 3D object many times per second. At 4K resolution, a single shader might be working on more than 8 million pixels at once!
When you write a shader, you’ll work in a specialized language called a Shading Language. Some of the more popular languages include OpenGL Shading Language (GLSL) and High Level Shading Language (HLSL). To run the shader, your CPU translates the code into instructions that the GPU can understand. This is known as compiling.
The CPU performs the compilation process while a game is initializing — and sometimes while running the game, as shaders can changed dynamically during gameplay. The compiled shaders are then cached on disk for future use. For modern titles with thousands of shaders, this process can take a while — which is why you’ll often see loading screens that say “Compiling shaders”.
Types of Shaders
As mentioned above, shaders are versatile. Godot supports the creation of the following types of shaders:
- Spatial: Manipulate the rendering of 3D objects.
- Canvas item: Change the look and feel of 2D objects, like sprites and UI elements.
- Particles: Manipulate the way a particle system behaves.
- Sky: Render sky backgrounds and cubemaps.
- Fog: Specialized shaders used for volumetric fog effects.
The spatial and canvas item shaders are the most common types of shaders because just about every game out there uses 3D objects or sprites. The others are reserved for niche cases.
To build up a basic understanding, you’ll be creating canvas item shaders throughout this tutorial.
Basics of Texture Manipulation
All right, enough theory for now! It’s time to write your first shader, a fragment shader. Fragment shaders can alter the color of a surface, be it a sprite or a 3D object.
Shaders are a type of resource in Godot, so their creation is the same as any other resource. Create a new folder in the shaders folder named fragment. Right-click the fragment folder and select Create New ▸ Resource….
Search for “shader” and double-click the first match that gets selected: Shader.
You’ll now see a Create Shader dialog with some options. Change the Mode to Canvas Item.
Next, name this new shader UV_to_color.gdshader and click the Create button.
Double-click the shader you created to open it in the shader editor.
This editor is similar to Godot’s script editor, but more minimal. It supports auto-completion and syntax highlighting, but you won’t be able to debug shaders or search for help about functions.
Fragment Shaders
The code you’re seeing here is the bare minimum required to create a fragment shader. It’s written in Godot’s own shading language called GDShader, which is similar to GLSL but simplified. It’s a high-level language with a syntax based on the C programming language.
This shader consists of two parts: the shader_type
and three functions: vertex
, fragment
and light
. The shader_type
tells Godot what kind of shader you’re working with. In this case, it’s a canvas item shader meant to change the color and/or texture of a canvas item, the class all sprites and UI elements derive from.
The functions are the heart of the shader, they’re called processor functions and are the entry points of your shader. For example, The GPU will call the fragment
function for every pixel of the canvas item you attach it to, along with some information about that pixel.
To apply this shader to a sprite, drag icon.svg from the FileSystem onto the 2D viewport first. This will add a Sprite2D node with the icon as its texture to the scene. Name this node UV.
Select the UV node and expand its Material category in the Inspector. You should now see the Material property with a dropdown next to it.
One way of applying the shader is by creating a new ShaderMaterial here and picking the shader file as its input, but I’ll share a much faster way! Simply drag UV_to_color.gdshader from the FileSystem onto the Material property. This will create the ShaderMaterial for you.
Click on the new ShaderMaterial resource to show its properties and you’ll notice the shader is already set. Nice and easy.
Now take a look at the sprite again and you’ll see nothing has changed. This is because your shader isn’t doing anything yet. Time to change that with some code.
Edit the UV_to_color shader’s fragment
function like below and press CTRL/CMD-S to save it:
void fragment() {
COLOR = vec4(UV.x, UV.y, 0.0, 1.0);
}
Godot updates shaders right away in its editor, so there’s now a dramatic change to the sprite. It looks like a colorful rectangle of gradients.
To explain why this happened, I’ll dissect the code you added:
- Everything inside the curly brackets of the
fragment()
function runs on every pixel of the sprite. You can compare this to a GDScript for loop:
for pixel in canvas_item.pixels:
fragment(pixel)
-
COLOR
is a built-in variable that represents the color of the current pixel. It’s avec4
, a vector with 4 floating-point components:r
,g
,b
anda
, representing the red, green, blue and alpha components of the color. By changing the value ofCOLOR
, you change the pixel color. -
= vec4(UV.x, UV.y, 0.0, 1.0)
is an expression that returns avec4
with the values ofUV.x
,UV.y
, 0.0 and 1.0 for the new pixel color in RGBA order. In this case, the blue component is absent by setting it to 0.0, while the alpha component is set to 1.0 for full opacity. -
UV
is a built-in variable that represents the normalized position of the current pixel. It’s avec2
, a vector with 2 floating-point components that range from 0.0 to 1.0. A pixel in the upper-left corner has a value of (X: 0, Y: 0) and a pixel in the lower-right corner has a value of (X: 1, Y: 1). The X value ofUV
gets mapped to the red component of the color, while the Y value gets mapped to the green component. The yellow color at the bottom right is caused by mixing the red and green components together.
In summary, the UV_to_color shader you wrote maps the UV
variable to the COLOR
variable. This creates a colorful gradient that represents the UV
variable. It’s important to know that the UV
variable represents the normalized position of a pixel as you’ll be using it a lot in the next shaders.
Congrats, you created your first shader!