Search Unity

Self-illumination + alpha overlapping issue

Discussion in 'Shaders' started by PedroGV, Feb 23, 2015.

  1. PedroGV

    PedroGV

    Joined:
    Nov 1, 2010
    Posts:
    415
    I'm trying to implement a shader for Unity 4.6.+ that properly renders self-illuminated objects with transparencies.

    After a lot of searching the web I finally got to a code which I tweaked a bit:

    Code (CSharp):
    1. Shader "Custom/Alpha Self-Illuminated"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Main Color", Color) = (1,1,1,1)
    6.             _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    7.         _Illum ("Illumination (A)", 2D) = "white" {}
    8.             _EmissionLM ("Emission (Lightmapper)", Float) = 0
    9.         _Exposure("Exposure", Float) = 2
    10.     }
    11.    
    12.     SubShader
    13.     {
    14.         Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
    15.        
    16.         LOD 200
    17.  
    18.         Blend SrcAlpha OneMinusSrcAlpha
    19.  
    20.         // Pass that writes to depth buffer only to avoid visual glitches with transparency.
    21.         Pass
    22.         {
    23.             ZWrite On
    24.             ColorMask 0
    25.         }
    26.  
    27.         // Pass (it throws an error if included in a pass)
    28.         // {
    29.             ZWrite Off
    30.  
    31.             CGPROGRAM
    32.  
    33.             #pragma surface surf Lambert
    34.  
    35.             sampler2D _MainTex;
    36.             sampler2D _Illum;
    37.             fixed4 _Color;
    38.             float _EmissionLM;
    39.             float _Exposure;
    40.                        
    41.             struct Input
    42.             {
    43.                 float2 uv_MainTex;
    44.                 float2 uv_Illum;
    45.             };
    46.  
    47.             void surf (Input IN, inout SurfaceOutput o)
    48.             {
    49.                 fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    50.                 o.Albedo = c.rgb;
    51.                 o.Emission = c.rgb * tex2D(_Illum, IN.uv_Illum).a * _Exposure;
    52.                 o.Alpha = c.a;
    53.             }
    54.            
    55.             ENDCG
    56.         //}
    57.     }
    58.  
    59.     Fallback "Transparent/VertexLit"
    60. }
    It works as expected with the exception of situations where two objects using a material with this shader overlap. The problem is that the object closer to the camera will remove any pixels from the object behind/beneath it, as if a stencil operation were performed on it where they overlap.

    In other words, say you have three game objects: ObjectA (diffuse), ObjectB (this shader), ObjectC(also this shader), and you place the objects centered on screen in that order towards the camera. The expected result is that pixels from the three objects should be visible. However, ObjectA and ObjectC are always visible, but only the pixels of ObjectB that do not overlap with pixels of ObjectC are.

    Any ideas how to fix this?
     
  2. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    That makes perfect sense with the ZWrite first pass and is exactly what this shader should do. Proper order independent transparency is not easy, so there is no easy fix.

    If the number of objects with this shader is limited and you know which is in front of which, you could copy this shader a few times to make it different shaders. Then adjust the Queue to Transparent, Transparent-1, etc. and manually render them back to front. (The back object with Queue=Transparent-1 and the front with Queue=Transparent.)
     
  3. PedroGV

    PedroGV

    Joined:
    Nov 1, 2010
    Posts:
    415
    That's the thing, objects are dynamic so they change position at runtime. Is there any way in Unity v4.6, other than creating different shaders, to specify "order the objects with this same shader/material back to front"?

    EDIT: btw @jvo3dc, thanks for answering :)
     
  4. PedroGV

    PedroGV

    Joined:
    Nov 1, 2010
    Posts:
    415
    It would be nice to be able to set the queue at runtime without having to create a new shader to set a different Queue value.
     
  5. PedroGV

    PedroGV

    Joined:
    Nov 1, 2010
    Posts:
    415
  6. PedroGV

    PedroGV

    Joined:
    Nov 1, 2010
    Posts:
    415
    Ok, downloaded Unity5 and the shader stop working as a transparent one. Also it seems that the standard shader does override manual/script changes in the Queue order (maybe it's got assigned by defualt a higher number?).
     
  7. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Actually, transparent objects are automatically rendered back to front as far as I know. The thing is that that is based only on the pivots of the objects and it doesn't guarantee a per pixel back to front rendering order.

    On the transparency not working, I've posted a response here that also applies for the shader above:
    http://forum.unity3d.com/threads/my-custom-shader-does-not-work-in-unity-5.307076/#post-2000918
    (In short, Blend states should be specified inside the Pass block.)
     
  8. PedroGV

    PedroGV

    Joined:
    Nov 1, 2010
    Posts:
    415
    Thanks for the answer and the link. I will specify Blend States in the pass block from now on.

    Regarding the queue order being ignored on the material this is what I have found in the docs: http://docs.unity3d.com/Manual/UpgradeGuide5-Shaders.html

    Sorting by material index has been removed
    Unity no longer sorts by material index in the forward renderloop. This improves performance because more objects can be rendered without state changes between them. This breaks compatibility for content that relies on material index as a way of sorting. In 4.x a mesh with two materials would always render the first material first, and the second material second. In Unity 5 this is not the case, the order depends on what reduces the most state changes to render the scene.
    My question is: does this mean, that sorting is still applicable for the deferred renderloop?
     
  9. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    I always assumed it didn't sort by material index actually. For the same reason they stopped doing it now.

    For sorting you should use the shader queue. For opaque geometry the strategy is front to back and big to small. For transparent geometry it's back to front. (Which is already done based on pivots as far as I know.)
     
  10. PedroGV

    PedroGV

    Joined:
    Nov 1, 2010
    Posts:
    415
    > I always assumed it didn't sort by material index actually. For the same reason they stopped doing it now.

    Actually, it did. I got it working for v4.6. I will try to find a solution using the shader queue instead. Thanks for the info.
     
  11. PedroGV

    PedroGV

    Joined:
    Nov 1, 2010
    Posts:
    415
    Now, the problem that I have is that, for whatever weird reason, I cannot include the CGProgram in a second pass so I cannot set the blendstate.