- Home /
The question is answered, right answer was accepted
How to fix transparent rendering problem
I'm getting incorrect rendering on objects that both are using the Unity transparent/diffuse shaders. If I move the camera back slightly the foliage gets obscured behind the tree trunk.
I've tried researching this but I can't find what seems to be the accepted solution. Some unity forum posts say to change the transparent ordering in the shaders, some say to turn on Z-Write buffering for all shaders, some suggest changing the camera settings, some say it's a bug to do with occlusion culling. What is the actual problem and what is the correct solution in this circumstance?
Since the question is answered and the images of the question are no longer available (due to external hosting) I'll close this question and lock the comments to prevent further bumping
Answer by Hoeloe · Jan 04, 2014 at 08:33 PM
The problem is due to how transparent objects are sorted in Unity. Usually, objects are drawn using the z-buffer, which draws a depth image as it renders the scene. This ensures that only the closest pixel is drawn, so everything appears in the right order. The problem occurs with transparent objects, or, more precisely, semi-transparent pixels. When objects are semi-transparent, they cannot be accurately written into the depth buffer. This is because the z-buffer makes the assumption that only one object will need to be drawn in any one pixel on the screen, in exchange for extremely fast sorting. Semi-transparent objects require multiple pixels to be drawn at the same point, and so they have to be drawn either before or after the rest of the image. Naturally, this produces some sorting errors, because per-pixel sorting, as found in the depth buffer, is not feasible. In Unity, the sorting method just takes the centre point of the mesh, and assumes that the entire mesh lies at the same depth value. The practical upshot of this is that if the centre of your transparent object goes behind another object, then the entire object will be rendered behind it.
Now that we've discussed the cause, let's talk about solutions. There are, in fact, a few possible ones, though they all involve trade-offs. I'll discuss 3 here:
Cutout Shaders. Cutout shaders solve this problem by applying a filter to the texture, giving every pixel a boolean value: visible or not visible. This allows complex shapes to be drawn, and since no pixel is semi-transparent, the depth buffer to be used. The trade-off here is with smoothness - you will lose the nice, soft edges you get with transparent objects. This is the most accurate solution, and for small, distant, or high-res textures, this is definitely the best one.
Segmented Meshes. This is a little more difficult to get right, and is only an approximation. The idea is that instead of having one large mesh, you separate it into several small ones, each carrying a part of the texture. Since the transparency sorting is on a per-mesh basis, this will allow the problem to become rarer, as each part of the object can be sorted individually. The trade-offs here are in performance, and difficulty of implementation.
Z-Writing. Another option is simply to write to the z-buffer anyway. This does work, but does produce some artefacts. Any other semi-transparent object drawn will either always be above, or always be behind, the object you're drawing, meaning depth sorting between this object and other transparent ones will simply disappear. This is often a good solution if you will very rarely overlap objects, or if your object is against a surface such that no other transparent object will pass beneath it.
There are more possible solutions, but these are some of the more common ones. The reason you have so much trouble finding one solution is that there isn't one - there are several. Each has their benefits and their drawbacks, and it's up to you to decide which suits your needs best.
Thanks so much for the in-depth explanation Hoeloe. Either cut-out shaders or Z-Writing seems to be my best options. Forest scenes with transparent bushes like $$anonymous$$e have been done a hundred times in games, what approach do you think you would personally go for in this situation?
I think it's important to mention I am targeting iOS with this game. And I'm aware cutout (alpha test) is not as good as alpha blend... cutout looks good, but do you know if Z-writing will be better for iOS performance?
Cutout is easily the best option for performance, and the one I would go for.
There are two more possibilities to consider:
4) renderQueue: if we are talking about different meshes (i.e., not within a single mesh), you can control the render order of these objects (or more precisely: of each material) using the shader/material property "renderQueue", which can be set via script. This will group all objects with the same queue and render them from low to high. (for example, opaque objects use 2000 as default, transparent objects use 3000, and so on. Disadvantage: each unique renderQueue value means an additional render pass/drawcall.
5) Z-pre-pass: you can modify your shader code to create an adittional first pass which does nothing except rendering the object(s) exclusively in the Z-buffer. See http://wiki.unity3d.com/index.php?title=AlphaVertexLitZ Advantage: transparent objects use z-Buffer information, and for complex meshes (which are unsortable) you can get smooth transitions especially when fading/switching between transparent and opaque. Disadvantages: You can no longer look "inside" semi-transparent objects, and other transparent objects behind the one you want to render will be invisible. Also, as it is an additional pass, it might be more expenstive (depending heavily on the shape of your objects).
Answer by vollchecker · Apr 14, 2016 at 12:16 PM
simply change the render queue: - select Object Material - change view to Debug Mode (Inspector Window top right drop down menu) - change Custom Render Queue value for example 3000 => 3100 - now your object will be rendered before other transparent objects
Thanks a lot, I totally forgot about that possibility, this solves my problem really well!
This solved my problem as well. (I had one larger tile-based mesh that forms a terrain/map in 3D, and wanted a plane the size of a tile to be able to draw over one of the tiles of the big mesh, semi transparent) $$anonymous$$any thanks.
Thanks, this helped a ton! I was able to set my particle's shader to 2900 so that they are behind my other transparent objects. Question though: The render queue value is not available for Unity's Standard shader with render mode set to Transparent. Is there another way to set the render queue value for this type of shader? Thanks!
Thanks, this makes so much sense and helped me a ton.
Answer by JEsteras · Apr 07, 2017 at 03:04 PM
Thnxx so much for the help!!!
In my case I had an open, top-down look into an apartment-like area. Since I wanted "sunlight" to come in through the windows I created a transparent plane to "block" the sunlight and prevent it from seeping in through the open roof, allowing it to shine through the windows...and THAT is why the Occlusion effect was NIOT rendering...as soon as I eliminated the transparent plane everything came back to normal...so THNXX!!! :)