Search Unity

Alpha Blending and Surface Shader Lighting Models

Discussion in 'Shaders' started by teammetablast, Jan 18, 2011.

  1. teammetablast

    teammetablast

    Joined:
    Nov 22, 2010
    Posts:
    13
    Hi, I have a surface shader that uses a custom lighting model, but it seems like the alpha calculation from the lighting model function is not used at all, but the color calculation is being used:

    Code (csharp):
    1. Shader "Test/AlphaSpecTest" {
    2.     Properties {
    3.         _Color ("Main Color", Color) = (1,1,1,1)
    4.         _MainTex ("Color Map (RGB)", 2D) = "white" {}
    5.         _SpecTex ("Specular Color Map (RGB) Gloss (A)", 2D) = "gray" {}
    6.         _Shininess ("Shininess (Spec. Exponent)", Range (75, 5)) = 32
    7.     }
    8.    
    9.     SubShader {
    10.         Tags{  
    11.             "RenderType" = "Tranparent"
    12.             "Queue" = "Transparent"
    13.             }
    14.            
    15.         CGPROGRAM
    16.  
    17.         //using custom lighting functions
    18.         #pragma surface surf BlinnPhongColor alpha
    19.         #include "UnityCG.cginc"
    20.  
    21.         //custom surface output structure
    22.         struct SurfaceOutputSpecColor {
    23.             half3 Albedo;
    24.             half3 Normal;
    25.             half3 Emission;
    26.             half Specular;
    27.             half3 GlossColor;
    28.             half Alpha;
    29.         };
    30.  
    31.         sampler2D _MainTex;
    32.         sampler2D _SpecTex;
    33.  
    34.         float4 _Color;
    35.         float _Shininess;
    36.  
    37.      
    38.         //forward lighting function
    39.         inline half4 LightingBlinnPhongColor (SurfaceOutputSpecColor s, half3 lightDir, half3 viewDir, half atten) {
    40.           half3 h = normalize (lightDir + viewDir);
    41.  
    42.           half diff = max (0, dot (s.Normal, lightDir));
    43.  
    44.           float nh = max (0, dot (s.Normal, h));
    45.           float spec = pow (nh, _Shininess);
    46.           half3 specCol = spec * s.GlossColor;
    47.  
    48.           half4 c;
    49.           c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * specCol * s.Specular) * (atten * 2);
    50.           c.a = s.Alpha * dot(s.Normal.xyz,viewDir);
    51.           return c;
    52.         }
    53.  
    54.         struct Input {
    55.             float2 uv_MainTex;
    56.             float2 uv_SpecTex;
    57.         };
    58.          
    59.         void surf (Input IN, inout SurfaceOutputSpecColor o) {
    60.               o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    61.               half4 spec = tex2D (_SpecTex, IN.uv_SpecTex);
    62.               o.GlossColor = spec.rgb;
    63.               o.Specular = spec.a;
    64.               o.Alpha = 1.0;
    65.         }
    66.         ENDCG
    67.     }
    68.     Fallback "Diffuse"
    69. }

    What am I doing wrong? It seems like no matter what the alpha value is set to in the lighting model function, the alpha value from the surf() function is the one that is always used. The color, however, does come from the lighting model function. Why?
     
  2. Kuba

    Kuba

    Moderator

    Joined:
    Jan 13, 2009
    Posts:
    416
    As usual when dealing with Surface Shaders, the easiest is to look at the debug output (just add #pragma debug to your shader and hit "Open compiled shader").

    So basically the alpha keyword that you added to the surface shader definition does a couple of things:

    Alphatest Greater 0
    ZWrite Off
    ColorMask RGB // <-- see, no alpha will be spit out to the framebuffer
    [...]
    Blend SrcAlpha OneMinusSrcAlpha
    [...]
    c.a = o.Alpha; // <-- added at the very end of your fragment program. o.Alpha comes from the surface function, overrides the color returned by the lighting function


    What you can easily do is take that shader with debug output, keep only the usual stuff (passes with CGPROGRAMS, etc.) and strip the rest. Make sure it compiles at this point. Now you can remove the following lines to get what you wanted:
    ColorMask RGB
    c.a = o.Alpha;


    But the question is - what do you actually want to achieve? :)
     
  3. akotranza

    akotranza

    Joined:
    Sep 7, 2011
    Posts:
    36
    I'm having a similar problem (not using any special pragmas). Anything I set in surf, e.g. o.Emission, o.Albedo, ends up being modulated with the output of my custom lighting function.

    I just want the output of the lighting function to be the final fragment color, before blending. How can this be accomplished?