Search Unity

Programmer-friendly Billboard Shader

Discussion in 'Shaders' started by thesupersoup, Aug 9, 2019.

  1. thesupersoup

    thesupersoup

    Joined:
    Nov 27, 2017
    Posts:
    70
    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.

    Code (CSharp):
    1. Shader "Custom/Billboard"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex("Texture", 2D) = "white" {}
    6.     }
    7.    
    8.     SubShader
    9.     {
    10.         Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "DisableBatching" = "True" }
    11.  
    12.         ZWrite Off
    13.         Blend SrcAlpha OneMinusSrcAlpha
    14.  
    15.         Pass
    16.         {
    17.             CGPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.  
    21.             #include "UnityCG.cginc"
    22.  
    23.             struct appdata
    24.             {
    25.                 float4 pos : POSITION;
    26.                 float2 uv : TEXCOORD0;
    27.             };
    28.  
    29.             struct v2f
    30.             {
    31.                 float4 pos : SV_POSITION;
    32.                 float2 uv : TEXCOORD0;
    33.             };
    34.  
    35.             const float3 vect3Zero = float3(0.0, 0.0, 0.0);
    36.  
    37.             sampler2D _MainTex;
    38.  
    39.             v2f vert(appdata v)
    40.             {
    41.                 v2f o;
    42.  
    43.                 float4 camPos = float4(UnityObjectToViewPos(vect3Zero).xyz, 1.0);    // UnityObjectToViewPos(pos) is equivalent to mul(UNITY_MATRIX_MV, float4(pos, 1.0)).xyz,
    44.                                                                                     // This gives us the camera's origin in 3D space (the position (0,0,0) in Camera Space)
    45.  
    46.                 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
    47.                 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
    48.  
    49.                 o.pos = outPos;
    50.                 o.uv = v.uv;
    51.  
    52.                 return o;
    53.             }
    54.  
    55.             fixed4 frag(v2f i) : SV_Target
    56.             {
    57.                 // Don't need to do anything special, just render the texture
    58.                 return tex2D(_MainTex, i.uv);
    59.             }
    60.             ENDCG
    61.         }
    62.     }
    63. }
     
    Mystic_Quest and FailCake like this.
  2. FailCake

    FailCake

    Joined:
    Aug 14, 2013
    Posts:
    2
    Thanks! Exactly what i was looking for :)
     
  3. Zapan15

    Zapan15

    Joined:
    Apr 11, 2011
    Posts:
    186
    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?
     
  4. thesupersoup

    thesupersoup

    Joined:
    Nov 27, 2017
    Posts:
    70