For performance reasons, i have to create my own billboards to replace some geometry. I modified the standard sprite shader to Cull Back and ZWrite On. Now my billboard layers are rendered in the correct order, but the ones in the front cull the ones in the back, even on transparent areas. This is due to the shape of the Plane/Quad i used as basis.

You can see this on the following screenshots:

enter image description here

The transparent pixels are occluding the second layer.

enter image description here

Front piece drawn with white texture to show dimensions.

How can i modify my shader below to avoid drawing the transparent pixels into the depth buffer?

    // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

    Shader "Sprites/DefaultSingle"
            [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
            _Color ("Tint", Color) = (1,1,1,1)
            [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
            [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
            [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
            [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
            [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0

            Cull Back
            Lighting Off
            ZWrite On
            Blend One OneMinusSrcAlpha

                #pragma vertex SpriteVert
                #pragma fragment SpriteFrag
                #pragma target 2.0
                #pragma multi_compile_instancing
                #pragma multi_compile _ PIXELSNAP_ON
                #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
                #include "UnitySprites.cginc"
  • \$\begingroup\$ I don't think you can. You might be able to get away with using the stencil mask instead though. Basically, if the alpha is 0, don't modify the stencil mask, otherwise do. Then only continue drawing where the mask is still 0. \$\endgroup\$ May 6, 2017 at 16:23

1 Answer 1


Two answers here; the first one is the one that usually works best, the second is closer to the exact answer you requested.

First method

In your example image, it looks like you are drawing two perpendicular panels. If you split the panels at the point where they intersect, creating four panels, they will sort and draw properly without having to write to Z at all (though you still may, if you find some reason to). Since these sprites are in the transparent queue anyway, they will always be sorted back-to-front by Unity before rendering.

Second method

You'll need to copy the fragment shader out of UnitySprites.cginc for this one. In that shader, after reading the sprite texture color and multiplying it by the incoming color, use the clip instruction to skip drawing anything that has a low alpha value. In my current Unity version, the new fragment shader is:

        fixed4 frag(v2f IN) : SV_Target
            fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
            clip(c.a - 1.0 / 255.0);
            c.rgb *= c.a;
            return c;

Change the 1 in the clip call to whatever alpha threshold (out of 255) you want.

This method is only good if you're using point filtering and you don't have any alpha values that aren't 0 or 1. An alpha value of, say, 0.5 will blend with whatever was already in the color buffer behind it, but still block later billboard pixels from rendering. You would be exchanging your large quad edge artifacts for fringe artifacts.

  • \$\begingroup\$ Thanks very much man! The second method works beautifully for me, because i'm lazy and have to build too many of those billboards! \$\endgroup\$
    – stainless
    May 6, 2017 at 19:00
  • \$\begingroup\$ Fair enough! Glad I could help. \$\endgroup\$
    – Victor T.
    May 8, 2017 at 16:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .