Dev Diaries 1: Shaders

Shaders.

 
Why am I looking at shaders?


I guess it must be that time of year again. The time where the sun starts to stay out a little longer, birds occasionally ruin my car, and most importantly, the time where I have to come face-to-face with creating custom shaders inside of a 3D game engine.

 
I hate shaders. I don’t even like the word. Shaders. The syllables give me shivers. It taunts me like a kid giving me the side eye at a spelling bee after he gets the word 'tessellation'. I hate that kid. Alright, maybe hate is too strong of a word. I like to think, often in situations like these, frustration is rooted in a lack of understanding. So maybe I just don’t understand shaders, and when I do understand them, I’ll love them. Maybe I'll date a shader, get married and we can name our firstborn 'Volumetric' or something like that. It’s unlikely.


So how did I end up here? Too much curiosity I suppose. I assume due to a bad upbringing or too much sugar in my diet. But also because I think games often look a little too same-y. It's often that I play a new game using the same asset library as the last game I played. Even in little things: The texture of a brick wall, the animation of a character running, or the same pseudo-realistic palette. It starts to dilute the experience to where it starts to feel like I've already explored everything there is to be explored within minutes. The only difference being that of the control scheme.


In a lot of games, that Breath of the Wild moment, where the camera zooms out and reveals this grand world you're about to experience for the first time is a hugely important ingredient in the magical spell you're about to be put under. It's your first big chance to wow the player. So what does it say about your PowerPoint if your first slide is copy-pasted? In my opinion, I'd rather that camera zoom out and show a bunch of shoddy pixels than nice ones if it at least meant they were new.


So welcome to my shoddy-looking landscape. There's no dramatic camera zoom or epic music. Nor is there an epic quest for the peace of the kingdom. We ain't got the budget for that. This new game project I’m working on is an adventure-puzzle game with a huge emphasis on trial-and-error and doing things you wouldn't normally think to try.




 
Exploration is the key to getting the most out of our game's concept. More importantly though, we wanted our core game to be able to convey that there is more to the game yet to be found, even when in some cases, there isn't. We identified early on, as part of trying to achieve that feeling, we needed to have a variety of navigable areas. Our designed solution to being able to achieve that effect is by having all of the rooms at our game be easily and quickly created and shown from a constant perspective. That way, we don't have to worry about spending too much time on one particular area.


Since it’s a static camera angle, shown from an isometric perspective, we have to find some alternative ways to sell the presentation. I'm not sure yet, but I suspect having our background being an animated material versus a static color or texture would help a lot in making the game feel less project-y. Plus, animated backgrounds look cool and I like that. 


I made a quick mockup in an image editor of what I imagine the final product to look like. It's not animated, but I do like the general vibe it gives, and I like that no matter where you are looking, the space doesn't look terribly empty.






Here’s the problem: I know nothing about shaders. I think I might even have negative knowledge about shaders. ‘So why’, I’m assuming you’re asking in your usual sultry sailor tone, ‘would I want to read this?’


Let’s take a step back. I’m a software developer. I like video games. I’m a Mississippi 8 on a good day. I did alright in school. I’m pretty good at Shinobi for the PlayStation 2. I’ve been told I’m intelligent by people who have yet to be committed. I’ve been really into jazz rap lately. Most of my family still talks to me. I have made exactly zero dollars from game development. I should see a therapist and I probably won’t.


Maybe, after reading that overly-self-deprecating preamble, you’re interested in seeing how this strange little man handles programming challenges. Maybe you’re interested in my Shinobi strategies. I have doubts. More than likely, you’re a developer, like me, who hates shaders and you’re afraid to venture into the dark cold abyss alone.


And you want my Shinobi Strategies.


To be sure, this blog is going to be an experiment in itself. I’m going to do my best to take some time every fifteen minutes or so to catalog every step, failure or otherwise, that I take. Hopefully, by the end, one of us has learned something.


Well, if my friend who still farms dogecoin is right, the second best time to start is now, so let’s get in the weeds with it.


Let’s start with defining the problem


We want a 2D animation to play in the background of some of our game’s scenes. It should be geometric and simple, but with swirling movement so that it looks more alive. Kind of like a lava lamp. If you already have an idea of what I’m talking about, you’re probably thinking of 'Earthbound's battle animations. If not, think of what it would be like to spin in a chair a bunch of times then look at a tie-dye shirt. That’s kind of like the vibe we’re going for. 




So, let’s start with defining some basic criteria. At the end of the day, we want a material that:
  • Has a background gradient that fades between two colors and rotates around a center point. We want to make sure the rotation doesn’t look too linear or rigid.
  • Either takes in an image of a geometric shape or generates it, then places it many times over the material. The shapes should:
    • Interpolate between different colors
    • Move between two position
    • Warp as they move, stretching and dragging behind
    • Fade their opacity in and out.
  • Can be placed on a 2D plane without being affected by lighting or shadows
We'll probably change these requirements as we go, but for now they should be good enough to get us going. 

To start, we don’t know what we don’t know. Or at least I don’t.


R&D


I remember making some Java programs during college that made similar looking patterns. They weren't animated, but maybe we can derive some good information from them. I managed to find my old homework folder which looks like a mess because I was a junior. I got some of it working and it looks sort of like how I remembered, but its a bit different from what we are looking for and its using well-established algorithms that are for very specific patterns. This is the part where I would show off the code, but to be honest it was kind of a dead end. I decided to look elsewhere.


