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:
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:
Billboards are also widely used in depicting the characters of Octopath Traveler. Now isn’t that something?
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:
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:
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;
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.
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:
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:
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.
This can achieve the same result as the Solution 1.
Let’s get back to this matrix.
The upper-left 3x3 submatrix is actually not random garbled numbers, and each column stands for something. Specifically,
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.
And here’s the end result.
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:
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!
Comments