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?
Overwriting Colors
For your next shader, you’ll be manipulating the color of a sprite. Repeat the steps you did for the previous shader. First, create a new shader named solid_color.gdshader in the shaders/fragment folder. Next, drag another copy of icon.svg from the FileSystem into the viewport and name it White. Now apply the new shader to it by dragging the shader to its Material property.
Open the solid_color shader in the shader editor to start working on it. This time, the original colors of the sprite should be overwritten by pure white while keeping the alpha intact. You already know how to change the color of a pixel using the COLOR
variable, but for this shader you’ll need to know the original color of the pixel first. To do so, add the following line to the top of the fragment()
function, inside its curly brackets:
vec4 color = texture(TEXTURE, UV);
This stores the color of the current pixel in a vec4
variable called color
. The texture
function is a built-in function that performs a texture read at a specific UV coordinate. The TEXTURE
variable is a built-in variable that represents the texture of the current sprite. This function returns a pixel color in RGBA format.
Now that you have access to the original color, you can define what color you’d like the pixel to be using a variable. Add this line to the fragment()
function:
vec4 new_color = vec4(1.0, 1.0, 1.0, 1.0);
This stores a pure white color in a vec4
variable called new_color
. To apply this new color to the pixel, add these lines to the fragment()
function:
color.r = new_color.r;
color.g = new_color.g;
color.b = new_color.b;
This overwrites the original red, green and blue components of the pixel with the ones in the new_color
variable. Note that the alpha component is still intact as you don’t overwrite it.
To actually change the pixel color, set the COLOR
variable like before:
COLOR = color;
Now save the shader using the CTRL/CMD-S key combination and look at the sprite again. It should look like a solid white color, while keeping its shape intact.
A shader like this can be useful to keep the identity of a character hidden by overwriting its color with black for example. Another use case would be to flash a sprite when it gets hit.
Manipulating Colors
In this section, you’ll learn how to manipulate the color of a sprite for a practical use case: making it grayscale. You can use this effect for flashbacks or for dramatic moments in your game. Like before, create a new shader named grayscale.gdshader in the shaders/fragment folder. Drag a copy of icon.svg into the viewport and name it Grayscale. Now apply the new shader to it by dragging the shader to its Material property.
Open the shader and think how you’d make the pixel colors grayscale. An often used method is to take the average of the red, green and blue components of the pixel and average them. I recommend you to try to create this shader yourself before moving on. Use the code of the previous shader and try to change it to make the sprite grayscale.
I hope you gave it a shot! No worries if you didn’t or if it didn’t work as planned, I’ll explain how to do it below.
To create a grayscale shader, add the following code to the fragment()
function:
vec4 input_color = texture(TEXTURE, UV); // 1
float gray = 0.21 * input_color.r + 0.71 * input_color.g + 0.07 * input_color.b; // 2
vec4 output_color = vec4(gray, gray, gray, input_color.a); // 3
COLOR = output_color; // 4
Instead of using the average of the RGB components, this uses the luminosity method to create a grayscale effect. This is a weighted average based on human color perception. Our eyes are more sensitive to green colors than to red or blue so its value is weighted more. This method gives a more natural grayscale effect.
Here’s how the shader works:
- Store the pixel color in a
vec4
variable calledinput_color
. - Calculate the grayscale value using the luminosity method and store it in a
float
variable calledgray
. - Create a new color named
output_color
and give all of its components the value ofgray
, excluding the alpha component. - Apply the new color to the
COLOR
variable.
The sprite should now be a nice grayscale color.
Vertex Function
Until now you’ve been using the fragment
function to manipulate the color of the sprite. But what if you want to manipulate the position of the sprite? That’s where the vertex
function comes in. You can use this function to move, rotate and scale the vertices of a sprite in your shader. This is useful to create cool effects and animations.
Moving Vertices
To start creating your first vertex shader, create a new folder in the shaders folder named vertex. These folders aren’t necessary to create a working shader, but they do help with organizing your shaders.
Now create a new shader in the vertex folder named offset.gdshader. Use the same parameters like you did with the previous shaders.
Next, drag icon.svg into the viewport and name the node Offset. Drag the offset shader to its Material property and open the shader in the shader editor.
Take a closer look at the shader. Its vertex
function is a processor function like fragment
. Unlike its counterpart, the GPU will call it for each vertex of the sprite instead of each pixel. By default, canvas items are a quad and have four vertices, one at each corner. Each of these vertices have a position and a UV coordinate.
To change the position of a vertex, you modify the value the VERTEX
variable. To give this a try, add the following line inside of the vertex()
function:
VERTEX += vec2(25.0, 0.0);
Like the COLOR
in a fragment
function, VERTEX
is a built-in variable. It’s a vec2
with 2 floating-point components representing the X and Y coordinates of the vertex. As it gets called for every vertex, the line above shifts all the vertices 25 pixels to the right of their original position.
You can see the change after saving the shader and selecting the sprite in the editor. The sprite will clearly be offset to the right from its selection box.