ShaderToy is a very handy tool that lets you create shaders inside your browser. It offers an easy-to-use interface where you can type in your GLSL code and watch it run immediately. You can also record your runs as WebM movies and share them on YouTube and other such websites.
Creating beautiful graphics with GLSL, however, is not an easy task. In fact, creating even simple geometric shapes involves a good amount of math, and requires a slightly different way of thinking. In this tutorial, I’ll show you how to use ShaderToy to create two circles and also animate them.
To be able to follow along, all you need is a browser that supports WebGL. Of course, if your computer is very old, I suggest you also make sure that it has a graphics card that supports OpenGL 2.0 or higher.
GLSL has no built-in function that lets you draw a circle, or any other geometric shape. In other words, you must always use math–and a little common sense–to draw anything with GLSL.
But first, you must understand that the output of your GLSL program is the color of just one pixel. In ShaderToy, that color, by default, is represented by the
fragColor variable. The program runs thousands of times to color all the pixels that are present in ShaderToy’s preview window. By using the
fragCoord variable, you can determine the position of the current pixel.
fragCoord variable directly, however, is cumbersome because you can’t be sure about what it’s values will be on different screens. To make sure that the coordinates of your pixels fall in the range (0,0) to (1,1), you must divide
iResolution. As you might have guessed,
iResolution is a variable containing the resolution of the preview window–or your monitor in full screen mode. Accordingly, make sure that the
mainImage() function has the following line:
Now, to actually draw a circle, you must remember that all points inside a circle are at a distance that is less than or equal to the radius of the circle. Let’s say that radius is 0.3.
Next, you must decide where the center of the circle should be. I’m going to use (0.4, 0.5) as the center. Although you can use two
float variables to hold the x and y coordinates seperately, using a
vec2 is easier, and more intuitive.
At this point, we can calculate the distance of the current pixel from the center of the circle using a GLSL built-in function called
If the value of
d is greater than
radius, let’s set
fragColor to black. Otherwise, let’s set it to be red, the color of the circle.
If you run your program now, you’ll see that we’ve created an ellipse instead of a circle. That’s because our preview window is a rectangle instead of a square. To correct this problem, we must multiply the x-coordinates of the pixels with the aspect ratio of the window. The following code shows you how–make sure you add it immediately after the calculation of
And now, you should be able to see a perfect circle.
Notice that the edges of the circle are jagged. To make them smoother, we can use the
smoothstep() function. Because the
smoothstep() function has a built-in if-statement, you can remove the
if statement in your program, and replace it with the following lines.
You should now be able to see a much smoother circle. That’s cool, isn’t it?
What if you want to draw another circle, one with a different color? Well, you just have one
fragColor variable. You must make do with it alone. Fortunately, doing so is not too difficult.
Create another circle using the following lines (add them before you set the value of
Of course, the code is a little repetitive, but ignore that for now. We’re still learning the ropes.
To render the second circle along with the first circle, we need to create two
vec4 variables, and add them. Each
vec4 variable will contain the color of each circle. Let the second circle be green.
You can now assign the
Run the program again to see the two circles.
I hope you found that easy.
Animating our circles will be far easier than creating them. I mean, you just have to modify their centers based on some parameter. What could that parameter be? Well, ShaderToy offers a variable called
iFrame, containing the current frame of your animation.
There are many different approaches to do this, but, for now, let’s say our animation has 400 frames. By dividing
iFrame by 400, we get a value between 0 and 1. We can then add/subtract that value to/from the x-coordinates of our circles’ centers. Here’s how:
Run the code now to see your circles moving.
You now know how to create shaders using ShaderToy. The shader we created today was extremely simple, but it is animated, and non-trivial. In future tutorials, we’ll creating something more complicated.