Overdraw of opaque and transparent geometry

Hi,
I try to understand how to optimize a game opaque geometry rendering using render queues.
I have created a simple example, with one fixed camera displaying a plane and a cube.
I am using v5.6f3, Standalone build.

3015552--225050--Unity_2017-04-01_16-20-42.png

Each object has a different material, using the standard shader.
I was thinking that if the render queue of the cube is lower than the render queue of the plane, the pixels that belong to the plane and are hidden behind the cube, will not be drawn.

Using the scene overdraw mode I got these results:

What I understand from this image is that the pixel region of the plane behind the cube gets rendered twice.
In the Frame debugger, I confirmed that the object rendering queue reflects the order in which the objects get drawn, but the overdraw mode showed no difference to the image above.
I have repeated the test with every transparent and opaque variant of the standard shader, still no difference. I inverted the rendering queue order, still no difference.

  1. Is it possible to reduce overdraw using render queues in the material settings? If yes, what are the exact steps to take in a similar simple setup?

  2. If the steps I took above are indeed the correct ones, as confirmed by the frame debugger, why the overdaw mode remains as such? Or, how should I interpret the findings in the overdaw mode ?

  3. While in the Editor mode, I tried to set the material render queue from the inspector and I found it resets every time I choose another gameobject in the inspector. This behavior is unexpected. The workaround I used was to set the Inspector in Debug mode to set the Render queue, where the modifications made remained, both in the Editor mode while choosing other gameObjects and in the Play mode, yet, it is not an expected behavior.

I hope someone can point to the right direction,
Kind regards.

Unity’s overdraw mode just renders all objects using a transparent shader, so the effects of ZTest on the fragment overshading isn’t taken into account.

Thanks @bgolus , that makes sense.

I have submitted a bug report (Case 897281).
I found this where can I get the overdraw shader used in the authoring scene - Questions & Answers - Unity Discussions where @Kuba mentions that the Overdraw shader looks like this

Shader "Overdraw" {
Properties {
    _MainTex ("Base", 2D) = "white" {}
}

SubShader
{
 Fog { Mode Off }
 ZWrite Off
 ZTest Always
 Blend One One // additive blending

 Pass
 {
   SetTexture[_MainTex]
   {
      constantColor(0.1, 0.04, 0.02, 0)
      combine constant, texture
   }
 }
}
}

If the above code is similar to the Overdraw shader as stated, the problem lies in using “ZTest Always”.
One should use ZTest LEqual instead.
E.g.

Shader "Overdraw"
{
    Properties
    {
    }
    SubShader
    {
        Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
        LOD 100
        Fog { Mode Off }
        ZWrite On
        ZTest LEqual
        Blend One One

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
          
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
          
            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(0.1, 0.04, 0.02, 0);
            }
            ENDCG
        }
    }
}

Kind regards.

1 Like

Hi, I’m having problems understanding the overdraw mode and sorting as well.

  1. The documentation about occlusion culling tells the user, that:

“in 3D computer graphics since most of the time objects farthest away from the camera are drawn first and closer objects are drawn over the top of them (this is called “overdraw”).”

This almost sounds like Unity would render opaque objects Back to Front which would be unusual.

  1. This short Intel Video mentions exactly the same behavior and presents a way (Front to Back Sorting) as optimiziation:
  1. BUT when I look at a simple scene with two opaque boxes behind each other, I see that the front box is rendered first and the box behind rendered after. That’s Front to Back sorting and that was actually what I expected.

  2. When I write a shader which disables zWrite/Read, I can see as well, that the box fruther away is rendered last.

  3. If objects are drawn Front to Back there shouldn’t be a problem with overdraw EXCEPT Unity defines the overdraw as “The vertex shader + rasterizer had to run for those areas, so we show them as overdraw”. The mode does NOT to necessarily show the Overdraw in regard of Pixel Shading.

I’m very confused about the differences of my testing-resuls, the Intel-Video and the Unity-Documentation. :frowning:

Have you guys tried the built in renderdoc or frame debugger? these can help debug order of drawing and other issues.

Yes, I checked with the frame debugger. And here it gets even weirder.

Depending on the view distance the render order seems to change. Here’s a video showing the weird behavior + shader code:

https://www.youtube.com/watch?v=lgGc5P7H7ps

(Vid seems private or unavailable)

thanks, should be working now.

It seems very random. Does anyone has a good explanation or link to a documentation about this behavior? I couldn’t find anything.

Here’s an GIF: x.com

Hi,

In this doc where they talk about overdraw they specify a bit about how they sort items " Unity sorts items front-to-back in the Geometry queue to minimize overdraw, but sorts objects back-to-front in the Transparent queue to achieve the required visual effect. "

“5. If objects are drawn Front to Back there shouldn’t be a problem with overdraw EXCEPT Unity defines the overdraw as “The vertex shader + rasterizer had to run for those areas, so we show them as overdraw”. The mode does NOT to necessarily show the Overdraw in regard of Pixel Shading.”
With a look here it appears your point 5 is correct since they render the vertex part, they cull and test the depth and, after that, they render the fragment part of the shader .

Your gif look like sorting issue problem, like semi-transparents objects can do. Since you don’t test the depth and they have the same render queue, unity doesn’t know which one to render first and will do it in a random way. If you change the render queue of one of your object, since you don’t test the depth, the one with the biggest renderqueue will render over the other one.
I had your issue with your shader and now I have that after I played a bit in the scene view with other objects.

Welcome @simonschreibt !

As far as I know Romain’s comment in that twitter conversation is mostly correct. Unity mainly sorts opaques front to back based on the closest bounding sphere.

However a few versions ago (5.5?) they made a change to sort by shader pass to reduce state changes. Since that change the sort order is far less predictable, even between different shaders. It’s been brought up a few times on the forums as it appears broken. My best guess is they’re just doing some additional per-material / per-shader pass fudge to try to get the same materials to draw successively rather than actually having the sort look at the shaders. How they determine the fudge amount is likely non-deterministic, hence the seemingly random sorting.