So I’ve done a bit of digging around and after a few minutes, I found this post from one of the the Mother4 fan game developers: https://blog.mother4game.com/post/123598820159/update-2-focus-on-the-background


This definitely seems to be something we can take advantage of, as it’s describing a process in which we generate similar geometric patterns to the ones we are looking for using different layers. There may be some difficulties translating this to Unity’s systems, but I think it’s as good a lead as any.


So what would we need to be able to recreate it?


Let’s think of the customization of our future shader. We want it to be able to take in 2 images, each one with different patterns. Then, we want to be able to adjust the opacity for each layer so that way they blend into each other. Then, we want to be able to set a speed for how quickly the warping animation is taking place.


In the Weeds

I know Unity has a package named “Shader Graph Editor” that we want to make full use of. After installing, I created a new ‘Unlit Shader Graph’. I spent a good amount of time playing around with some of the nodes and managed to get some basic stuff working, like this shader that has sort of the swirling effect that we want:




 
I also tried just putting some pieces together and seeing what would happen, but the result was… not so great: 




 
After that, I decided to keep to the script a bit.



I made some images that we can use as patterns instead of trying to generate them:







I searched online and found the documentation which shows how to set up some variables that we can use everytime we create a new material that uses the shader, so I created some for the images and the intended colors.


One of the first things I noticed from that blog post we’ll need is the position of the y coordinate, and there is a ‘position’ node, so that seems helpful!


I noticed that it outputs 3 numbers, but I can only seem to split the output into RGBA. After doing way too much digging, I’ve found that RGBA and XYZW are interchangeable in this instance, so we’re moving on. I connected the rest of the dots together for the formula and I seem to have completed it, but it’s having some strange behavior that doesn’t quite line up with what I was thinking it would be.


Instead of it looking like a cool 2D trippy image, it looks like a 3D worm. Did I just create life? Probably.


Let’s look over our nodes and see what is going wrong. I placed the shader onto a material just to see what would happen, and something interesting was occurring. It seems like the texture itself is moving, not necessarily the coordinates of the texture. Weird! I didn’t even know shaders could do that. I tried changing the ‘view’ parameter in the initial position node, but it just seemed to break things more. I believe the issue may be that I am getting the ‘y’ position of the object, and not necessarily the y position of the fragment.


I tried working through a couple of different solutions, namely using the node ‘screen position’ which I later learned was a way of making sure a texture was always being displayed so that the user could see it (kinda neat, but not what we want) and after quite a lot of trial and error, I figured out that by changing the ‘uv’ field of the image, we could change the pattern.


So I did a bit more research and found out that you can create a ‘uv’ node. I looked it up, a UV in shader-land is a way for the system to describe the coordinates where the texture lands on our model, more or less.


So I added that to the graph, split it like before and used the ‘G’, (which really means our V as I found out) in place of the Y position, and the ‘R’ (which means ‘U’ in this instance) in place of the X position. So now, it’s actually working! Well sort of, there’s definitely a lot to be desired. But now instead of moving the object itself it’s moving the texture projected onto the object, so I’ll take that as a win.


Let’s add another layer on top of this one. Ladies and gentlemen this is looking very promising indeed.




 

Since we added those parameters before, I can even change the texture whenever I make a new material meaning we can have a variety of backgrounds we can swap in and out depending on where the player is in our game world





I added some additional parameters for each layer, including:
  • Color
  • Opacity
  • Speed
  • Frequency
  • Offset

By offsetting the layer's values from each other, we can start to get some really whacky results. 

Still, I'm struggling with getting the edges of the image to be more faded than the rest, giving it that 'vignette' style effect. 

I've got an idea to adjust the incoming image patterns to include the effect before sending it to our shader. It's a straight-forward filter to apply in my image editor, so it wouldn't be introducing much in terms of time to create new materials.

You know those days where things just aren’t working out? Like it’s the holidays and you planned on getting a lot done cause you aren’t working, but then your car starts making that weird noise again and you dropped the ice cream bucket on the floor and the plastic cracked and now you got a bum muffler and a floor full of rocky road? I’ve been having one of those lately, I think a lot of people have. In times like that, I always try and work on something small to get my spirits back up. Not as a distraction, but more as a way to show that even when I'm down, I'm still able to move forward. 

And, well, would ya look at that, we got us a Christmas goose.


Final Showcase



Simple.

Geometric.

Wavy.



I like it, and I don’t like very many things. It's not perfect, and I'll undoubtably fiddle with it over the next however many months I'm working on this project, but what is? I’m proud of it and I think the little effect does a lot for making our game more of a unique experience.


We did it. We learned a little bit about shaders. I mean, hey, I’m not gonna invite them to a picnic, but they aren’t so bad. They’re just a little guy. A pretty funny little guy. Haha, shaders, stop! Come on, I’m ticklish! What was I doing again? I don’t know, it's getting late and I should probably go to bed.

 
Thanks for sticking with me up till this point, new friend. I don’t know you, but I hope you learned something like I did. And if you didn’t, maybe we’ll cross again, I’ll bring Shinobi.

Comments

Popular posts from this blog

Unreal Project Prototyping

A Year Spent Looking at One Room