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:
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! 😊
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.
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 (: 😀 .
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.
(it is called “Dithering Smoothing” apparently)
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.
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.
Great to hear, Mark. Hope your project goes well!
It doesn’t work on Android platform. And i can’t understand why(
Great! Its working perfectly, even with the newest Unity Version 5.6! Thank you so much!
This is so perfect! I’m using it in Unity 2017.1 for Diluvion. Thanks for making this!!
You’re welcome! Hoping Diluvion is a huge success!
Is there anyway to limit this to only a section of a model? I have many multi layer models where only the outermost layer needs to have transparency. Is it possible to still render what’s underneath a clipped pixel if it’s part of the same model? I’m trying to avoid using multiple materials and models for so many parts. An alpha cut out would work the best for my use but forward pass is unacceptable due to it ruining my screen effect.
Hi, very nice shader. Is it possible for the shader to create and receive stippled shadows? When using the shader to ‘fade out’ an object, the received shadows on the object are still visible, which leaves the shadows floating in space. Something to do with the shadow caster/collector?
Yeap, you’d just need to add a shader caster pass to the shader with the same stippling as the main pass.
While this is not what I was looking for, with my newbie knowledge of computer graphics and shaders I have to admit this is quite a clever way of doing it and looks very good, thanks!
This shader is so good! Is it possible to use a normal map with it?
It’s been a long time since I used Unity, but I don’t see why not! The standard shader version should already have a normal map slot, and it’s just alpha clipping, so you can copy and paste the code into any other shader you’d like fairly easily too.
Yep, it worked. Thank you!