Monday, April 20, 2015

Unity Shader & Material: Fade by Distance

Recently, I switched over from UDK (Unreal Engine 3) to Unity to help with some vfx on a project. My friend I am working with asked if I could make a fog effect that faded when the player gets closer to it, so that they never actually touch the fog walking through it. I had done a few things with object and world position in UDK before, but wasn't sure if Unity had the same capabilities. When I first opened unity I found that there was no material editor like UDK, but that shaders were the equivalent and created entirely with scripting. Having no scripting experience and no time to learn it, I sought out a different workflow. Someone suggested a 3rd party plugin called Shader Forge, which is a godsend that is a node based shader editor (and a godsend for code challenged people like myself). I highly recommend supporting the creator and downloading Shader Forge for Unity, especially if you are starting out in Unity, or coming from UDK/Unreal 4. You can find Shader Forge HERE, and it's website and node documentation HERE.

After messing around in the editor, researching nodes, and finally getting very decent fade-by-distance shader/material, someone asked me if I could post my setup and findings for documentation and reference. So here it is, my full setup that I'm testing, as well as the setup for just the fade by distance. First I will cover my node tree, then the player/object distance setup, followed by some useful tips I discovered while experimenting. I am by no means an expert in Shader Forge, Unity, or material/shader creation. The information that follows is what I have learned just from my experience creating this effect in Shader Forge.


My full node tree, which combines the value output by the distance between the viewer and the object (in this case, a particle system) with an alpha erosion setup. My setup uses the value output by player/object distance twice; once to drive the alpha erosion, and the second time multiplied with the erosion for an overall fade out. I included a slider to divide the distance output, as my team is still working out the unit scaling of the levels. This gives me or a level designer versatility to adjust the scale of the distance fade. After the scale fade, I have another slider subtracted to fine adjust the distance the material completely fades out. My final slider for the fade is a decimal value subtracted from the distance value and multiplied after the alpha erosion for control of when the material is to evenly fade out. A big thanks to Bill Kladis and his tutorial on alpha erosion!




For my player/object distance setup, I will be referencing UDK a few times, but will also include any information needed to understand this effect if Unity/Shader Forge is your first experience with this kind of thing. 
The main composition of my player/object fade is the 'View Pos.' node, the 'Object Pos.' node, and the 'Distance' node. The 'View Pos.' node refers to the viewer's XYZ position within the game space, and likewise the 'Object Pos.' node refers to the object's XYZ position that has the material applied to it. The 'Distance' node takes the X, Y, and Z values of the two inputs (in this case, the distance between the player and object) and outputs a single value. The closer the distance between the two, the smaller the number. My assumption is that the distance within the Unity editor is set, so the larger your assets, the larger the distance of the player's perspective, and hence the base value control. This gives the shader more life, as it can be tuned for both large or small scale games, and using a slider node gives the user the ability to test in real time rough inputs and get an idea on what value they will need. KEEP IN MIND: this shader will work as intended with individual assets, however when applied to particle systems, the shader takes the object position of the system node. Please read further for more information on use in particle systems. 


For UDK/Unreal material users, Unity's 'View Pos.' node (through functionality testing) seems to be the equivalent of Unreal's 'Camera World Position' node. This relation seems to hold true as well for both 'Object World Position' (UDK) and 'Object Pos.' (Unity). I DID try various combinations in Shader Forge of the 'Screen Position' and 'World Position' nodes with View and Object position, but was not getting results similar to my effect in UDK. It is quite possible, however, that one of these is actually a better choice than my current setup and I just needed to check a box or add something else to it.



Some things to keep in mind when using this player/object distance fade setup:

 Unlike UDK, who's player/object distance seems to work on a per-particle basis (distance applies to each particle), Unity's works between the particle system node and the viewer distance. This is roughly illustrated in the above image.

What does that mean for the effect? It means that you can't use just one particle system for a whole room or hallway as something like ambient mist or fog. Depending on the size of the effect and the player's distance from the system node, particles may not fade as the player passes the furthest particles, your particles on the far side of the node will fade the same as the ones in front of you, or all of the above. My only suggested workaround for this so far is to talk to your level designers or open up some levels and find out the unit sizes of your various rooms. Keep your particle emitter volumes small, place as many of the nodes as you need to get the desired effect, and then create a room prefab of the combined particle systems. That way, you or your level designers can place the pre-constructed fog volumes into the hallway or room without them having to constantly place multiple particle systems themselves.


 Some other cool stuff!

Something cool I found while messing around with the particle systems for my fog volumes (Unity) was changing the Sort Mode to: By Distance. When the player approaches a particle that is between the camera view and the particle system node, the particle will actually get pushed "out of the way" and around the camera! It gives a pretty cool effect when combined with a fade, and gives the feel of a curtain parting for the player.

 This, again, seems to work off the particle system node and not the particle systems itself when it comes to distance. I'm not sure what controls the distance the particle decides to move out of the way, and I am by no means an expert on this sort mode. This was just some cool info I found just messing around, and at this time I'm unsure of it's full function and limitations.

A demo of my player/object distance fade with placeholder fog/smoke textures. Shows both sorting modes.



No comments:

Post a Comment