Search Unity

How to add global fog to a transparent sprite?

Discussion in 'Shaders' started by sarahnorthway, Jul 12, 2018.

  1. sarahnorthway

    sarahnorthway

    Joined:
    Jul 16, 2015
    Posts:
    78
    I have custom vert + surf shader for waving plant sprites displayed with a SpriteRenderer, and I'd like to add fog to it. If I remove #pragma nofog, the result affects the alpha of transparent areas, making visible boxes around sprites within the fog.



    I traced this to Unity's UNITY_FOG_LERP_COLOR, called at the end of the Unity generated frag shader (frag_surf):

    Code (CSharp):
    1. #define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.rgb = lerp((fogCol).rgb, (col).rgb, saturate(fogFac))
    If I change it to:

    Code (CSharp):
    1. col.r = 1;
    Now it only sets the red channel to 1. It shouldn't affect other colors, or the alpha, right? But the result still adds semi-visible red boxes around my sprites (pictured above). Does Unity somehow embed alpha information into the R channel? How do I change RGB in the frag shader without affecting alpha?

    I don't want to use clip. Multiplying col.rgb by col.a after applying the fog looks close to correct, but adds a faint dark outline. Same exact effect if I change #pragma keepalpha to #pragma alpha:blend. I feel like I'm missing something important about sprites and alpha.

    My shader:

    Code (CSharp):
    1. Shader "Northway/SpritesDiffuseWave" {
    2.      Properties {
    3.          [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    4.      }
    5.  
    6.      SubShader {
    7.          Tags {
    8.              "Queue"="Geometry"
    9.              "IgnoreProjector"="True"
    10.              "RenderType"="Transparent"
    11.              "PreviewType"="Plane"
    12.              "CanUseSpriteAtlas"="True"
    13.          }
    14.  
    15.          Cull Off
    16.          Lighting Off
    17.          ZWrite Off
    18.          Blend One OneMinusSrcAlpha
    19.  
    20.          CGPROGRAM
    21.          #pragma surface surf SimpleLambert vertex:vert nolightmap nodynlightmap keepalpha noinstancing //nofog
    22.        
    23.          #include "UnitySprites.cginc"
    24.  
    25.          #undef UNITY_FOG_LERP_COLOR
    26.          #define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.r = 1;
    27.        
    28.          struct Input {
    29.              float2 uv_MainTex;
    30.              fixed4 color;
    31.          };
    32.        
    33.          half4 LightingSimpleLambert(SurfaceOutput s, half3 lightDir, half atten) {
    34.              half4 c;
    35.              c.rgb = s.Albedo * _LightColor0.rgb * atten * 0.60;
    36.              c.a = s.Alpha;
    37.              return c;
    38.          }
    39.          void vert (inout appdata_full v, out Input o) {
    40.              UNITY_INITIALIZE_OUTPUT(Input, o);
    41.  
    42.              //... vertex shader code
    43.          }
    44.  
    45.          void surf (Input IN, inout SurfaceOutput o) {
    46.              fixed4 color = tex2D(_MainTex, IN.uv_MainTex) * IN.color;
    47.              o.Albedo = color.rgb * color.a;
    48.              o.Alpha = color.a;
    49.          }
    50.  
    51.          ENDCG
    52.      }
    53.  
    54.      Fallback "Transparent/VertexLit"
    55. }
    Apologies that this is a repost from Unity Answers. I usually end up answering my own questions there.
     
  2. sarahnorthway

    sarahnorthway

    Joined:
    Jul 16, 2015
    Posts:
    78
    I eventually solved this by multiplying fogCol.rgb by col.a, which seems a little obvious in retrospect. I guess by this time the alpha is baked into col.rgb:

    #define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.rgb = lerp(fogCol.rgb * col.a, col.rgb, saturate(fogFac))