A semi-curated blog of computer graphics and rendering.

This is a blog post from eons past, remastered. Originally written at 2019-02-11.

Models loading & rendering come into play after using OpenGL for some time. But what if you are way too lazy and don’t want to learn how to make models (like me,) or when something is really, really far away, and it doens’t matter if a simple image is suffice for the realism?

That’s when billboard comes into rescue. Take a look at this:

An image showing a bald man. The bald man is rendered using billboards.

Billboards are actually used quite commonly in gamedev. It serves as the fishing float in Minecraft, shown in the image below. Notice that looking down from suhc a high angle, the fishing float should not face directly to the camera:

Minecraft's fishing float.

Billboards are also widely used in depicting the characters of Octopath Traveler. Now isn’t that something?

Billboard characters in Octopath Traveler.

Solution 1

There are various ways to achieve the billboard effect. I have summarized some implementable ways after trying (and failing at) various methods. The first one comes from “The 3D Way” in opengl-tutorial:

A health bar with a rotating cube beneath.

In the above GIF (or as some say, JIF,) the cube is not rotating; it’s the camera that’s rotating around the cube. opengl-tutorial treats the billboard problem as generating an appropriate model matrix for the billboard. The billboard can be seen as a rectangle defined in the model space:

The billboard defined in model space

By redefining the billboard center to the world space, the x axis to the camera right, and the y axis to the camera up, we can guarantee that the billboard is facing the camera at just the right spot:

vec3 vertexPosition_worldspace =
    billboardCenter_wordspace
    + CameraRight_worldspace * billboardVertices.x * BillboardSize.x
    + CameraUp_worldspace * billboardVertices.y * BillboardSize.y;

Billboard, but transformed to the world space

The billboard vertices can then be passed through the MVP vertices just like regular models.

This can achieve the billboard effect shown in the Minecraft fishing float. The billboard faces the camera even when the camera is high up. But sometimes, this effect is not to be desired. For example, if I am high up in the sky, and I look down on the trees, the trees simply should not appear to be facing the camera still.

Billboard trees in their correct form.

Solution 2

And so here comes the second solution. From lighthouse3d, this is an archaic technique, and is much simpler than Solution 1. You can feel the archaic-ness from the screenshot:

Vertical rotation only billboard.

First, recall the MVP transformation.

gl_Position = perspec * view * model * vec4(aPos, 1.0);

The perspec is the perspective matrix, which in simple terms, is responsible for things appear smaller when they are further away. (I know it does more than that, but this is just a simplification.) That means the object is already kinda in camera plane within view * model, including rotation, scaling, translation, you have it. So let’s take a look at the view * model matrix:

The view * model matrix

From how the matrix transformation works we know that the upper-left 3x3 matrix is responsible for rotation, and the last column is responsible for translating the billboard from the world space to camera space. So by setting the upper-left 3x3 matrix to an identity matrix, there will be no more rotation for the billboard - meaning it will always be how it appears in the model space - that is, facing directly at us.

Setting the upper left 3x3 matrix to the identity matrix.

This can achieve the same result as the Solution 1.

But What About the Trees?

Let’s get back to this matrix.

The view * model matrix

The upper-left 3x3 submatrix is actually not random garbled numbers, and each column stands for something. Specifically,

  • The first column stands for the right vector of the camera.
  • The second column stands for the up vector of the camera.
  • The third column stands for the front vector of the camera.

However, that’s not true; because as stated in this post, the matrix is actually the transpose (or inverse) of the \([\text{right}, \text{up}, \text{front}]\) matrix, because the view matrix is responsible for rotating the world, not the camera. So, by keeping the second column unchanged, the billboard will now only rotate along the Y axis, but nothing else.

Vertical-rotation only matrix.

And here’s the end result.

An image showing a pixelated bald man from a high place. The bald man is rendered using vertical rotation-only billboards.

Further Readings

And that’s it! Two cool approaches to achieve billboarding. According to lighthouse3d however, Solution 2 is only achieved via cheating - because billboards should always face you no matter the camera angle, and here’s a counterexample:

An image showing lots of billboards.

Here, the billboards on the left side or the right side of the camera should face slightly left/right, not directly front. Real billboards in this sense can be done via cylindrical or spherical billboard, and you can check out both methods in his tutorial paper. Until next time!

+ Loading comments +
Copyleft 2023 42yeah.