


 
Billboarding Tutorial
Cheating  Fast and Easy Spherical Billboards
The technique about to be presented isn't true billboarding. Instead it provides a cheap way of achieving an approximation that may be good enough in some applications.
The source code for this tutorial is an extension to one of the projects on the GLUT tutorial. If you're not familiar with GLUT then maybe you should check it out to get a better grasp of the source code.
The following image is a screenshot of the demo. It shows a snowman plus some billboarded trees. Although it is hard to tell, the trees aren't facing the camera, although it is hard to tell. Instead they are facing a plane perpendicular to the cameras viewing direction.
The next diagram gives a clearer picture of what's going on. The black circle at the bottom represents the camera. The vector starting from the camera is the current viewing direction. This vector defines the orientation of the plane perpendicular to the cameras viewing direction. The objects in the scene, O1..O3, have been rotated so that their front facing vector is pointing to this plane. It is assumed that the objects in the scene are positioned in the local origin, and that they're facing the poistive Z axis.
An approach to achieve this effect requires the modelview matrix. As you're aware the modelview matrix stores the geometric transformations, rotations, scales and translations, you do. This matrix contains the required transformations to change the coordinates you input, world coordinates, into camera coordinates.
The top 3 values of the right column provide the current position of the local origin relative to the camera's position and orientation. The top 3x3 submatrix contains the scaling and rotation operations. Setting this submatrix to the identity matrix effectively reverses these operations, so that the cameras viewing direction is aligned with the worldsZ axis. The up and right vectors of the camera are also aligned with the worlds axis, which means that this type of billboard acts like a cheat to spherical billboarding. The center of the billboard is the local origin. If you're planning to do your trees with this type of billboarding then when the user looks up or down the trees will bend forwards and backwards as well, which may be a little awkward. This is because the orientation of the billboard depends on the camera's orientation as opposed to the camera's position.
In practice, setting the submatrix to the identity matrix means the your object won't suffer any rotation when it is rendered. Therefore it will be rendered in the same way as if the camera was looking down the negative Z axis.
Note that scaling is also reversed, so if you wanted a tall tree you're not going to get it with this method, unless you scale after you changed the modelview matrix.
The first step is to save the current modelview matrix. Afterwards get the modelview matrix. Then reset the top 3x3 submatrix to the identity matrix. Load the matrix in to the OpenGL state machine, and render your object in the local origin. Finally restore the original modelview matrix.
float modelview[16];
int i,j;
// save the current modelview matrix
glPushMatrix();
// get the current modelview matrix
glGetFloatv(GL_MODELVIEW_MATRIX , modelview);
// undo all rotations
// beware all scaling is lost as well
for( i=0; i<3; i++ )
for( j=0; j<3; j++ ) {
if ( i==j )
modelview[i*4+j] = 1.0;
else
modelview[i*4+j] = 0.0;
}
// set the modelview with no rotations and scaling
glLoadMatrixf(modelview);
drawObject();
// restores the modelview matrix
glPopMatrix();
With the above snippet of code, the object will be rotated to face the plane perpendicular to the cameras viewing direction. The centre for this rotation is the local origin.
The above code can be divided in two functions, besides the rendering function, drawObject. The first function will setup the modelview matrix, and the second will restore the current matrix.
void billboardCheatSphericalBegin() {
float modelview[16];
int i,j;
// save the current modelview matrix
glPushMatrix();
// get the current modelview matrix
glGetFloatv(GL_MODELVIEW_MATRIX , modelview);
// undo all rotations
// beware all scaling is lost as well
for( i=0; i<3; i++ )
for( j=0; j<3; j++ ) {
if ( i==j )
modelview[i*4+j] = 1.0;
else
modelview[i*4+j] = 0.0;
}
// set the modelview with no rotations
glLoadMatrixf(modelview);
}
void billboardEnd() {
// restore the previously
// stored modelview matrix
glPopMatrix();
}
The source code for rendering a billboard object becomes:
billboardCheatSphericalBegin();
drawObject();
billboardEnd();
As mentioned before, scaling operations are lost when you set the new modelview matrix. If you want to scale your objects you can do it after setting up the billboard as in the following snippet.
billboardCheatSphericalBegin();
glScalef(1,2,1);
drawObject();
billboardEnd();
