50 Shaders of Gray

Shaders are hard. Overall, they’re not something I’m used to working on and I find myself mostly stumbling around in the dark with them. After a week of bashing my head against the wall, I finally sort of understand what I’m doing.

For the uninitiated, shaders are small programs that are used to display various graphics on your screen. If you’ve played pretty much any modern video game, you’ve seen shaders at work whether you knew it or not. They are able to take existing artwork (3D or 2D) and run processes upon them to get all sorts of desired effects; shockwaves, outlines, changing colors, invisibility… They run on the GPU rather than the CPU which allows for massive amounts of computations in relatively small amounts of time. So, want to make a character dissolve like it’s being teleported? Or perhaps get a nice water effect like Wind Waker? Well, you’re gonna need a shader for that.

For the past week I’ve been trying to get the rainbow outline shader coded. I went through a ton of trial and error and eventually had to cobble together several examples I found, muck with the code, change it from using a TEXTURE to a SCREEN_TEXTURE and various other garbage.

I started with this sort of thing:

Shader from Godot Shaders

This was fine, but not quite right. Notice how the outline is only on one side of the objects. I needed an outline that spanned the whole object AND was dynamic enough so that I could use it on any scene, regardless of what objects appear in the scene. With that in mind, I kept digging and got to this:

Now, this was way cooler for sure. Has more of a neon TRON look to it which I can’t complain about. However, the edges aren’t really animated and I wanted something more punchy instead of just a laser rainbow. So, I kept digging, and smashing my head against the keyboard.

It took several more days to really “get it”. I had to keep playing around with how I was loading the texture and which texture I was using (screen vs object’s). I started messing with duplicating the objects into a viewport and using that viewport’s texture as the texture for the shader. That may have worked eventually but was a MASSIVE amount of annoying work to get any result.

Finally, it sort of dawned on me that I needed to simplify what I was doing. The shader itself is complex. But, like any good programming problem, it can and SHOULD be broken down into small pieces. I decided I needed to break the shader up into the following parts:

  1. Generate a donut shaped “mask” to show/hide the shader

    1. This wasn’t too terrible to find. I definitely didn’t come up with it but it’s basically just making two circles, a white one and a significantly smaller black one, and using that to blend with the final pixel.

  2. Generate a rainbow color

    1. This is surprisingly easy to do and I found numerous examples on how to do so for shaders. Here’s the example I ended up using.

  3. Generate an inline

    1. This was helpful to make sure that the actual shader didn’t mess up the smoothness of the edges. It’s a bit of a weird issue but it took me forever to realize this was a good solution.

  4. Generate an outline

    1. This is by far the meat of the problem as it actually has two more parts to it

      1. Generate an actual outline that goes from the inline to x pixels away from the object.

        1. For this, I was able to find this shader which uses some fancy math to build the outline.

      2. Mix the outline with noise so that it looks animated like fire.

        1. This was a complete pain ><. I got lucky and found this shader that does this sort of thing without a noise texture but without that I’m sure I’d have to come up with something completely different. The hard part was converting it to use the SCREEN_TEXTURE and making sure it actually was able to find the edges of the objects.

Phew! After all that, I was FINALLY able to bring about my goal: I call it a FLAMEBOW!

I’m so thankful for the https://godotshaders.com/ website, I know I wouldn’t be nearly finished by now without it!

For anyone interested, I’ve uploaded the final shader here.

Previous
Previous

What Exactly is Going On?!