Cg Programming/Unity/Billboards

This tutorial introduces billboards.

Billboards along a highway. Note the orientation of the billboards for best visibility.

It is based on Section “Textured Spheres” and the discussion in Section “Vertex Transformations”.

Billboards

edit

In computer graphics, billboards are textured rectangles that are transformed such that they always appear parallel to the view plane. Thus, they are similar to billboards along highways in that they are rotated for best visibility. However, they are different from highway billboards since they are dynamically rotated to always offer best visibility.

The main use of billboards is to replace complex three-dimensional models (e.g. grass, bushes, or even trees) by two-dimensional images. In fact, Unity also uses billboards to render grass. Moreover, billboards are often used to render two-dimensional sprites. In both applications, it is crucial that the billboard is always aligned parallel to the view plane in order to keep up the illusion of a three-dimensional shape although only a two-dimensional image is rendered.

Vertex Transformation for Billboards

edit

Similarly to Section “Skyboxes”, we can use the default cube object to render a billboard. (For it to work with the default quad, you should change the minus sign to a plus sign in the code. For the default plane, you have to use the z coordinate instead of the y coordinate.) The basic idea is to transform only the origin   of the object space to view space with the standard model-view transformation UNITY_MATRIX_MV. (In homogeneous coordinates all points have a 1 as fourth coordinate; see the discussion in Section “Vertex Transformations”.) View space is just a rotated version of world space with the   plane parallel to the view plane as discussed in Section “Vertex Transformations”. Thus, this is the correct space to construct an appropriately rotated billboard. We subtract the   and   object coordinates (vertex.x and vertex.y) from the transformed origin in view coordinates and then transform the result with the projection matrix UNITY_MATRIX_P:

            output.pos = mul(UNITY_MATRIX_P, 
              mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
              + float4(input.vertex.x, input.vertex.y, 0.0, 0.0));

In order to have billboards of different sizes, we add shader properties _ScaleX and _ScaleY to scale the object coordinates; thus, the code becomes:

            output.pos = mul(UNITY_MATRIX_P, 
              mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
              + float4(input.vertex.x, input.vertex.y, 0.0, 0.0)
              * float4(_ScaleX, _ScaleY, 1.0, 1.0));

Apart from this, we only have to set texture coordinates:

            output.tex = input.tex;

Then the fragment shader just looks up the color at the interpolated texture coordinates.

Complete Shader Code

edit

The complete shader code for the standard cube object is now:

Shader "Cg  shader for billboards" {
   Properties {
      _MainTex ("Texture Image", 2D) = "white" {}
      _ScaleX ("Scale X", Float) = 1.0
      _ScaleY ("Scale Y", Float) = 1.0
   }
   SubShader {
      Pass {   
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag

         // User-specified uniforms            
         uniform sampler2D _MainTex;        
         uniform float _ScaleX;
         uniform float _ScaleY;

         struct vertexInput {
            float4 vertex : POSITION;
            float4 tex : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;

            output.pos = mul(UNITY_MATRIX_P, 
              mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0))
              + float4(input.vertex.x, input.vertex.y, 0.0, 0.0)
              * float4(_ScaleX, _ScaleY, 1.0, 1.0));
 
            output.tex = input.tex;

            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, float2(input.tex.xy));   
         }
 
         ENDCG
      }
   }
}

Summary

edit

Congratulations, you made it to the end of this tutorial. We have seen:

  • How to transform and texture a cube in order to render a view-aligned billboard.

Further reading

edit

If you still want to learn more

Reader comments

edit

In order to avoid "flickering" when rendering several billboards I had to add the following tag in the Subshader

Tags { "DisableBatching" = "True" }

< Cg Programming/Unity

Unless stated otherwise, all example source code on this page is granted to the public domain.