Search code examples
unity-game-engine3drenderingshadertransparent

Unity3d, Single transparent object's drawing order is mixed up


Image of my sandwich

So I'm using URP, lit materials.

I have this sandwich object with SINGLE fbx model with one submesh only. Sandwich is made in order of Bread - Tomato - Cheese - Ham - Lettuce - Bread

When opaque, it works fine, but when sandwich's material is set to transparent (but alpha is full 1) its rendering order get's messed up and the ham renders on top of everything and the bread under everything.

Why's unity even acknowledging them as seperate objects? It's technically a single mesh with single texture.

Since they are a single object I can't even foddle with the render queue. Would there be any solution to this? Thanks in advance.


Solution

  • You can not really use a transparent shader on a mesh that has self intersection or overlap. That's because transparent shader do not write to the depth buffer but only check against the depth buffer so transparent objects are still occluded by opaque geometry.

    Unity draws the opaque geometry first and it sorts the objects from front to back to avoid unnecessary overdraw.

    Transparent objects are rendered later and those objects are sorted back to front to follow the painters algorithm so that transparent blending works properly. However Unity only sorts objects, not individual triangles. The triangles of a single mesh are usually rendered in order as they appear in the index buffer of the mesh. So when rendering fully opaque objects with a transparent shader, you get exactly the result you've shown. Which parts would be seen on top just depends on the order of the triangles. Generally those rendered last would end up on top. So it even matters from which side you view it.

    Your sandwich parts are all 100% opaque, but I guess you want to fade out the mesh at some point? If you just want to "fade out" the object, you could use a stipple shader as I suggested over here. This is the blog post I referenced in my post.

    There is no easy solution for this problem. To have your object rendered correctly, all the triangles would need to be sorted in the correct way.

    Depending on the requirements it's possible to use a transparent shader that actually writes to the depth buffer and craft your mesh in a way so the "outermost" triangles are rendered first. As a result you would not see the "inside" of the mesh unless you look at it from the sides where none of the outer triangle are blocking the view. Though this only works of objects that can be split / sorted in this way.