{"id":281,"date":"2016-06-01T13:03:40","date_gmt":"2016-06-01T03:03:40","guid":{"rendered":"https:\/\/ocias.com\/blog\/?p=281"},"modified":"2016-06-01T14:11:00","modified_gmt":"2016-06-01T04:11:00","slug":"unity-stipple-transparency-shader","status":"publish","type":"post","link":"https:\/\/ocias.com\/blog\/unity-stipple-transparency-shader\/","title":{"rendered":"Unity Stipple Transparency Shader"},"content":{"rendered":"<p>Transparency in 3D games is still really tough to get right.\u00a0You want a shader\u00a0that is\u00a0cheap performance-wise,\u00a0avoids order\/sorting issues and works across different platforms\/rendering pipelines. Stippling is an old-school solution that works perfectly in most cases. I&#8217;ve put together a Unity stipple implementation, which you can download and use however you like.<!--more--><\/p>\n<p>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.<\/p>\n<p>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:<\/p>\n<p><a href=\"https:\/\/ocias.com\/blog\/wp-content\/uploads\/2016\/06\/UnityIssues-1.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-288 size-full\" src=\"https:\/\/ocias.com\/blog\/wp-content\/uploads\/2016\/06\/UnityIssues-1.gif\" alt=\"A comparison of default alpha blending and my Unity stipple transparency shader\" width=\"640\" height=\"640\" \/><\/a><\/p>\n<p>I&#8217;ve searched for a while for a stipple\/screen-door\/dithering shader for Unity, but wasn&#8217;t able to find any results. In the end, I&#8217;ve decided to throw together one of my own. I was able to find an example in another engine in <a href=\"https:\/\/www.digitalrune.com\/Blog\/Post\/1743\/Screen-Door-Transparency\">an article by Digital Rune<\/a>. I fixed it up to work in Unity&#8217;s shader language (you can&#8217;t access a matrix using a double index in Unity, what the heck?), here&#8217;s my diffuse version:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">Shader \"Ocias\/Diffuse (Stipple Transparency)\" {\r\nProperties {\r\n    _MainTex (\"Base (RGB)\", 2D) = \"white\" {}\r\n    _Transparency (\"Transparency\", Range(0,1)) = 1.0\r\n}\r\nSubShader {\r\n    Tags { \"RenderType\"=\"Opaque\" }\r\n    LOD 150\r\n\r\nCGPROGRAM\r\n#pragma surface surf Lambert noforwardadd\r\n\r\nsampler2D _MainTex;\r\n\r\nstruct Input {\r\n    float2 uv_MainTex;\r\n    float4 screenPos;\r\n};\r\n\r\nhalf _Transparency;\r\n\r\nvoid surf (Input IN, inout SurfaceOutput o) {\r\n    fixed4 c = tex2D(_MainTex, IN.uv_MainTex);\r\n    o.Albedo = c.rgb;\r\n    o.Alpha = c.a;\r\n\r\n    \/\/ Screen-door transparency: Discard pixel if below threshold.\r\n    float4x4 thresholdMatrix =\r\n    {  1.0 \/ 17.0,  9.0 \/ 17.0,  3.0 \/ 17.0, 11.0 \/ 17.0,\r\n      13.0 \/ 17.0,  5.0 \/ 17.0, 15.0 \/ 17.0,  7.0 \/ 17.0,\r\n       4.0 \/ 17.0, 12.0 \/ 17.0,  2.0 \/ 17.0, 10.0 \/ 17.0,\r\n      16.0 \/ 17.0,  8.0 \/ 17.0, 14.0 \/ 17.0,  6.0 \/ 17.0\r\n    };\r\n    float4x4 _RowAccess = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };\r\n    float2 pos = IN.screenPos.xy \/ IN.screenPos.w;\r\n    pos *= _ScreenParams.xy; \/\/ pixel position\r\n    clip(_Transparency - thresholdMatrix[fmod(pos.x, 4)] * _RowAccess[fmod(pos.y, 4)]);\r\n}\r\nENDCG\r\n}\r\n\r\nFallback \"Mobile\/VertexLit\"\r\n}<\/pre>\n<p>It&#8217;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 <strong>slower<\/strong> 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&#8217;re after.<\/p>\n<h2>Unity Stipple Shader Download<\/h2>\n<p>Here&#8217;s a Unitypackage with both the above diffuse shader and a standard shader variant, do whatever you like with it: <a href=\"https:\/\/ocias.com\/blog\/wp-content\/uploads\/2016\/06\/OciasStippleShadersV1.unitypackage\">Download Version 1<\/a><\/p>\n<p>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! &#x1f60a;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Transparency in 3D games is still really tough to get right.\u00a0You want a shader\u00a0that is\u00a0cheap performance-wise,\u00a0avoids order\/sorting issues and works across different platforms\/rendering pipelines. Stippling is an old-school solution that works perfectly in most cases. I&#8217;ve put together a Unity stipple implementation, which you can download and use however you like.<\/p>\n","protected":false},"author":1,"featured_media":296,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[14,9,3],"class_list":["post-281","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorised","tag-shader","tag-tutorial","tag-unity3d"],"_links":{"self":[{"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/posts\/281","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/comments?post=281"}],"version-history":[{"count":7,"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/posts\/281\/revisions"}],"predecessor-version":[{"id":297,"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/posts\/281\/revisions\/297"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/media\/296"}],"wp:attachment":[{"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/media?parent=281"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/categories?post=281"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ocias.com\/blog\/wp-json\/wp\/v2\/tags?post=281"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}