Created
March 8, 2026 03:40
-
-
Save ompuco/82fd6b2032ee353bb65e1ab5bbeb0c9e to your computer and use it in GitHub Desktop.
A shader for better pixel-perfect line mesh rasterization in Unity, since the default behavior on most graphics platforms make for some real garbage lines, especially if you wanted to use it for a project with low-resolution graphics.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Shader "ompuco/LineRaster" | |
| { | |
| Properties | |
| { | |
| _MainTex ("Texture", 2D) = "white" {} | |
| } | |
| SubShader | |
| { | |
| Tags { "RenderType"="Opaque" } | |
| LOD 100 | |
| //conservative rasterization to avoid making gaps when clipping | |
| Conservative True | |
| Pass | |
| { | |
| CGPROGRAM | |
| #pragma vertex vert | |
| #pragma geometry geom | |
| #pragma fragment frag | |
| // make fog work | |
| #pragma multi_compile_fog | |
| #include "UnityCG.cginc" | |
| struct appdata | |
| { | |
| float4 vertex : POSITION; | |
| float2 uv : TEXCOORD0; | |
| }; | |
| struct v2g | |
| { | |
| float4 vertex : SV_POSITION; | |
| float2 uv : TEXCOORD0; | |
| }; | |
| struct g2f | |
| { | |
| float2 uv : TEXCOORD0; | |
| UNITY_FOG_COORDS(1) | |
| float4 vertex : SV_POSITION; | |
| //store both coordinates of the current line pair here | |
| nointerpolation float4 coords : TEXCOORD3; | |
| }; | |
| sampler2D _MainTex; | |
| float4 _MainTex_ST; | |
| v2g vert (appdata v) | |
| { | |
| v2g o; | |
| o.vertex = v.vertex; | |
| o.uv = v.uv; | |
| return o; | |
| } | |
| [maxvertexcount(2)] | |
| void geom(line v2g IN[2], inout LineStream<g2f> lineStream) | |
| { | |
| g2f o; | |
| o.coords = 0; | |
| float4 coords0 = ComputeScreenPos(UnityObjectToClipPos(IN[0].vertex)); | |
| float4 coords1 = ComputeScreenPos(UnityObjectToClipPos(IN[1].vertex)); | |
| o.coords = float4( | |
| coords0.xy/coords0.w, | |
| coords1.xy/coords1.w | |
| ) * _ScreenParams.xyxy; | |
| for(int i = 0; i < 2; i++) | |
| { | |
| o.vertex = UnityObjectToClipPos(IN[i].vertex); | |
| UNITY_TRANSFER_FOG(o,o.vertex); | |
| o.uv = TRANSFORM_TEX(IN[i].uv, _MainTex); | |
| lineStream.Append(o); | |
| } | |
| lineStream.RestartStrip(); | |
| } | |
| //line rasterization | |
| float diag(float2 p0, float2 p1) | |
| { | |
| float2 d = abs(p1 - p0); | |
| return max(d.x, d.y); | |
| } | |
| // Created by PureAsbestos, 2023 | |
| // Free for any use. Credit appreciated but not required. | |
| float lineRaster(float2 p, float2 p0, float2 p1) | |
| { | |
| float stp = diag(p,p0); | |
| float n = diag(p0,p1); | |
| float t = (n==0.0)? 0.0 : stp/n; | |
| float2 pt = lerp(p0, p1, t); | |
| float2 d = abs(p - round(pt)); | |
| return (d.x < 0.5 | |
| && d.y < 0.5 | |
| && stp <= n) | |
| ? 1.0 : 0.0 ; | |
| } | |
| fixed4 frag (g2f i) : SV_Target | |
| { | |
| //Bresenham line test for pixels between the coordinates of the current line pair | |
| float lineTest = lineRaster( floor(i.vertex.xy), floor(i.coords.xy), floor(i.coords.zw) ); | |
| //discard pixels that aren't inside the desired line | |
| clip(lineTest-.5); | |
| // sample the texture | |
| fixed4 col = tex2D(_MainTex, i.uv); | |
| // apply fog | |
| UNITY_APPLY_FOG(i.fogCoord, col); | |
| return col; | |
| } | |
| ENDCG | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment