Hello everyone!
Introduction
I have been asked a countless number of times to prepare a series of shader tutorials. More specifically, a series of shader tutorials that will help Game Maker users approach this complex topic without being incredibly overwhelmed. Programming requires a certain mindset and shader programming requires yet another mindset to fully grasp what is going on. That being said, I am really going to slow this down in hopes that nobody gets lost.
What is a Shader?
For these examples, I will be using Game Maker: Studio. GM gives you several options for shading languages, but I will be using the default: GLSL ES. This is a shader programming language that is based on the OpenGL shading language, as well as C++.
A shader exists to return a vec4 to the graphics pipeline (at this point I would hope that you have a solid grasp on vectors, as containers). The vec4 contains the red, green, blue, and alpha values of a single pixel. Every frame a shader runs for every pixel on screen. The return value is the pixel that you see rendered on screen. If you do not explicitly set a shader, a pasthrough shader will be called for you.
The Passthrough Shader
For now, we will call a passthrough shader ourselves. To do this, right-click on the shaders tab and choose to create a new shader. GM will create a passthrough shader for you, by default (I called mine shdrPassthrough). A shader can basically be applied to any form and any number of draw calls (a sprite, a entire surface, the application surface, etc). I will create a simple object that let’s us toggle our shader(s) on and off and draws a sprite accordingly.
Create Event
Step Event
Draw Event
From here, place the test object in the room. You can press the space bar to toggle your shader on and off, but you will be unable to see what is happening because your shader is the same as the default passthrough shader that is being called while yours is off.
Your First Shader
Ok, so the first thing that we will do is experiment with the Fragment Shader. You will notice that when you open a shader, there are actually two tabs open; a vertex shader and a fragment shader. The vertex shader is called for every vertex, while the fragment shader is called for every pixel. Open up the fragment portion of your shader file and you will notice that the last line of main() sets a variable called gl_FragColor to a particular value. This is the return value and final rendered RGBA value of your pixel. For our first attempt, we are simply going to change every pixel to a solid red. Note that these values are normalized and range from 0 to 1, rather than 0 to 255. Here’s what this would look like:
That’s incredibly simple and not very useful, but you have successfully written your first shader! We can take that a bit further by blending each pixel in the original image with red, rather than just replacing it with a solid color completely.
We’re skipping a few steps here, but just be aware that gm_BaseTexture refers to the texture that you’re currently running your shader on and that v_tex is the texture coordinates passed in from your vertex shader (in this case, it should be unchanged). So you essentially have a position within your texture (a single pixel) and you’re multiplying it by your red value. You are doing this for every pixel in the texture.
Again, a very simple effect that you may have stumbled upon before. You can also achieve this by setting your object’s image_blend value to c_red. You have now accomplished the same thing via shader!
I’ll leave you all with this for now. I am trying to take this very slow both for people who are new to shaders, as well as people who are new to programming and GM, in general. Play with color inputs and see what other effects you can come up with.
More to come soon,
-Z