Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Anti-Aliased Line Shader

Discussion in 'Shaders' started by JoeMan500, Jun 8, 2023.

  1. JoeMan500

    JoeMan500

    Joined:
    Jul 26, 2022
    Posts:
    4
    Hi All,

    I am struggling to get anti-aliasing working on my simple shader. I understand the concept of changing the alpha in the fragment shader. I feel like I need to use the current vertex and the next, to get the line, then work out how far away from the line the pixel will be, then change the alpha depending on this.

    Here is a screenshot of what is currently happening, to show the badly aliased lines, I have also included my code. Turning on MSAA fixes this issue, but drops from 160 FPS to 100, as this is only a small sample, I feel like that may be too much performance hit to turn it on.

    upload_2023-6-8_15-41-31.png

    Code (CSharp):
    1. Shader "Custom/Aliased Line Shader"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color", Color) = (1,1,1,1)
    6.         _WireframeThickness("Wireframe Thickness", float) = 1
    7.         [MaterialToggle]
    8.         _AntiAliasing("Aliasing", float) = 1
    9.     }
    10.     Subshader
    11.     {
    12.         Tags { "RenderType" = "Opaque" }
    13.         LOD 200
    14.         // NB: We add the blend mode in so that we an alias our wireframe.
    15.         Blend SrcAlpha OneMinusSrcAlpha
    16.  
    17.         Pass
    18.         {
    19.             CGPROGRAM
    20.             #pragma vertex vert
    21.             #pragma fragment frag
    22.             //#pragma geometry geom
    23.  
    24.             fixed4 _Color;
    25.             float _WireframeAliasing;
    26.             float _WireframeThickness;
    27.             bool _AntiAliasing;
    28.             // vertex shader inputs
    29.             struct appdata
    30.             {
    31.                 float4 vertex : POSITION; // vertex position
    32.             };
    33.  
    34.             struct v2f
    35.             {
    36.                 float4 vertex : SV_POSITION;
    37.                 float3 worldPos : TEXCOORD0;
    38.             };
    39.  
    40.  
    41.             // vertex shader
    42.             v2f vert(appdata v)
    43.             {
    44.                 v2f o;
    45.                 // transform position to clip space
    46.                 // (multiply with model*view*projection matrix)
    47.                 o.vertex = UnityObjectToClipPos(v.vertex);
    48.                 o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    49.                 return o;
    50.             }
    51.  
    52.  
    53.             fixed4 frag(v2f i) : SV_Target
    54.             {
    55.                 float alpha = 1.0f;
    56.                 if (_AntiAliasing > 0)
    57.                 {
    58.                     // I know this is wrong, but just don't know how to do what I wanted
    59.                     float distance = length(i.worldPos.xyz - _WorldSpaceCameraPos.xyz);
    60.                     // Compute the alpha value for the fragment.
    61.                     alpha = smoothstep(0.0, _WireframeThickness, distance);
    62.                 }
    63.  
    64.  
    65.                 // Set the fragment color.
    66.                 return fixed4(_Color.r, _Color.g, _Color.b, alpha);
    67.             }
    68.  
    69.  
    70.             ENDCG
    71.         }
    72.     }
    73. }
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,256
    How are you rendering the wireframe in the first place? Are you making a copy of the mesh data and changing the topology to lines?

    The only way to anti-alias those kinds of lines is with MSAA.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,256
    To do anti-aliased lines in a shader, you need geometry that’s wider than one pixel. Hardware draw lines are 1 pixel wide. There are API calls that let you set lines to any width you want, but they’re not exposed by Unity, and it doesn’t matter that they’re not because no matter what you set on modern consumer GPUs it’ll render them 1 pixel wide still. Also they’ll still be aliased.

    If you want thicker, anti-aliased lines, you need to render the lines as mesh geometry that’s at least 0.5 pixels wider than you want the line to be. You can do this with Unity’s Line Renderer, or one of a handful of tools on the Asset Store, or using a geometry shader to expand the lines into mesh topology. You then need a gradient across the width of the line you can use to figure out how far from the edge of the line mesh geometry you are, like a UV where the x=0 on the left edge, and 1 on the right. You can then use partial screen space pixel derivatives to find out how much that value is changing in screen space, which will give you how far you are from either edge.

    Or you can buy the Shapes asset from the store which will do antialiased 3D lines out of the box. Or the Amazing Wireframe Shader which uses a slightly different shader based approach but is explicitly for doing what you’re trying to do.
     
  4. JoeMan500

    JoeMan500

    Joined:
    Jul 26, 2022
    Posts:
    4
    Hi @bgolus thanks for your replies.
    Yes I am processing the original mesh geometry into MeshGeometry.Lines.
    I was after a generic line shader as I have other types of lines that I am hoping to draw. Your second reply was really useful and helped me connect various shader code and concepts that I have seen online.
    I have had issues with Unity's Line Renderer in the past so I will avoid that and will attempt to do my own Thick Line shader. Failing that the Shapes asset seems a good option.
    Thanks once again and also for your various other posts on the forum that I have found really useful.