Search Unity

Simple vertex color based fog shader (glsl)

Discussion in 'Shaders' started by melong, Sep 17, 2012.

  1. melong

    melong

    Joined:
    Sep 2, 2011
    Posts:
    22
    Hi everyone,

    I tried to recreate a simple "fog effect" by filling the vertex color red channel with white proportionnally to the distance of the vertex from the camera and use it as a mask to mix the regular texture with my fog color. For my particular case i assume that i will only need to calculate this distance on the z axis, this saves me the use of a length() function as i fear this to be a bit heavy (am i right?)

    This works perfectly on desktop, but gives me flat pink color on mobile.

    Code (csharp):
    1.  
    2. Shader "MyShaders/FogVertexColor_GLSL"
    3. {
    4.     Properties
    5.     {
    6.         _MainTex ("Base (RGB)", 2D) = "white" {}
    7.         _fogColor ("Fog Color", Color) = (0,0,0,0)
    8.         _fogStart ("Linear Fog Start", float) = 0.0
    9.         _fogEnd ("Linear Fog End", float) = 50.0
    10.     }
    11.     SubShader
    12.     {
    13.         Tags { "RenderType"="Opaque" }
    14.        
    15.         Pass
    16.         {
    17.             GLSLPROGRAM
    18.  
    19.                 uniform vec3 _WorldSpaceCameraPos;
    20.  
    21.                 varying mediump vec2 uv;
    22.                 uniform mediump sampler2D _MainTex;
    23.                 uniform mediump vec4 _fogColor;
    24.                 uniform mediump float _fogStart;
    25.                 uniform mediump float _fogEnd;
    26.                 varying mediump vec4 vertexColor;
    27.                 varying mediump vec4 worldSpaceCoord;
    28.  
    29.                 #ifdef VERTEX
    30.                 void main()
    31.                 {
    32.                     gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    33.                     uv = gl_MultiTexCoord0.xy;
    34.                     worldSpaceCoord = gl_ModelViewMatrix * gl_Vertex;
    35.                     float distToCamera = abs(worldSpaceCoord.z - _WorldSpaceCameraPos.z - _fogStart);
    36.                     float ratio = distToCamera / _fogEnd;
    37.                     vertexColor = gl_Color;
    38.                     vertexColor.r = min(ratio, 1);
    39.                 }
    40.                 #endif
    41.  
    42.                 #ifdef FRAGMENT
    43.                 void main()
    44.                 {
    45.                     vec4 tex = tex2D (_MainTex, uv );
    46.  
    47.                     gl_FragColor = vec4(mix(tex.rgb, _fogColor.rgb, vertexColor.r), 1.0);
    48.                 }
    49.                 #endif
    50.  
    51.             ENDGLSL
    52.         }
    53.     }
    54. }
    55.  
    After i a few test i figured that this particular line was responsible of my problem:
    Code (csharp):
    1.  
    2. vertexColor.r = min(ratio, 1);
    3.  
    I tried to replace it by this and got the same result:
    Code (csharp):
    1.  
    2. if ( ratio <= 1 )
    3. {
    4.     vertexColor.r = ratio;
    5. }
    6. else
    7. {
    8.     vertexColor.r = 1;
    9. }
    10.  
    So i don't have any clue about why this would cause any problem on mobile and not on desktop but maybe i am missing something obvious so if you have any idea please, your help would be welcome.
    Thanks !
     
  2. Martin-Kraus

    Martin-Kraus

    Joined:
    Feb 18, 2011
    Posts:
    617
    Did you try to write "1.0" instead of "1"? Some GLSL compilers are a bit pedantic when it comes to automatic integer to float castings.

    Also, gl_ModelViewMatrix transforms to view coordinates; thus, "worldSpaceCoord" is a misnomer.
    In view coordinates, the camera is usually at the origin, thus, you shouldn't subtract the camera world position. In OpenGL you are usually looking down the negative z axis, but I don't remember whether that's true in Unity; thus, you might keep the abs function.

    worldSpaceCoord = gl_ModelViewMatrix * gl_Vertex;
    float distToCamera = max(0.0, abs(worldSpaceCoord.z) - _fogStart);

    Also, using just the z coordinate will make the distance depend on the position where it appears on your screen which you probably don't want. The additional length function should be no issue in a vertex shader.

    float distToCamera = max(0.0, length(gl_ModelViewMatrix * gl_Vertex) - _fogStart);
     
    Last edited: Sep 17, 2012
  3. melong

    melong

    Joined:
    Sep 2, 2011
    Posts:
    22
    That worked, thanks !

    I knew i was missing something obvious :)

    Actually i use this to make a highway fade away in the background in a rather rainy atmosphere. This road is following along the Z axis so that's why i thought this would be enough but if length() is ok i might go for the most flexible solution.

    Thanks for the help and suggestions!
     
  4. Peter99

    Peter99

    Joined:
    Jan 18, 2013
    Posts:
    9
    This shader could works... but I'm trying to add support to lightmap without success...

    Code (csharp):
    1.  
    2. Shader "Custom/ShaderFog" {
    3.  
    4.     Properties {
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.         _FogColor ("Fog Color (RGB)", Color) = (0.5, 0.5, 0.5, 1.0)
    7.         _FogStart ("Fog Start", Float) = 0.0
    8.         _FogEnd ("Fog End", Float) = 10.0
    9.  
    10.     }
    11.  
    12.     SubShader {
    13.  
    14.         Tags { "RenderType"="Opaque" }
    15.         Fog { Mode off }    
    16.  
    17.  
    18.         Pass {
    19.  
    20.             CGPROGRAM
    21.             #pragma vertex vert
    22.             #pragma fragment frag
    23.  
    24.  
    25.             sampler2D _MainTex;
    26.             float4 _FogColor;
    27.             float _FogStart;
    28.             float _FogEnd;
    29.  
    30.             struct appdata {
    31.  
    32.                 float4 vertex : POSITION;
    33.                 float4 texcoord : TEXCOORD0;
    34.  
    35.             };
    36.  
    37.             struct v2f {
    38.  
    39.                 float4 pos : SV_POSITION;
    40.                 float4 uv : TEXCOORD0;
    41.                 float fog : TEXCOORD1;
    42.  
    43.             };
    44.  
    45.  
    46.             v2f vert(appdata v) {
    47.  
    48.                 v2f o;
    49.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    50.                 o.uv = v.texcoord;
    51.                 float fogz = mul(UNITY_MATRIX_MV, v.vertex).z;
    52.                 o.fog = saturate((fogz + _FogStart) / (_FogStart - _FogEnd));
    53.  
    54.                 return o;
    55.  
    56.             }
    57.  
    58.             half4 frag(v2f i) : COLOR {
    59.  
    60.                 return lerp(tex2D(_MainTex, i.uv.xy), _FogColor, i.fog);
    61.  
    62.             }
    63.  
    64.             ENDCG
    65.  
    66.         }
    67.  
    68.     }
    69.  
    70. }
    71.  
     
    BMadrid likes this.
  5. Peter99

    Peter99

    Joined:
    Jan 18, 2013
    Posts:
    9
    anyway. I haven't tested your shader. Does it supports lightmap? I'm having big headaches trying to implement it =/
     
  6. mikaelgustafsson

    mikaelgustafsson

    Joined:
    Mar 6, 2014
    Posts:
    15
    Is this technique better for mobile than the built in fog system? I'm looking for a mobile friendly fog system but It's crazy hard to find.