Programmer-friendly Billboard Shader

Here’s a programmer-friendly billboard shader I worked up this evening. I needed one (apparently Camera.main is basically an Object.FindGameObjectsWithTag call?) and Googled around for a few hours, finding plenty of potential billboard shaders, but none that made any effort to explain what was going on in a way that someone unlearned like myself could understand. Hopefully, even if the comments are imperfect, they would at least point someone in the right direction to making sense of the arcane wizardry involved.

Simply create a material using this shader, then assign the material to any Sprite Renderers you want to billboard.

Also most of the examples I found on the web seemed to be outdated, as Unity threw warnings about certain matrix multiplications, so this one is implemented with the helper functions Unity recommended.

Shader "Custom/Billboard"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
   
    SubShader
    {
        Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "DisableBatching" = "True" }

        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 pos : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            const float3 vect3Zero = float3(0.0, 0.0, 0.0);

            sampler2D _MainTex;

            v2f vert(appdata v)
            {
                v2f o;

                float4 camPos = float4(UnityObjectToViewPos(vect3Zero).xyz, 1.0);    // UnityObjectToViewPos(pos) is equivalent to mul(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz,
                                                                                    // This gives us the camera's origin in 3D space (the position (0,0,0) in Camera Space)

                float4 viewDir = float4(v.pos.x, v.pos.y, 0.0, 0.0);            // Since w is 0.0, in homogeneous coordinates this represents a vector direction instead of a position
                float4 outPos = mul(UNITY_MATRIX_P, camPos + viewDir);            // Add the camera position and direction, then multiply by UNITY_MATRIX_P to get the new projected vert position

                o.pos = outPos;
                o.uv = v.uv;

                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                // Don't need to do anything special, just render the texture
                return tex2D(_MainTex, i.uv);
            }
            ENDCG
        }
    }
}
3 Likes

Thanks! Exactly what i was looking for :slight_smile:

Thank you, looks nice. Do you have also an idea, how to scale the billboard always to the same size, so that we can use this like normal UI on a canvas?

I imagine you’d want to modify the shader to multiply the billboard scale by some function of the distance between the camera and the billboard. I’d check this article out: https://en.wikibooks.org/wiki/Cg_Programming/Unity/Billboards