Transparent objects sorting

Edit : Clarified my question based on discussion in comments.


Hi,

I found several questions concerning transparent objects sorting, but no answers cover my needs, so here is my question :

Problem :

It seems meshes in the transparent render queue are sorted ‘back to front’ using their distance from the camera. It is my understanding (please correct me if I’m wrong here) that meshes should rather be sorted using only their Z coordinate in camera’s space…

Example :

Let object B be in (3, 0, 1) and object A be in (2, 0, 2), both coordinates expressed in camera’s space.

While B and A respectively are at sqrt(10) and sqrt(8) from the camera, their Z coordinate in camera’s space respectively is 1 and 2.

Now it is clear that sorting A and B back to front by their distance will first render B then A, while sorting them by their Z coordinate in camera’s space will render A then B.

If you look at the schema you can see that the expected behaviour is to have A rendered first. As stated above, it seems Unity renders B first.

Schema

Questions :

  • Is that a Unity’s bug, or am I facing a special case ?
  • Is there a way to implement new render queues, assigning them a (range of) id(s), so that one can create custom sort algorithms (the two I now of being ‘some magic + front to back (ids <= 2500)’ and ‘back to front (ids > 2500)’ ?
  • If not, could this feature be added ?

Thanks for your help !

I got this mail from Unity yesterday:

Hi,

Good news! This issue has been fixed
for the upcoming Unity 3.5.3 release
(it will be out in a matter of days
now). You have to set your camera’s
transparency sort mode from code to
TransparencySortMode.Ortographic so
that objects are sorted based on
distance along the camera’s view.

Best regards, Elvis Alistar Test
Engineer

Edit:

## Perspective2DSortMode.boo
import UnityEngine
[ExecuteInEditMode, RequireComponent(Camera)]
class Perspective2DSortMode (MonoBehaviour): 
    def Awake ():
        camera.transparencySortMode = TransparencySortMode.Orthographic

You are right that the correct way to render transparent would be to sort them using the z-component in screen space. However that is not how the render pipeline works. The render pipeline render one mesh at a time using a shader. This makes it impossible to sort transparency per pixel. Therefor an approximation is used (sort geometry by distance to camera).

You can easily tweak the render queue, but you cannot solve this problem in a general way.

See:

http://unity3d.com/support/documentation/Components/SL-PassTags.html

We solved the problem of sorting our transparent planes by adding an extra vertex to them that effectively shifts the center of geometry, which Unity uses to sort by.

I just got another idea that might help you. You could consider using orthographic camera. In this case the sorting is like you want (the down side is that you do not have a perspective in your image).

If you think this is a bug in Unity, please submit a bug report from the Editor and include a project that demonstrates the issue. One of the QA team will take a look and work with Devs to figure out with you if this is really a bug or not. (Saying “it seems” is not sufficiently definitive!)

Please use the feedback site at feedback.unity3d.com if you want to request a new feature.

I found a ‘somewhat’ working solution to circumvent that sorting problem : I use a custom transparency shader that writes to the Z buffer all pixels with alpha values greater than 0, discarding all others.

Obviously this is not perfect at all since now all transparent objects with wrong sort order have an edge preventing objects behind them to be visible, but at least it is better than having entire polygons rendered invisible.

If no other solution is proposed here today, I think I will post a bug request to Unity’s forum.

Also I add here screen-shots of different results based on what have been explain before :

Expected result (A drawn before B) :
Expected

Unity’s result (B draw before A) :
Transparent - ZWrite Off

Result by adding ZWrite to transparent shader (B still drawn before A) :
Transparent - ZWrite On

Result by adding ZWrite and Alpha test to transparent shader (B still drawn before A) :
Transparent - ZWrite On - AlphaTest Greater 0