Unity Stipple Transparency Shader

Transparency in 3D games is still really tough to get right. You want a shader that is cheap performance-wise, avoids order/sorting issues and works across different platforms/rendering pipelines. Stippling is an old-school solution that works perfectly in most cases. I’ve put together a Unity stipple implementation, which you can download and use however you like.

Stipple transparency (or Screen-door transparency, or dithered transparency) works by omitting drawing more and more pixels from the object as transparency increases. This is obviously not physically accurate in any way, but looks convincing enough for many cases.

Traditional alpha blending transparency has issues with sorting polygons, drawing shadows, functioning with deferred rendering, as well as with overlapping geometry on complex meshes (unless you invest in writing to the z-buffer), take a look at a comparison with the default Unity (as of 5.4) transparency:

A comparison of default alpha blending and my Unity stipple transparency shader

I’ve searched for a while for a stipple/screen-door/dithering shader for Unity, but wasn’t able to find any results. In the end, I’ve decided to throw together one of my own. I was able to find an example in another engine in an article by Digital Rune. I fixed it up to work in Unity’s shader language (you can’t access a matrix using a double index in Unity, what the heck?), here’s my diffuse version:

Shader "Ocias/Diffuse (Stipple Transparency)" {
Properties {
    _MainTex ("Base (RGB)", 2D) = "white" {}
    _Transparency ("Transparency", Range(0,1)) = 1.0
}
SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 150

CGPROGRAM
#pragma surface surf Lambert noforwardadd

sampler2D _MainTex;

struct Input {
    float2 uv_MainTex;
    float4 screenPos;
};

half _Transparency;

void surf (Input IN, inout SurfaceOutput o) {
    fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
    o.Albedo = c.rgb;
    o.Alpha = c.a;

    // Screen-door transparency: Discard pixel if below threshold.
    float4x4 thresholdMatrix =
    {  1.0 / 17.0,  9.0 / 17.0,  3.0 / 17.0, 11.0 / 17.0,
      13.0 / 17.0,  5.0 / 17.0, 15.0 / 17.0,  7.0 / 17.0,
       4.0 / 17.0, 12.0 / 17.0,  2.0 / 17.0, 10.0 / 17.0,
      16.0 / 17.0,  8.0 / 17.0, 14.0 / 17.0,  6.0 / 17.0
    };
    float4x4 _RowAccess = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
    float2 pos = IN.screenPos.xy / IN.screenPos.w;
    pos *= _ScreenParams.xy; // pixel position
    clip(_Transparency - thresholdMatrix[fmod(pos.x, 4)] * _RowAccess[fmod(pos.y, 4)]);
}
ENDCG
}

Fallback "Mobile/VertexLit"
}

It’s worth mentioning that while the method this uses, called an alpha-test, is faster than alpha-blending in most cases, there appears to be a consensus that on iOS alpha-test is slower than alpha-blend. So if you plan to use this shader on mobile, do check in Xcode if the Unity stipple transparency shader is giving the results you’re after.

Unity Stipple Shader Download

Here’s a Unitypackage with both the above diffuse shader and a standard shader variant, do whatever you like with it: Download Version 1

I hope this helps you with your game, do let me know if you end up using it, or if you run into any problems! 😊

8 thoughts on “Unity Stipple Transparency Shader”

  1. Very useful post and unique. Thanks for the shader code, these shaders are really good for LOD transitions and even GTA V had such a shader. Good job.

  2. Since I currently don’t know much about writing shaders. I have a question about this, How to use it for LOD objects? (How to let the transparency slider adjust the transparency for an object based on camera distance?) Would you help a bit (: 😀 .

  3. And my last question here is, do you know any way to blur this so the checker board effect won’t be obvious? Sorry for asking too much.

  4. Hey Dan, glad you’ve found it useful. Unfortunately I don’t have much experience with LOD transitions, but as for the obscuring the checker board effect you could try alpha-to-coverage/AlphaToMask if MSAA is an option.

  5. Thank you so much for this! Worked like a charm in my current project and I plan to definitely use it for future ones as well.

Leave a Reply

Your email address will not be published.