Having recently learned about render textures and replacement shaders in Unity, I had the chance to put that to use creating to create stylized reflections for our game.
Creating a basic reflection is pretty simple: first attach a camera to the reflective object. If we were being physically accurate, we would have the camera point away from the building. But we are not being physically accurate! Instead we will point the camera at the building, a little behind the main camera in depth, to give the impression that the building is further away. Since the game is 2D, it doesn’t matter whether we look at it from the front or the back.
Next we will create a render texture and tell the camera to render to that texture by assigning it to the Target Texture of the camera:
Now, if we drag that render texture to the building, Unity will create a material with the render texture assigned to the Albedo.
At this point, we should have a result that looks something like this:
As you can see, everything the reflect camera sees is rendered onto the building. One unideal feature is that the building itself is seen by the camera as well, creating a recursive look we don’t want. We only want the main 2D environment features to be reflected. Our game also has a few other features that shouldn’t show up in a reflection.
Dealing with this can be relatively simple depending on the organization of your game. Since our game makes a lot of use of the layers feature in Unity (used for mainly for organizing different types of collisions) we can use the layers to create a Culling Mask for the reflective Camera.
If we put the building and other features we do not want drawn on a layer that is not included in the Culling Mask, it will not be rendered by the camera. This gives us a cleaner look:
For our game however, full color reflections can be a bit distracting (so many slime reflections!), and doesn’t fit as well stylistically for our game, so we decided to try using silhouettes instead.
This is where Replacement Shaders are useful. We basically want to render the same geometry but with a different shader (instead of the original full-color shaders).
We add to the reflect camera a simple script:
This tells the camera to replace all shaders with replaceShader. The second argument is used to specify tags to look for on the shaders to specify which ones are replaced, but in this case we want to replace all of them with the same shader so we use an empty string.
Now we need to write the replacement shader. Since some of our objects are transparent, we will build off of the transparent standard shader.
In the replacement shader we still have access to the arguments passed in to the original shader i.e. the _MainTex that gives us the original textures of the objects. We will use the _MainTex as normal to get the alpha for transparency, but instead of using the original texture colors, we will assign the albedo to black to get only a silhouette.
Now when we hit play, our reflect camera will use this shader to render everything, giving us the final result we want!
Ideally, if we have multiple reflective buildings, we’d want this to all be in a single script that we could attach any object and have it generate everything we need (the render texture and camera) instead of us having to manually create them, but I’ll leave that for later 🙂