How I fixed my billboards rendering wrongly

How I fixed billboards rendering behind my transparent water shader in Unity

If you’ve tried written your own custom shaders like I have in Unity, you know how much of a headache they can be sometimes. And sometimes, the solution to a problem seems obvious but you can’t quite figure out how to solve it.

One of these obvious-but-hard-to-solve issues I had while writing a custom water shader recently is having billboards, such as trees and detail objects drawn on the Terrain, rendering behind your shaders (despite being in front or above a certain surface). This results in the scene looking like this.

Trees and detail objects, when drawn on Unity’s Terrain using Terrain painting tools, are automatically converted into billboards when viewed from a certain distance away. The setting is controlled by the Terrain’s Billboard Start property.

Transparent Object rendering over Unity Billboard Speedtrees
The SpeedTree billboards are rendering behind the water’s surface, despite being above water.

This is a problem that occurs with shaders that are assigned to use the Transparent Render Queue. An easy fix would be for me to increase the Billboard Start property on my Terrain, so that my trees don’t turn into billboards at noticeable distances.

Terrain Settings - Billboard Start
Increasing the Billboard Start attribute will fix my problem, at the expense of speed.

However, I decided I wanted to fix this issue for good, instead of designing around the problem. Hence, I did some research, and found a simple solution.


Article continues after the advertisement:


Changing the Render Queue of the Shader

Although shaders have SubShader tags that reference the different Render Queues (Background, Geometry, AlphaTest, Transparent, Overlay), we can set our shaders to use a custom index relative to each of these queues by adding an integer offset to the Queue tag.

Each of those five Queue SubShader Tags have their own index values — you can refer to them in Unity’s Documentation on Rendering Order. By adding an offset to the SubShader tag, you can create an unnamed Render Queue that will be rendered based on its index.

For example, a Shader with the Queue Subshader tag Transparent-200 has an index of 2800, and will render before the Transparent Queue.

However, I could not find a way to change the Render Queue of Unity’s Speedtrees. Hence, I will have to change the Render Queue of my own shader instead. I found that a Queue tag of Transparent-200 worked for me. Hence, I tagged my SubShader as follows:

{ "RenderType" = "Transparent" "Queue" = "Transparent-200" }

Afterwards, when I went back to my scene, my billboards started rendering correctly (i.e. in front of the water when the tree is above water).

Transparent Object rendering behind Unity Billboard Speedtrees
My billboards are finally rendering right.

But why does this solution work in the first place, and why does this problem occur at all?

Why Unity got the rendering order wrong

Objects that use a Shader with a Render Queue index above 2500 (2501 and onwards) are considered Transparent. Hence, Unity will render them by sorting them based on their distance and render them starting from the objects furthest away. As a result, objects further away are rendered over objects closer to the camera. This distance is calculated based on the distance between an object’s Pivot and the Camera.

For large objects like a water plane, this distance may cause the Unity to incorrectly calculate the depth of some objects relative to our water plane’s, as the distance of the water plane’s position from the camera is always calculated using its Pivot.

The solution provided works as, after some experimentation, I found that the index value of the Queue used by the Speedtrees is around 2901 (or Transparent-99). Thus, by changing the Render Queue index of the Water Shader to a value of 2900 or lesser, Unity will render the Speedtrees over the Water even if the Speedtrees are further from the camera and thus solving this issue.

I hope this article helped you solve this problem, as well as potentially solve similar problems that might occur with Render Queues!


Article continues after the advertisement:


Leave a Reply

Your email address will not be published. Required fields are marked *

Note: You can use Markdown to format your comments.

For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

I agree to these terms.

This site uses Akismet to reduce spam. Learn how your comment data is processed.