Search Unity

Alpha Test with Alpha Blend?

Discussion in 'Shaders' started by Justafin, Mar 28, 2013.

  1. Justafin

    Justafin

    Joined:
    Aug 6, 2012
    Posts:
    30
    Is it possible to have two passes in a Surface Shader, one to alpha test and then one to alpha blend and soften edges?

    Thanks
    Justin
     
  2. Jaimi

    Jaimi

    Joined:
    Jan 10, 2009
    Posts:
    6,208
  3. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    No.

     
  4. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    It is possible. It's how I do my character's hair.

    Here's a stripped down version using Lambert.

    The first surface shader does the "solid" interior bit, the second does the soft edge exterior.

    Code (csharp):
    1.  
    2. Shader "Custom/Surface Shader Soft Edge" {
    3.     Properties {
    4.         _Color ("Main Color", Color) = (1,1,1,1)
    5.         _MainTex ("Diffuse (RGB) Alpha (A)", 2D) = "gray" {}
    6.         _Cutoff ("Alpha Cut-Off Threshold", Range(0,1)) = 0.5
    7.     }
    8.  
    9.     SubShader {
    10.         Tags { "RenderType" = "TransparentCutout" }
    11.  
    12.         CGPROGRAM
    13.             #pragma surface surf Lambert
    14.  
    15.             struct Input
    16.             {
    17.                 float2 uv_MainTex;
    18.             };
    19.            
    20.             sampler2D _MainTex;
    21.             float _Cutoff;
    22.                
    23.             void surf (Input IN, inout SurfaceOutput o)
    24.             {
    25.                 float4 albedo = tex2D(_MainTex, IN.uv_MainTex);
    26.                 clip(albedo.a - _Cutoff);
    27.                
    28.                 o.Albedo = albedo.rgb;
    29.                 o.Alpha = albedo.a;
    30.             }
    31.         ENDCG
    32.  
    33.         ZWrite Off
    34.  
    35.         CGPROGRAM
    36.             #pragma surface surf Lambert
    37.  
    38.             struct Input
    39.             {
    40.                 float2 uv_MainTex;
    41.             };
    42.            
    43.             sampler2D _MainTex;
    44.             float _Cutoff;
    45.                
    46.             void surf (Input IN, inout SurfaceOutput o)
    47.             {
    48.                 float4 albedo = tex2D(_MainTex, IN.uv_MainTex);
    49.                 clip(-(albedo.a - _Cutoff));
    50.                
    51.                 o.Albedo = albedo.rgb;
    52.                 o.Alpha = albedo.a;
    53.             }
    54.         ENDCG
    55.     }
    56.     FallBack "Transparent/Cutout/VertexLit"
    57. }
    58.  
     
    Last edited: Mar 28, 2013
  5. Jaimi

    Jaimi

    Joined:
    Jan 10, 2009
    Posts:
    6,208
    Ah, sorry - missed the "surface shader" somehow. Still, really simple to do as farfarer shows (though I wouldn't clip the second pass)
     
  6. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    You clip the second pass so you don't draw the same pixels again - they've already been drawn in the first pass. Clip as early as possible in the shader.
     
  7. Jaimi

    Jaimi

    Joined:
    Jan 10, 2009
    Posts:
    6,208
    Ah - really cool! I missed the negative at the beginning. I haven't done that before, but make perfect sense!
     
  8. Justafin

    Justafin

    Joined:
    Aug 6, 2012
    Posts:
    30
    Thanks for all the great replies. They were very helpful. I actually had my shader set up very much like Farfarer suggested and I'm still not quite achieving the results I was hoping for.

    $test.jpg

    On the left is what I see in the Editor which is exactly what I want. On the right is in-game. Its somewhat hard to see but it is still alpha testing for the most part without showing any of the 2nd pass alpha blend.

    Here is the code, maybe I'm just missing something simple:

    Code (csharp):
    1. Shader "Soft-Edge Testing" {
    2.     Properties {
    3.         _Color ("DOES NOTHING", Color) = (1,1,1,1)
    4.         _Highlight ("Highlight Color", Color) = (.5,.5,.5,1)
    5.         _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    6.         _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
    7.     }
    8.     SubShader {
    9.         Tags { "Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }    
    10.                
    11.         CGPROGRAM
    12.         #pragma only_renderers d3d9
    13.         #pragma surface surf Lambert noambient nolightmap nodirlightmap novertexlights noforwardadd
    14.        
    15.         struct Input {
    16.             float2 uv_MainTex;
    17.             float4 color : COLOR; // vertexcolor
    18.         };     
    19.                                
    20.         fixed4 _Highlight;
    21.         sampler2D _MainTex;
    22.         half _Cutoff;
    23.         fixed4 _Color;
    24.        
    25.         void surf (Input IN, inout SurfaceOutput o) {
    26.             _Color = (0.5,0.5,0.5,1);
    27.             fixed4 colorMap = tex2D (_MainTex, IN.uv_MainTex);
    28.             o.Albedo = colorMap.rgb * IN.color.a * _Highlight;
    29.             o.Emission = colorMap.rgb * IN.color.a * IN.color.rgb + (_Highlight - 0.5);
    30.             clip(colorMap.a - _Cutoff);
    31.             o.Alpha = 0.0;
    32.         }
    33.         ENDCG
    34.        
    35.         ZWrite Off
    36.         Blend SrcAlpha OneMinusSrcAlpha
    37.    
    38.         Tags { "IgnoreProjector"="True" }
    39.        
    40.         CGPROGRAM
    41.         #pragma surface surf Lambert noambient nolightmap nodirlightmap novertexlights noforwardadd alpha
    42.        
    43.         struct Input {
    44.             float2 uv_MainTex;
    45.             float4 color : COLOR; // vertexcolor
    46.         };     
    47.                                
    48.         fixed4 _Highlight;
    49.         sampler2D _MainTex;
    50.         half _Cutoff;
    51.         fixed4 _Color;
    52.    
    53.         void surf (Input IN, inout SurfaceOutput o) {
    54.             _Color = (0.5,0.5,0.5,1);
    55.             fixed4 colorMap = tex2D (_MainTex, IN.uv_MainTex);
    56.             o.Albedo = colorMap.rgb * IN.color.a * _Highlight;
    57.             o.Emission = colorMap.rgb * IN.color.a * IN.color.rgb + (_Highlight - 0.5);
    58.             clip(-(colorMap.a - _Cutoff));
    59.             o.Alpha = colorMap.a;
    60.             }
    61.         ENDCG
    62.     }
    63.     Fallback "Transparent/Cutout/Diffuse"
    64. }
    Any suggestions? Thanks again.
     
  9. BIG-BUG

    BIG-BUG

    Joined:
    Mar 29, 2009
    Posts:
    457
    The blended fragments do not write into the ZBuffer so they get overwritten by the skybox which is rendered after solid geometry.
    The chosen queue fits only for the AlphaTest part of your shader, the AlphaBlend part should go into queue "Transparent". You could try to assign the shader to a queue like "Transparent-100". The standard TreeCreatorLeaves shader uses "Transparent-99" while also writing Z...
     
  10. Justafin

    Justafin

    Joined:
    Aug 6, 2012
    Posts:
    30
    Tried messing with all sorts of variations on the queue....still same problem. Guess it may not be possible.
     
  11. BIG-BUG

    BIG-BUG

    Joined:
    Mar 29, 2009
    Posts:
    457
    Strange. I gave it a try and setting the RenderQueue to "Transparent-100" did indeed work for me.
    Are there other specialities in your setup like shadows, deferred rendering, etc? Do you use the standard Skybox component?