Search Unity

SRP transparent sorting bug

Discussion in 'Shaders' started by dreamerflyer, Jul 16, 2018.

  1. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Because this has no affect on transparency sorting. Only the CPU specified render order matters, and the Offset property only modifies the rendered depth, not the render order, and the depth only affects its interaction with objects that render to the depth buffer which transparency traditionally does not.

    Transparency sorting in that demo, as well as the LW and HD pipelines, are the same as Unity's built in forward and deferred renderers and have the same limitations.
     
  3. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    emm,any method to fixed this?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You could manually sort the objects via script using renderOrder, which will work for simple planes like this a texture least. For more complex geometry you’d have to resort to per poly sorting, or some form of Order Independent Transparency. I know you tend to be focused on mobile projects, and I can tell you now that no form of OIT is going to be mobile friendly.
     
  5. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    hair card.jpg
    OIT ,i think it should do it with source engine code.Since unity 2018 changing the render system,why not do this and renderOrder within engine?And it will cost less than Manusally setting .This transparent sorting is very very long time bug,from it began.... if want to do uncharted hair, so many hair card to manual setting....horrible..... And ,if use two pass ,one for depth ,one for alpha ,it will waste the draw call,so ,if engine can do one pass sorting correct will be good.
     
    Last edited: Jul 18, 2018
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    No.

    True OIT is far too expensive to do by default, not supported by most hardware, and often requires unbounded memory usage for the framebuffer. A 1920x1080 framebuffer with true OIT support via an A-Buffer might use the usual 64 MB (if no transparent objects overlap), or it could use a few gigabytes! A-Buffers work decently well on AMD gpus, and have for the last decade, but it's still several times slower to render than generic rasterization. Like potentially 100x times slower.

    OIT approximations are all either very rough approximations that are only useful in specific situations, or still very expensive. The two most common ones are depth peeling and weighted blended OIT.

    Depth peeling works by rendering the objects in the scene multiple times in chunks, either with depth buckets or presorted back and front mesh chunks. This can solve some issues but can also have a significant impact on the render performance, and doesn't solve most cases of intersection between transparent objects.


    Weighted blended OIT does a good job with rendering multiple objects with low transparency, or when the effect is homogenous and blurry where the sorting order can be kind of ambiguous. The main idea behind it is to pick a blended color value for overlapping surfaces that is consistent and ambiguous as to the order rather than trying to actually solve sorting. For example if you have a red and a green surface that are both 50% transparent, if the red is on top then it should be a greenish red color, and flipped it should be a reddish green color, but with weighted blended OIT it's just a dull yellow, regardless of the order. This makes the technique useful for doing things like smoke rendering or semi-transparent CAD, but kind of terrible for more general cases.


    Intel also has a new technique for approximate OIT. It's sort of a middle ground to A-Buffers and depth peeling that can sort some limited number of layers (like depth peeling) per pixel while they're rendering in a single pass, but still has the unbounded memory problem of A-Buffers. So it's the best and worst of both techniques.

    Lastly there's raytracing / raycasting. That seems like it's coming soonish if you see all of the "Real Time GPU Raytracing" announcements lately. The irony is that all of the recent GPU Raytracing demos out there ... they all use old school rasterization for the initial main scene rendering, only the shadows, lighting and reflections are using raytracing, so the rest of the scene still has the same old transparency sorting problems. It's also at the point of "look, this is possible now in real time and look decent at 30 fps in these test scenes" and not "this is fast enough to use in a real game" as it's still way, way slower than traditional techniques. And this is using $3000+ professional GPUs, no consumer GPU supports this yet. We're a long way off still from this being practical.

    So, the short version:
    Not a bug, this is how transparency is done in all real time game engines because anything else is too slow to be useful.
     
    dnnkeeper likes this.
  7. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    OH,Man~Thank your so detail tech ! according my picture show,many quads without intersect should have tool to auto setting the transparent quad's render order,this can work i think ,not take in count with OIT.
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Arbitrary quad or tri sorting is relatively expensive, and most of the time not required. Unity’s perspective depth sorting is purely* based on distance to per mesh bounds centers, and orthographic depth sorting is purely based on bounds center depth (distance along the view axis). For the most common cases of depth sorting, these work well. Especially orthographic when used for camera facing particles and sprites it is perfectly accurate as interecting geometry isn’t possible. You can force the camera to use perspective or orthographic, or a custom axis. If your quads are roughly all facing in the same direction that might be a good option. Alternatively you can manually sort them using their renderer’s sortingOrder.

    * I say “purely”, but I’m only talking about the actual depth sorting part of Unity’s draw order sorting. It does additional sorting based on material instance, material queue, batching, instancing, etc. that mean the final sorted order is not purely center distance based.

    Btw, that image you posted of Nathan Drake’s hair ... that’s not OIT, that’s just manual pre sorted geometry. Pretty common for hair geometry for the last 10 years. Unreal used to have an import option to reorder geometry based on distance to pivot, but these days they just assume you’ve done that already.
     
    dreamerflyer likes this.
  9. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    OK,Got it~Thanks very much, should make my self sorting tool.
     
  10. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    hair2.jpg hair.jpg
    hi, found AMD 2004 document,it will use 4 pass to get the correct sorting ...
     
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    This is for the specific case of rendering pre-sorted hair geometry with areas of full opacity.

    This won't help at all for your simple case of two transparent quads.
     
  12. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    emm,if render hair,how about ue4 using tempAA and dither than upward 4 pass? dither alpha.png
     
  13. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Stochastic or dithered alpha works pretty well for certain situations. Its quite popular with deferred rendering as it integrates nicely with that technique and means "transparent" objects get all of the benefits of the deferred pipeline. TAA helps a ton with hiding dithered alpha, as can FXAA and similar post AA techniques, though it's been used in many games with out it, or with other techniques.

    Super Mario Odyssey uses it for fading out objects near the screen, and some other effects with out any AA techniques at all.
    https://threadreaderapp.com/thread/924061000919285761.html

    Grand Theft Auto V uses it for distant foliage and some other transparent objects with a custom blurring technique using the gbuffer's alpha value to store the intended apparent opacity.
    http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/

    It can also be used with normal forward rendering, and combined with MSAA using Alpha to Coverage to in some cases remove the need for a post AA or blur.


    However there's one situation that dithered alpha does really, really bad at:
    Two overlapping quads with the same alpha value. Worse case one quad renders (the closest one), best case they both render, but it's not entirely clear what order they're in.
     
    dreamerflyer likes this.
  14. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    emm,UE used pixel depth offset to controll the overlap sorting also.But i think UE hair effect is still no good enough.... hair.jpg
     
  15. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    Code (CSharp):
    1.  
    2. Shader "Custom/AMD Hair" {
    3.  
    4.  
    5.         Properties{
    6.  
    7.  
    8.                 _Color("Color", Color) = (1,1,1,1)
    9.  
    10.         _MainTex("Albedo (RGB)", 2D) = "white" {}
    11.  
    12.  
    13.             _Glossiness("Smoothness", Range(0,1)) = 0.5
    14.  
    15.  
    16.                 _Metallic("Metallic", Range(0,1)) = 0.0
    17.  
    18.  
    19.          }
    20.  
    21.  
    22.             SubShader{
    23.  
    24.         Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjectors" = "True" }
    25.  
    26.             //    Blend SrcAlpha OneMinusSrcAlpha
    27.                 ZWrite on
    28.                 Ztest less
    29.                 cull front
    30.             CGPROGRAM
    31.  
    32.  
    33.            // Physically based Standard lighting model, and enable shadows on all light types
    34.  
    35.  
    36.             #pragma surface surf Standard fullforwardshadows
    37.  
    38.  
    39.  
    40.  
    41.            // Use shader model 3.0 target, to get nicer looking lighting
    42.  
    43.  
    44.             #pragma target 3.0
    45.  
    46.  
    47.    
    48.  
    49.  
    50.           sampler2D _MainTex;
    51.  
    52.  
    53.    
    54.  
    55.        struct Input {
    56.  
    57.  
    58.                float2 uv_MainTex;
    59.  
    60.  
    61.     };
    62.  
    63.  
    64.             half _Glossiness;
    65.  
    66.  
    67.         half _Metallic;
    68.  
    69.  
    70.             fixed4 _Color;
    71.  
    72.  
    73.    
    74.  
    75.  
    76.             void surf(Input IN, inout SurfaceOutputStandard o) {
    77.  
    78.  
    79.                 // Albedo comes from a texture tinted by color
    80.  
    81.  
    82.                    fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    83.  
    84.             o.Albedo = c.rgb;
    85.  
    86.                        o.Metallic = _Metallic;
    87.  
    88.  
    89.               o.Smoothness = _Glossiness;
    90.  
    91.  
    92.                   o.Alpha = c.a;
    93.                   clip(-0.1 + c.a);
    94.  
    95.     }
    96.  
    97.  
    98.             ENDCG
    99.  
    100.                 Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
    101.                 Blend SrcAlpha OneMinusSrcAlpha
    102.                 ZWrite off
    103.                 ZTest less
    104.                 Cull front
    105.                 CGPROGRAM
    106.  
    107.  
    108.                 // Physically based Standard lighting model, and enable shadows on all light types
    109.  
    110.  
    111. #pragma surface surf Standard fullforwardshadows alpha:fade  
    112.  
    113.  
    114.  
    115.  
    116.                 // Use shader model 3.0 target, to get nicer looking lighting
    117.  
    118.  
    119. #pragma target 3.0
    120.  
    121.  
    122.  
    123.  
    124.  
    125.                 sampler2D _MainTex;
    126.  
    127.  
    128.  
    129.  
    130.             struct Input {
    131.  
    132.  
    133.                 float2 uv_MainTex;
    134.  
    135.  
    136.             };
    137.  
    138.  
    139.             half _Glossiness;
    140.  
    141.  
    142.             half _Metallic;
    143.  
    144.  
    145.             fixed4 _Color;
    146.  
    147.  
    148.  
    149.  
    150.  
    151.             void surf(Input IN, inout SurfaceOutputStandard o) {
    152.  
    153.  
    154.                 // Albedo comes from a texture tinted by color
    155.  
    156.  
    157.                 fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    158.  
    159.                 o.Albedo = c.rgb;
    160.  
    161.                 o.Metallic = _Metallic;
    162.  
    163.  
    164.                 o.Smoothness = _Glossiness;
    165.  
    166.  
    167.                 o.Alpha = c.a;
    168.  
    169.  
    170.             }
    171.  
    172.  
    173.             ENDCG
    174.  
    175.                 Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" "LightMode"="forwardbase"}
    176.                 Blend SrcAlpha OneMinusSrcAlpha
    177.                 ZWrite on
    178.                 ZTest less
    179.                 Cull back
    180.                 CGPROGRAM
    181.  
    182.  
    183.                 // Physically based Standard lighting model, and enable shadows on all light types
    184.  
    185.  
    186. #pragma surface surf Standard fullforwardshadows alpha:fade  
    187.  
    188.  
    189.  
    190.  
    191.                 // Use shader model 3.0 target, to get nicer looking lighting
    192.  
    193.  
    194. #pragma target 3.0
    195.  
    196.  
    197.  
    198.  
    199.  
    200.                 sampler2D _MainTex;
    201.  
    202.  
    203.  
    204.  
    205.             struct Input {
    206.  
    207.  
    208.                 float2 uv_MainTex;
    209.  
    210.  
    211.             };
    212.  
    213.  
    214.             half _Glossiness;
    215.  
    216.  
    217.             half _Metallic;
    218.  
    219.  
    220.             fixed4 _Color;
    221.  
    222.  
    223.  
    224.  
    225.  
    226.             void surf(Input IN, inout SurfaceOutputStandard o)
    227.             {
    228.                 // Albedo comes from a texture tinted by color
    229.  
    230.  
    231.                 fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    232.  
    233.                 o.Albedo = c.rgb;
    234.  
    235.                 o.Metallic = _Metallic;
    236.  
    237.  
    238.                 o.Smoothness = _Glossiness;
    239.  
    240.  
    241.                 o.Alpha = c.a;
    242.  
    243.  
    244.             }
    245.  
    246.  
    247.             ENDCG
    248.  
    249.          }
    250.  
    251.  
    252.             FallBack "Diffuse"
    253.  
    254.  
    255.     }
    256.  
    surface transparent look like glass?? and still soring seems not correct... surface alpha.png