Introduction to Shaders in Godot 4
- 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?
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
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
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
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.
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
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
- Calculate the grayscale value using the luminosity method and store it in a
- Create a new color named
output_colorand give all of its components the value of
gray, excluding the alpha component.
- Apply the new color to the
The sprite should now be a nice grayscale color.
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.
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 += vec2(25.0, 0.0);
COLOR in a
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.