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

wireframe grid shader

Discussion in 'Shaders' started by stefano.cecere, Sep 11, 2010.

  1. stefano.cecere

    stefano.cecere

    Joined:
    Jun 24, 2010
    Posts:
    28
    hi
    sorry for the maybe simple question but i searched everywhere and i could not find this:

    is it possibile to program a shader so that it creates infinite squared wireframe grid like in the picture?

    i wouldn't like to use a texture, but a vectorial shape..
    so i was thinking about a shader

    or would it better to use "draw lines" method?

    thank you for any answear!

    stefano
     

    Attached Files:

  2. Broken-Toy

    Broken-Toy

    Joined:
    Jan 16, 2010
    Posts:
    455
  3. stefano.cecere

    stefano.cecere

    Joined:
    Jun 24, 2010
    Posts:
    28
  4. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    Yes, I know this thread is old, but at the time of writing it comes up as the top hit for a Google search of "Unity Grid Shader" and it still hasn't received a satisfactory answer. So, for the benefit of anyone coming to this page now, here's a purely shader-based grid renderer.

    For more information on using world coordinates in shader code, see the excellent wikibook http://en.wikibooks.org/wiki/Cg_Programming/Unity/Shading_in_World_Space:
    Code (csharp):
    1.  
    2. Shader "Grid" {
    3.      
    4.     Properties {
    5.       _GridThickness ("Grid Thickness", Float) = 0.01
    6.       _GridSpacing ("Grid Spacing", Float) = 10.0
    7.       _GridColour ("Grid Colour", Color) = (0.5, 1.0, 1.0, 1.0)
    8.       _BaseColour ("Base Colour", Color) = (0.0, 0.0, 0.0, 0.0)
    9.     }
    10.      
    11.     SubShader {
    12.       Tags { "Queue" = "Transparent" }
    13.      
    14.       Pass {
    15.         ZWrite Off
    16.         Blend SrcAlpha OneMinusSrcAlpha
    17.      
    18.         CGPROGRAM
    19.      
    20.         // Define the vertex and fragment shader functions
    21.         #pragma vertex vert
    22.         #pragma fragment frag
    23.      
    24.         // Access Shaderlab properties
    25.         uniform float _GridThickness;
    26.         uniform float _GridSpacing;
    27.         uniform float4 _GridColour;
    28.         uniform float4 _BaseColour;
    29.      
    30.         // Input into the vertex shader
    31.         struct vertexInput {
    32.             float4 vertex : POSITION;
    33.         };
    34.  
    35.         // Output from vertex shader into fragment shader
    36.         struct vertexOutput {
    37.           float4 pos : SV_POSITION;
    38.           float4 worldPos : TEXCOORD0;
    39.         };
    40.      
    41.         // VERTEX SHADER
    42.         vertexOutput vert(vertexInput input) {
    43.           vertexOutput output;
    44.           output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
    45.           // Calculate the world position coordinates to pass to the fragment shader
    46.           output.worldPos = mul(_Object2World, input.vertex);
    47.           return output;
    48.         }
    49.  
    50.         // FRAGMENT SHADER
    51.         float4 frag(vertexOutput input) : COLOR {
    52.           if (frac(input.worldPos.x/_GridSpacing) < _GridThickness || frac(input.worldPos.y/_GridSpacing) < _GridThickness) {
    53.             return _GridColour;
    54.           }
    55.           else {
    56.             return _BaseColour;
    57.           }
    58.         }
    59.     ENDCG
    60.     }
    61.   }
    62. }
     
    matej172 likes this.
  5. RGravity

    RGravity

    Joined:
    Jul 4, 2012
    Posts:
    30
    Nice dude, thanks!
    Btw just to add that if you want to draw the grid on the 'floor' use the z coordinate of input.World instead of y
     
  6. mikelaurence

    mikelaurence

    Joined:
    Oct 1, 2013
    Posts:
    11
    Lovely shader @tanoshimi, thanks!

    If anyone needs a little more tweakability, I just added X Y spacing as well as an offset:

    Code (csharp):
    1.  
    2. Shader "Grid" {
    3.  
    4.  
    5.  
    6.     Properties {
    7.  
    8.       _GridThickness ("Grid Thickness", Float) = 0.01
    9.  
    10.       _GridSpacingX ("Grid Spacing X", Float) = 1.0
    11.  
    12.       _GridSpacingY ("Grid Spacing Y", Float) = 1.0
    13.  
    14.       _GridOffsetX ("Grid Offset X", Float) = 0
    15.  
    16.       _GridOffsetY ("Grid Offset Y", Float) = 0
    17.  
    18.       _GridColour ("Grid Colour", Color) = (0.5, 1.0, 1.0, 1.0)
    19.  
    20.       _BaseColour ("Base Colour", Color) = (0.0, 0.0, 0.0, 0.0)
    21.  
    22.     }
    23.  
    24.  
    25.  
    26.     SubShader {
    27.  
    28.       Tags { "Queue" = "Transparent" }
    29.  
    30.  
    31.  
    32.       Pass {
    33.  
    34.         ZWrite Off
    35.  
    36.         Blend SrcAlpha OneMinusSrcAlpha
    37.  
    38.  
    39.  
    40.         CGPROGRAM
    41.  
    42.  
    43.  
    44.         // Define the vertex and fragment shader functions
    45.  
    46.         #pragma vertex vert
    47.  
    48.         #pragma fragment frag
    49.  
    50.  
    51.  
    52.         // Access Shaderlab properties
    53.  
    54.         uniform float _GridThickness;
    55.  
    56.         uniform float _GridSpacingX;
    57.  
    58.         uniform float _GridSpacingY;
    59.  
    60.         uniform float _GridOffsetX;
    61.  
    62.         uniform float _GridOffsetY;
    63.  
    64.         uniform float4 _GridColour;
    65.  
    66.         uniform float4 _BaseColour;
    67.  
    68.  
    69.  
    70.         // Input into the vertex shader
    71.  
    72.         struct vertexInput {
    73.  
    74.             float4 vertex : POSITION;
    75.  
    76.         };
    77.  
    78.  
    79.  
    80.         // Output from vertex shader into fragment shader
    81.  
    82.         struct vertexOutput {
    83.  
    84.           float4 pos : SV_POSITION;
    85.  
    86.           float4 worldPos : TEXCOORD0;
    87.  
    88.         };
    89.  
    90.  
    91.  
    92.         // VERTEX SHADER
    93.  
    94.         vertexOutput vert(vertexInput input) {
    95.  
    96.           vertexOutput output;
    97.  
    98.           output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
    99.  
    100.           // Calculate the world position coordinates to pass to the fragment shader
    101.  
    102.           output.worldPos = mul(_Object2World, input.vertex);
    103.  
    104.           return output;
    105.  
    106.         }
    107.  
    108.  
    109.  
    110.         // FRAGMENT SHADER
    111.  
    112.         float4 frag(vertexOutput input) : COLOR {
    113.  
    114.           if (frac((input.worldPos.x + _GridOffsetX)/_GridSpacingX) < (_GridThickness / _GridSpacingX) ||
    115.               frac((input.worldPos.y + _GridOffsetY)/_GridSpacingY) < (_GridThickness / _GridSpacingY)) {
    116.  
    117.             return _GridColour;
    118.  
    119.           }
    120.  
    121.           else {
    122.  
    123.             return _BaseColour;
    124.  
    125.           }
    126.  
    127.         }
    128.  
    129.     ENDCG
    130.  
    131.     }
    132.  
    133.   }
    134.  
    135. }
    136.  
     
    dataviz_science likes this.
  7. aalmada

    aalmada

    Joined:
    Apr 29, 2013
    Posts:
    21
    Thanks for sharing the shader code.
    I'm trying to use it but it results in a lot of aliasing. How can I reduce it?
    Thanks
     
  8. Alekxss

    Alekxss

    Joined:
    Mar 25, 2013
    Posts:
    170
    Modified from here
    http://www.gamedev.net/topic/529926-terrain-contour-lines-using-pixel-shader/

    Don't know how it works realy. Just cg port.
    smooth_grid.jpg

    Unity5 surface shader:

    Code (CSharp):
    1. Shader "Custom/XZGrid"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic ("Metallic", Range(0,1)) = 0.0
    9.         _GridStep ("Grid size", Float) = 10
    10.         _GridWidth ("Grid width", Float) = 1
    11.     }
    12.     SubShader
    13.     {
    14.         Tags { "RenderType"="Opaque" }
    15.         LOD 200
    16.        
    17.         CGPROGRAM
    18.         // Physically based Standard lighting model, and enable shadows on all light types
    19.         #pragma surface surf Standard fullforwardshadows
    20.  
    21.         // Use shader model 3.0 target, to get nicer looking lighting
    22.         #pragma target 3.0
    23.  
    24.         sampler2D _MainTex;
    25.  
    26.         struct Input
    27.         {
    28.             float2 uv_MainTex;
    29.             float3 worldPos;
    30.         };
    31.  
    32.         half _Glossiness;
    33.         half _Metallic;
    34.         fixed4 _Color;
    35.         float _GridStep;
    36.         float _GridWidth;
    37.        
    38.         void surf (Input IN, inout SurfaceOutputStandard o) {
    39.             // Albedo comes from a texture tinted by color
    40.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    41.            
    42.             // grid overlay
    43.             float2 pos = IN.worldPos.xz / _GridStep;
    44.             float2 f  = abs(frac(pos)-.5);
    45.             float2 df = fwidth(pos) * _GridWidth;
    46.             float2 g = smoothstep(-df ,df , f);
    47.             float grid = 1.0 - saturate(g.x * g.y);
    48.             c.rgb = lerp(c.rgb, float3(1,1,1), grid);
    49.            
    50.             o.Albedo = c.rgb;
    51.             // Metallic and smoothness come from slider variables
    52.             o.Metallic = _Metallic;
    53.             o.Smoothness = _Glossiness;
    54.             o.Alpha = c.a;
    55.         }
    56.         ENDCG
    57.     }
    58.     FallBack "Diffuse"
    59. }
    60.  
     
    Deng-Jia, Sarkahn and Beguiled like this.
  9. bertling

    bertling

    Joined:
    Sep 24, 2012
    Posts:
    1
    I changed tanoshimi's code to give better support for anti-aliasing, which I noticed when I tried to resize player window.

    Shader "Grid" {

    Properties {
    _GridThickness ("Grid Thickness", Float) = 0.01
    _GridSpacing ("Grid Spacing", Float) = 10.0
    _GridColour ("Grid Colour", Color) = (1.0, 1.0, 1.0, 1.0)
    _BaseColour ("Base Colour", Color) = (1.0, 0.0, 0.0, 0.0)
    }

    SubShader {
    Tags { "Queue" = "Transparent" }

    Pass {
    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha

    CGPROGRAM

    // Define the vertex and fragment shader functions
    #pragma vertex vert
    #pragma fragment frag

    // Access Shaderlab properties
    uniform float _GridThickness;
    uniform float _GridSpacing;
    uniform float4 _GridColour;
    uniform float4 _BaseColour;

    // Input into the vertex shader
    struct vertexInput {
    float4 vertex : POSITION;
    };

    // Output from vertex shader into fragment shader
    struct vertexOutput {
    float4 pos : SV_POSITION;
    float4 worldPos : TEXCOORD0;
    };

    // VERTEX SHADER
    vertexOutput vert(vertexInput input) {
    vertexOutput output;
    output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
    // Calculate the world position coordinates to pass to the fragment shader
    output.worldPos = mul(_Object2World, input.vertex);
    return output;
    }

    // FRAGMENT SHADER
    float4 frag(vertexOutput input) : COLOR {
    float xfrac = frac(input.worldPos.x / _GridThickness) - 0.5;
    float yfrac = frac(input.worldPos.y / _GridThickness) - 0.5;
    float dist = xfrac * xfrac + yfrac * yfrac;
    float strength = max(0.5 - dist, 0) * 2;
    strength = pow(strength, 5);

    bool xvalid = false;
    bool yvalid = false;

    if (input.worldPos.x > 0)
    {
    if (fmod(input.worldPos.x, _GridSpacing) < _GridThickness)
    xvalid = true;
    }
    else
    {
    if (fmod(input.worldPos.x, _GridSpacing) < _GridThickness - _GridSpacing)
    xvalid = true;
    }

    if (input.worldPos.y > 0)
    {
    if (fmod(input.worldPos.y, _GridSpacing) < _GridThickness)
    yvalid = true;
    }
    else
    {
    if (fmod(input.worldPos.y, _GridSpacing) < _GridThickness - _GridSpacing)
    yvalid = true;
    }

    if (xvalid && yvalid)
    return _GridColour * strength + _BaseColour * (1.0 - strength);
    else
    return _BaseColour;
    }
    ENDCG
    }
    }
    }
     
  10. Beguiled

    Beguiled

    Joined:
    Mar 15, 2014
    Posts:
    14
  11. Zer0_Ph34r

    Zer0_Ph34r

    Joined:
    Aug 15, 2017
    Posts:
    1
    Great code, works perfectly, but I adjusted it slightly so that you get a real grid pattern with cross hatching, since you code only produced lines in one direction. I'm putting it up in case some people need it and don't know how to adjust Shader code.

    Code (csharp):
    1.  
    2. Shader "Grid" {
    3.      
    4.     Properties {
    5.       _GridThickness ("Grid Thickness", Float) = 0.01
    6.       _GridSpacing ("Grid Spacing", Float) = 10.0
    7.       _GridColour ("Grid Colour", Color) = (0.5, 0.5, 0.5, 0.5)
    8.       _BaseColour ("Base Colour", Color) = (0.0, 0.0, 0.0, 0.0)
    9.     }
    10.      
    11.     SubShader {
    12.       Tags { "Queue" = "Transparent" }
    13.      
    14.       Pass {
    15.         ZWrite Off
    16.         Blend SrcAlpha OneMinusSrcAlpha
    17.      
    18.         CGPROGRAM
    19.      
    20.         // Define the vertex and fragment shader functions
    21.         #pragma vertex vert
    22.         #pragma fragment frag
    23.      
    24.         // Access Shaderlab properties
    25.         uniform float _GridThickness;
    26.         uniform float _GridSpacing;
    27.         uniform float4 _GridColour;
    28.         uniform float4 _BaseColour;
    29.      
    30.         // Input into the vertex shader
    31.         struct vertexInput {
    32.             float4 vertex : POSITION;
    33.         };
    34.  
    35.         // Output from vertex shader into fragment shader
    36.         struct vertexOutput {
    37.           float4 pos : SV_POSITION;
    38.           float4 worldPos : TEXCOORD0;
    39.         };
    40.      
    41.         // VERTEX SHADER
    42.         vertexOutput vert(vertexInput input) {
    43.           vertexOutput output;
    44.           output.pos = UnityObjectToClipPos(input.vertex);
    45.           // Calculate the world position coordinates to pass to the fragment shader
    46.           output.worldPos = mul(unity_ObjectToWorld, input.vertex);
    47.           return output;
    48.         }
    49.  
    50.         // FRAGMENT SHADER
    51.         float4 frag(vertexOutput input) : COLOR {
    52.           if (frac(input.worldPos.x/_GridSpacing) < _GridThickness || frac(input.worldPos.y/_GridSpacing) < _GridThickness) {
    53.             return _GridColour;
    54.           }
    55.          else if (frac(input.worldPos.x/_GridSpacing) < _GridThickness || frac(input.worldPos.z/_GridSpacing) < _GridThickness) {
    56.             return _GridColour;
    57.          }
    58.           else {
    59.             return _BaseColour;
    60.           }
    61.         }
    62.     ENDCG
    63.     }
    64.   }
    65. }
    66.  
     
  12. psangj

    psangj

    Joined:
    Oct 12, 2017
    Posts:
    1
     
  13. jmgek

    jmgek

    Joined:
    Dec 9, 2012
    Posts:
    103
    Hate to Necro, but for @Zer0_Ph34r shader just switch up line 52:
    Code (CSharp):
    1. if (frac(input.worldPos.x/_GridSpacing) < _GridThickness || frac(input.worldPos.z/_GridSpacing) < _GridThickness) {
     
    MisterMashu likes this.
  14. kb_z

    kb_z

    Joined:
    May 14, 2021
    Posts:
    9
    Is there any way to make it so that the grid isn't based off world position and instead use the object position?

    The current implementation makes the grid stay "Locked" to the world, so moving objects creates a weird effect where it doesn't seem as if the object was moving. (I just started looking into shaders for a small project)