Weekly Shaders

Weekly Shaders

I am getting closer and closer to graduation, which means that I am getting busier and busier. Sometimes, I find it helps to take a mental break from intense focus and think about something else for a little bit. So, today I’d like to write about something I find fun to program.

One of the things that originally got me interested in programming was the visualization of patterns and the mathematics behind them. It naturally led me into the world of Computer Graphics. My first advanced computer science course was a course on writing shaders, which might be my favorite things to program. A shader, if you don’t know, is a piece of code that can efficiently modify an input texture of a graphical object using the GPU. An example of this might be taking the shirt on a character and making it look wrinkled by altering the texture’s surface normals, or making water feel turbulent with the use of some Perlin noise.

I find that shaders are often quite beautiful, not just in the visualization, but also in the simplicity of the code. While the shader is operating on thousands of pixels many times per second, the GPU handles all of the multi-threading of this process. So, the written shader code only has to care about one pixel at a time. Fairly complex representations of patterns can get boiled down into just a few lines of code.

Over the weekend, I decided that I wanted to write some shaders for fun. Nothing practical at all, but I wanted to create some nice, aesthetic pieces as a break from my normal stream of thought. I started simple, creating nothing more than a circle on a flat plane. The fragment shader code looked like this:

// is v within a circle of center c and radius r?
bool circle(vec2 v, vec2 c, float r) {
return distance(v, c) <= r;
}

void main() {
vec2 pos = vPosition.xy;
vec3 color = vec3(0);
if (circle(pos, vec2(0), 1.0)) color = vec3(1);
gl_FragColor = vec4(color, 1.0);
}

vPosition is our input pixel at position (x, y) in a region going from -1 to 1 in both axes. When applied to every pixel in our region, only the pixels with positions that would fit inside of a circle centered at (0, 0) (vec2(0)) with radius 1 will be colored white (vec3(0)); the others will remain black (vec3(0)).

This is pretty uninteresting, what if we made it move a bit? We can pass in variables from our external program, known as uniforms to the shader, which are applied uniformly throughout the entire texture. In this case, we pass in time as uTime, which will update at every frame:

 void main() {
vec2 pos = vPosition.xy;
vec3 color = vec3(0);
if (circle(pos, vec2(cos(uTime), sin(uTime)), 1.0)) color = vec3(1);
gl_FragColor = vec4(color, 1.0);
}

Now, our circle moves in the path (cos(uTime), sin(uTime)), which you probably know as a circular pattern.

I began to make small changes to the shader, one by one. What if I didn’t want to render a circle, but some disc?


bool circle(vec2 v, vec2 c, float r) {
return distance(v, c) <= r;
}
// is v within the disc centered at c with inner radius r1 and outer radius r2?
bool disc(vec2 v, vec2 c, float r1, float r2) {
return circle(v, c, r2) &&! circle(v, c, r1);
}

What if I wanted lots of discs moving at different points in time? If I wanted to change the color of some discs? Every small alteration created a new pattern. I eventually wound up with three I was happy with:

http://cdefanti.github.io/shaders/shader1/index.html

I enjoy the way that simple shapes moving in simple patterns can create something more complex when put together (which is the whole idea behind most shaders!). Sometimes, they can create bizarre illusions. In the first one, do you think the discs move in a circular pattern? Look again, and look carefully at each one individually!

I had fun spending an hour or two making these, and I hope you had fun looking at them. I plan to do more along the same vein, exploring other simple patterns. Keep an eye out for (hopefully!) weekly updates here:

http://cdefanti.github.io/shaders/index.html

Connor DeFanti
Posted on:
Post author

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.