Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to make an infinite grid that becomes transparent as its getting away from the camera?

Discussion in 'Shaders' started by ardakoyuncu, Nov 20, 2017.

  1. ardakoyuncu

    ardakoyuncu

    Joined:
    Apr 12, 2017
    Posts:
    6
    Hey guys,

    I am pretty new to shader writing. I found this chunk of code of a shader for an infinite grid here on the forums. I am trying modify it so it becomes invisible as it gets away from the camera. I just could not figure it out and appreciate some help.

    How would I modify this to make that happen in this shader?

    Code (CSharp):
    1. Shader "Unlit/Grid"
    2. {
    3.     Properties
    4.     {
    5.         _GridColour ("Grid Colour", color) = (1, 1, 1, 1)
    6.         _BaseColour ("Base Colour", color) = (1, 1, 1, 0)
    7.         _GridSpacing ("Grid Spacing", float) = 1
    8.         _LineThickness ("Line Thickness", float) = .1
    9.  
    10.  
    11.     }
    12.     SubShader
    13.     {
    14.         Tags { "RenderType"="Transparent" "Queue"="Transparent"}
    15.         LOD 100
    16.  
    17.         Blend SrcAlpha OneMinusSrcAlpha
    18.         ZWrite Off
    19.  
    20.         Pass
    21.         {
    22.             CGPROGRAM
    23.             #pragma vertex vert
    24.             #pragma fragment frag
    25.  
    26.             #include "UnityCG.cginc"
    27.  
    28.  
    29.             struct appdata
    30.             {
    31.                 float4 vertex : POSITION;
    32.             };
    33.  
    34.             struct v2f
    35.             {
    36.                 float2 uv : TEXCOORD0;
    37.                 float4 vertex : SV_POSITION;
    38.             };
    39.  
    40.             fixed4 _GridColour;
    41.             fixed4 _BaseColour;
    42.             float _GridSpacing;
    43.             float _LineThickness;
    44.  
    45.             v2f vert (appdata v)
    46.             {
    47.                 v2f o;
    48.                 o.vertex = UnityObjectToClipPos(v.vertex);
    49.                 o.uv = mul(unity_ObjectToWorld, v.vertex).xz / _GridSpacing;
    50.  
    51.                 return o;
    52.             }
    53.  
    54.             fixed4 frag (v2f i) : SV_Target
    55.             {            
    56.                 float2 wrapped = frac(i.uv) - 0.5f;
    57.                 float2 range = abs(wrapped);
    58.  
    59.                 float2 speeds;
    60.                 /* // Euclidean norm gives slightly more even thickness on diagonals
    61.                 float4 deltas = float4(ddx(i.uv), ddy(i.uv));
    62.                 speeds = sqrt(float2(
    63.                             dot(deltas.xz, deltas.xz),
    64.                             dot(deltas.yw, deltas.yw)
    65.                          ));
    66.                 */  // Cheaper Manhattan norm in fwidth slightly exaggerates thickness of diagonals
    67.                 speeds = fwidth(i.uv);
    68.  
    69.                 float2 pixelRange = range/speeds;
    70.                 float lineWeight = saturate(min(pixelRange.x, pixelRange.y) - _LineThickness);
    71.  
    72.                 return lerp(_GridColour, _BaseColour, lineWeight);
    73.             }
    74.             ENDCG
    75.         }
    76.     }
    77. }
    Thanks a lot in advance!
     
  2. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    823
    Unity exposes the camera position in world space as a built in variable. Take a look at the docs:
    https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html

    The one you are interested in is _WorldSpaceCameraPos
    In the vertex shader you already get the world positon of the vertex with mul(unity_ObjectToWorld, v.vertex).
    Stroe that one in a own variable to calculate the distance between the two. Then you can pass that value to the fragment shader by extending your v3f struct. Add something like
    float distanceToCamera : TEXCOORD1;

    Then you can use that value to control the alpha in the fragment return.
     
  3. ardakoyuncu

    ardakoyuncu

    Joined:
    Apr 12, 2017
    Posts:
    6
    @Johannski thanks for your reply!

    I've been looking into implementing that idea somehow into the code and I found some suggestions online. I tried to combine those with what I had and put together this shader below. I end up having the color and param parameters at the end of my fragment shader. I do not know how to combine those to output a transparent pixel so the grid dissapears. Anything I do just changes the color of it. I also added TDistance to it so I can read a distance value to adjust the falloff but could not integrate that either. What am I doing wrong in the code?

    Code (CSharp):
    1. Shader "Unlit/Grid"
    2. {
    3.     Properties
    4.     {
    5.         _GridColour ("Grid Colour", color) = (1, 1, 1, 1)
    6.         _BaseColour ("Base Colour", color) = (1, 1, 1, 0)
    7.         _GridSpacing ("Grid Spacing", float) = 1
    8.         _LineThickness ("Line Thickness", float) = .1
    9.         _TDistance ("Transparency Distance", float) = 1
    10.  
    11.     }
    12.     SubShader
    13.     {
    14.         Tags { "RenderType"="Transparent" "Queue"="Transparent"}
    15.         LOD 100
    16.  
    17.         Blend SrcAlpha OneMinusSrcAlpha
    18.         ZWrite Off
    19.  
    20.         Pass
    21.         {
    22.             CGPROGRAM
    23.             #pragma vertex vert
    24.             #pragma fragment frag
    25.  
    26.             #include "UnityCG.cginc"
    27.  
    28.  
    29.             struct appdata
    30.             {
    31.                 float4 vertex : POSITION;
    32.             };
    33.  
    34.             struct v2f
    35.             {
    36.                 fixed4 color : COLOR0;
    37.                 float2 uv : TEXCOORD0;
    38.                 float4 vertex : SV_POSITION;
    39.             };
    40.  
    41.      
    42.             fixed4 _GridColour;
    43.             fixed4 _BaseColour;
    44.             float _GridSpacing;
    45.             float _LineThickness;
    46.             float _TDistance;
    47.  
    48.             sampler2D   _MainTex;
    49.             half        _MinVisDistance;
    50.             half        _MaxVisDistance;
    51.      
    52.  
    53.             v2f vert (appdata_full v)
    54.             {
    55.                 v2f o;
    56.                 o.vertex = UnityObjectToClipPos(v.vertex);
    57.                 o.uv = mul(unity_ObjectToWorld, v.vertex).xz / _GridSpacing;
    58.                 o.color = v.color;
    59.  
    60.                 //distance falloff
    61.                 half3 viewDirW = _WorldSpaceCameraPos - mul((half4x4)_Object2World, v.vertex);
    62.                 half viewDist = length(viewDirW);
    63.                 half falloff = saturate((viewDist - _MinVisDistance) / (_MaxVisDistance - _MinVisDistance) );
    64.                 o.color.a *= (1.0f - falloff);
    65.  
    66.                 return o;
    67.             }
    68.  
    69.          
    70.             fixed4 frag (v2f i) : SV_Target
    71.             {            
    72.                 float2 wrapped = frac(i.uv) - 0.5f;
    73.                 float2 range = abs(wrapped);
    74.  
    75.                 float2 speeds;
    76.                 speeds = fwidth(i.uv);
    77.  
    78.                 float2 pixelRange = range/speeds;
    79.                 float lineWeight = saturate(min(pixelRange.x, pixelRange.y) - _LineThickness);
    80.  
    81.                 fixed4 color = tex2D(_MainTex, i.uv) * i.color;
    82.                 half4 param = lerp(_GridColour, _BaseColour, lineWeight);
    83.  
    84.                 return param;
    85.             }
    86.             ENDCG
    87.  
    88.         }
    89.     }
    90. }
    91.  
     
  4. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    823
    There were quite a few errors in there. It would have been a bit too tedious to point them out, I fixed the shader for you:
    upload_2017-11-21_19-8-33.png

    Code (CSharp):
    1. Shader "Unlit/Grid"
    2. {
    3.     Properties
    4.     {
    5.         _GridColour ("Grid Colour", color) = (1, 1, 1, 1)
    6.         _BaseColour ("Base Colour", color) = (1, 1, 1, 0)
    7.         _GridSpacing ("Grid Spacing", float) = 1
    8.         _LineThickness ("Line Thickness", float) = .1
    9.         _ODistance ("Start Transparency Distance", float) = 5
    10.         _TDistance ("Full Transparency Distance", float) = 10
    11.     }
    12.     SubShader
    13.     {
    14.         Tags { "RenderType"="Transparent" "Queue"="Transparent"}
    15.         LOD 100
    16.         Blend SrcAlpha OneMinusSrcAlpha
    17.         ZWrite Off
    18.         Pass
    19.         {
    20.             CGPROGRAM
    21.             #pragma vertex vert
    22.             #pragma fragment frag
    23.             #include "UnityCG.cginc"
    24.             struct appdata
    25.             {
    26.                 float4 vertex : POSITION;
    27.             };
    28.             struct v2f
    29.             {
    30.                 float4 vertex : SV_POSITION;
    31.                 float2 uv : TEXCOORD0;
    32.                 float3 worldPos : TEXCOORD1;
    33.             };
    34.  
    35.             fixed4 _GridColour;
    36.             fixed4 _BaseColour;
    37.             float _GridSpacing;
    38.             float _LineThickness;
    39.             float _ODistance;
    40.             float _TDistance;
    41.  
    42.             v2f vert (appdata_full v)
    43.             {
    44.                 v2f o;
    45.                 o.vertex = UnityObjectToClipPos(v.vertex);
    46.                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    47.                 o.uv = o.worldPos.xz / _GridSpacing;
    48.                 return o;
    49.             }
    50.      
    51.             fixed4 frag (v2f i) : SV_Target
    52.             {        
    53.                 float2 wrapped = frac(i.uv) - 0.5f;
    54.                 float2 range = abs(wrapped);
    55.                 float2 speeds;
    56.                 speeds = fwidth(i.uv);
    57.                 float2 pixelRange = range/speeds;
    58.                 float lineWeight = saturate(min(pixelRange.x, pixelRange.y) - _LineThickness);
    59.                 half4 param = lerp(_GridColour, _BaseColour, lineWeight);
    60.              
    61.                 //distance falloff
    62.                 half3 viewDirW = _WorldSpaceCameraPos - i.worldPos;
    63.                 half viewDist = length(viewDirW);
    64.                 half falloff = saturate((viewDist - _ODistance) / (_TDistance - _ODistance) );
    65.                 param.a *= (1.0f - falloff);
    66.                 return param;
    67.             }
    68.             ENDCG
    69.         }
    70.     }
    71. }
    Please take a good look in order to understand the functionality. If you have any questions feel free to ask :)

    You can use this shader with a CC0 License.
     
    Last edited: Oct 5, 2020
    TakuanDaikon likes this.
  5. ardakoyuncu

    ardakoyuncu

    Joined:
    Apr 12, 2017
    Posts:
    6
    I really appreciate it. I guess I was trying to construct the whole thing in a nonsensical way. It makes a lot of sense now, thank you for your help!
     
  6. Johannski

    Johannski

    Joined:
    Jan 25, 2014
    Posts:
    823
    You're welcome. Just as a side note: I did do the distance calculation in the fragment part and not in the vertex shader as suggested before. This is the exact method to do, but will also need more performance (actually really not that much).
    With the calculation happening in the vertex shader you will get quite wrong results when the mesh has few vertices. Here is an example:
    upload_2017-11-22_9-9-39.png

    As for point p you see that the fragment shader would calculate the value 0.4, while the shader with distance calculation in the vertex shader would interpolate between the distance results and would get a value of 0.624. To be more extreme, the point the is directly at the camera would obviously have a distance of zero, but from interpolating the results of the fragment shader you would get a value above 0.5, so a completely wrong result.
     
    TakuanDaikon likes this.
  7. ROBYER1

    ROBYER1

    Joined:
    Oct 9, 2015
    Posts:
    1,450
    This is a very nice shader, however it doesn't render in VR using Single Pass/Multiview

    New version for VR Single Pass/Multiview Instanced!


    Code (CSharp):
    1. Shader "Unlit/Grid"
    2. {
    3.     Properties
    4.     {
    5.         _GridColour ("Grid Colour", color) = (1, 1, 1, 1)
    6.         _BaseColour ("Base Colour", color) = (1, 1, 1, 0)
    7.         _GridSpacing ("Grid Spacing", float) = 1
    8.         _LineThickness ("Line Thickness", float) = .1
    9.         _ODistance ("Start Transparency Distance", float) = 5
    10.         _TDistance ("Full Transparency Distance", float) = 10
    11.     }
    12.     SubShader
    13.     {
    14.         Tags { "RenderType"="Transparent" "Queue"="Transparent"}
    15.         LOD 100
    16.         Blend SrcAlpha OneMinusSrcAlpha
    17.         ZWrite Off
    18.         Pass
    19.         {
    20.             CGPROGRAM
    21.             #pragma vertex vert
    22.             #pragma fragment frag
    23.             #include "UnityCG.cginc"
    24.             struct appdata
    25.             {
    26.                 float4 vertex : POSITION;
    27.                 UNITY_VERTEX_INPUT_INSTANCE_ID //Insert
    28.             };
    29.             struct v2f
    30.             {
    31.                 float4 vertex : SV_POSITION;
    32.                 float2 uv : TEXCOORD0;
    33.                 float3 worldPos : TEXCOORD1;
    34.                 UNITY_VERTEX_OUTPUT_STEREO //Insert
    35.             };
    36.  
    37.             fixed4 _GridColour;
    38.             fixed4 _BaseColour;
    39.             float _GridSpacing;
    40.             float _LineThickness;
    41.             float _ODistance;
    42.             float _TDistance;
    43.  
    44.             v2f vert (appdata_full v)
    45.             {
    46.                 v2f o;
    47.  
    48.                     UNITY_SETUP_INSTANCE_ID(v); //Insert
    49.                     UNITY_INITIALIZE_OUTPUT(v2f, o); //Insert
    50.                     UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert
    51.  
    52.                 o.vertex = UnityObjectToClipPos(v.vertex);
    53.                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    54.                 o.uv = o.worldPos.xz / _GridSpacing;
    55.                 return o;
    56.             }
    57.      
    58.             fixed4 frag (v2f i) : SV_Target
    59.             {        
    60.                 float2 wrapped = frac(i.uv) - 0.5f;
    61.                 float2 range = abs(wrapped);
    62.                 float2 speeds;
    63.                 speeds = fwidth(i.uv);
    64.                 float2 pixelRange = range/speeds;
    65.                 float lineWeight = saturate(min(pixelRange.x, pixelRange.y) - _LineThickness);
    66.                 half4 param = lerp(_GridColour, _BaseColour, lineWeight);
    67.            
    68.                 //distance falloff
    69.                 half3 viewDirW = _WorldSpaceCameraPos - i.worldPos;
    70.                 half viewDist = length(viewDirW);
    71.                 half falloff = saturate((viewDist - _ODistance) / (_TDistance - _ODistance) );
    72.                 param.a *= (1.0f - falloff);
    73.                 return param;
    74.             }
    75.             ENDCG
    76.         }
    77.     }
    78. }
     
  8. XynanXDB

    XynanXDB

    Joined:
    Jan 17, 2017
    Posts:
    9
    Im sorry for bumping an old thread but I found this shader particularly useful as I wanted to create a grid shader. The only difference is I need subdivisions. How do I implement it, I'm very new to shader.
     
    ROBYER1 likes this.