Search Unity

Overdraw of opaque and transparent geometry

Discussion in 'Shaders' started by Ippokratis, Apr 1, 2017.

  1. Ippokratis

    Ippokratis

    Joined:
    Oct 13, 2008
    Posts:
    1,521
    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.

    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:

    Unity_2017-04-01_17-50-15.png

    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.
     
    Last edited: Apr 1, 2017
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    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.
     
  3. Ippokratis

    Ippokratis

    Joined:
    Oct 13, 2008
    Posts:
    1,521
    Thanks @bgolus, that makes sense.
     
  4. Ippokratis

    Ippokratis

    Joined:
    Oct 13, 2008
    Posts:
    1,521
    I have submitted a bug report (Case 897281).
    I found this http://answers.unity3d.com/questions/34614/where-can-i-get-the-overdraw-shader-used-in-the-au.html where @Kuba mentions that the Overdraw shader looks like this
    Code (CSharp):
    1.  
    2. Shader "Overdraw" {
    3. Properties {
    4.     _MainTex ("Base", 2D) = "white" {}
    5. }
    6.  
    7. SubShader
    8. {
    9.  Fog { Mode Off }
    10.  ZWrite Off
    11.  ZTest Always
    12.  Blend One One // additive blending
    13.  
    14.  Pass
    15.  {
    16.    SetTexture[_MainTex]
    17.    {
    18.       constantColor(0.1, 0.04, 0.02, 0)
    19.       combine constant, texture
    20.    }
    21.  }
    22. }
    23. }
    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.

    Code (CSharp):
    1. Shader "Overdraw"
    2. {
    3.     Properties
    4.     {
    5.     }
    6.     SubShader
    7.     {
    8.         Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
    9.         LOD 100
    10.         Fog { Mode Off }
    11.         ZWrite On
    12.         ZTest LEqual
    13.         Blend One One
    14.  
    15.         Pass
    16.         {
    17.             CGPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.          
    21.             #include "UnityCG.cginc"
    22.  
    23.             struct appdata
    24.             {
    25.                 float4 vertex : POSITION;
    26.             };
    27.  
    28.             struct v2f
    29.             {
    30.                 float4 vertex : SV_POSITION;
    31.             };
    32.  
    33.             v2f vert (appdata v)
    34.             {
    35.                 v2f o;
    36.                 o.vertex = UnityObjectToClipPos(v.vertex);
    37.                 return o;
    38.             }
    39.          
    40.             fixed4 frag (v2f i) : SV_Target
    41.             {
    42.                 return fixed4(0.1, 0.04, 0.02, 0);
    43.             }
    44.             ENDCG
    45.         }
    46.     }
    47. }
    Kind regards.
     
    Last edited: Apr 3, 2017
    Unity-Nikos likes this.
  5. simonschreibt

    simonschreibt

    Joined:
    Apr 13, 2017
    Posts:
    6
    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”)."
    https://docs.unity3d.com/Manual/OcclusionCulling.html

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

    2. This short Intel Video mentions exactly the same behavior and presents a way (Front to Back Sorting) as optimiziation:



    3. 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.

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

    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.

    I'm very confused about the differences of my testing-resuls, the Intel-Video and the Unity-Documentation. :(
     
  6. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Have you guys tried the built in renderdoc or frame debugger? these can help debug order of drawing and other issues.
     
  7. simonschreibt

    simonschreibt

    Joined:
    Apr 13, 2017
    Posts:
    6
    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:

     
  8. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    (Vid seems private or unavailable)
     
  9. simonschreibt

    simonschreibt

    Joined:
    Apr 13, 2017
    Posts:
    6

    thanks, should be working now.
     
  10. simonschreibt

    simonschreibt

    Joined:
    Apr 13, 2017
    Posts:
    6
  11. Balikk

    Balikk

    Joined:
    Oct 23, 2014
    Posts:
    49
    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.
     
  12. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    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.