This is the second post in a series about a shader side project of mine, so make sure you’ve read the first one or this won’t make much sense!
In this post I want to talk about the script I use to interface with this weird vertex wobbling system I’ve made. Before I wrote this script, the shader on it’s own was unruly and impossible to get usable results out of unless you got very lucky with the parameters used. The brilliant thing about shaders is that they can do a lot of maths very quickly using your GPU. The not so brilliant thing is that it can be tricky passing information between shader programs and regular CPU scripts or programs. I have no idea if the way I do it is the best way to do it, but I’ve got some pretty good results with it so far.
Getting your mitts on those shader variables
In my shader program there are a few properties that I can access from outside the shader. For toggling my different maths on and off I actually use a float parameter rather than a bool (apparently shaders don’t like them) with a “[MaterialToggle]” flag that makes them look like a check box in Unity. Very useful if you want to turn of bits of your shader at runtime. Generally speaking, it’s not a great idea to do a lot of CPU-style logic operations (like if statements) in a this kind of shader because it’s going to do that for every vertex. Ideally you’d want to make a custom shader with the exact combination of stuff you want to use and never use any if statements, but this approach is what I find most useful for just playing around.
The above shows the shader options in Unity and how you set it up in the properties section of a standard shader file. Adjustable values (e.g. X, Y, Z) correspond to amplitudes of the modulations I explained in the last post. “Time Scale” values refer to a scaling factor for each type of deformation, so you could have a spherical modulation running at double the speed of a Cartesian deformation for instance.
OK, hands up, I tried to make something with nice time scaling differences but could make anything that looked good. The following undulating flame vine uses Spherical time scaling 1 and Cartesian time scaling 0.7 separately, then shows the final product at the end. Actual settings for the final product are shown above. In this case, the spherical deformation adds a sort of fluttering effect to this fiery thing. Changing the time scaling will modify the intensity of this effect.
Using scripts to control bits of shaders
Having a shader property value visible in the inspector is great for manual tweaking, but we’re coders, right? What if we want to do something more interesting? Well if you’re familiar with C# and object oriented programming, you can view shader properties as a kind of public variable. You can access and modify these directly through scripts in Unity by using a material.SetFloat(“PropertyName”, value) call. This can be extremely useful and I’m barely scratching the surface in my implementation.
As I mentioned earlier, the vertex deformation shader I wrote about in the last blog is great fun but completely unstable. What I found when playing around with settings is that I’d often find awesome parameters combinations that’d produce great results… for about 3 seconds before my meshes would explode into a mathematical soup of nonsense of no use to anybody. Armed with the ability to pass information from a script to the shader, I figured out that I could control the very passage of time itself. Now time is just a variable that I manually increment, pause, reverse, reset… whatever I want. What this all amounts to is the ability to produce steady states in which the vertices deform within aesthetically pleasing bounds.
Pretty sweet! The C# code to achieve this is fairly simple:
All we’re doing here is using Update() to increment or decrement a timer float m_timer every frame depending on the bool value m_timeDir to denote time direction. The coroutine ReplayVerts() is used to control the flow of time by simply waiting for a given amount of time to pass, swapping the time direction and repeating forever as required.
I’m now experimenting with producing unique and interesting animations with this system. One of the simpler ones I’ve managed to pull off so far is a basic heartbeat effect.
We might use this kind of thing for the horror VR game I’m currently developing Late Night Shop. Hopefully this system should produce a lot of cool surreal stuff with a bit of experimentation. I haven’t done a lot more with this for a little bit but I’ll hopefully do another post about more sophisticated animations once I figure out how to do that.