Billboarding How To
1. Introduction 2. What is Billboarding 3. Terms 4. Point Sprites 4.1 Collective Billboarding 4.2 Individual Billboarding 5. Axis Aligned Billboards 6. Arbitrary Axis Billboards 7. Using Those Billboard Vectors 8. Rendering a Billboard
I looked around a lot for a good billboarding tutorial, but the most I could ever find was a short document that missed a lot or some code with bad commenting. My intention with this document and code was to resolve those issues. I hope this document explains things well enough so you can get billboarding to work in your code. There is also accompanying source to demonstrate this, the source requires that you have freetype and directX5 to build; although I did include a Windows® executable for those who cant build it. You may notice that there is a lot more code than just billboarding code that comes with. This is a collection of source I written over time, and most my projects I make are based on it. I made the billboarding code in a separate file from this, so hopefully you can just paste the source into your project if you so desire. Questions and comments can be emailed to: email@example.com.
This document should give you an overview of billboarding and it should also teach you how to implement billboarding in your own code. This was written with the purpose of assisting the MDX file document to describe the billboarding techniques used for rendering the MDX models. But it is also intended to be a standalone tutorial. The MDX document is a collection of information on how to render the MDX models from Blizzards WarCraft3®. This document is not finished yet, and will be released some day soon.
Billboarding is a simple concept, but can be difficult to implement. A billboard is a flat object, usually a quad (square), which faces the camera. This direction usually changes constantly during runtime as the object and camera move, and the object needs to be rotated each frame to point in that direction. There are two types of billboarding: point and axis. Point sprites, or point billboards, are a quad that is centered at a point and the billboard rotates about that central point to face the user. Axis billboards come in two types: axis aligned and arbitrary. The axis-aligned (AA) billboards always have one local axis that is aligned with a global axis, and they are rotated about that axis to face the user. The arbitrary axis billboards are rotated about any axis to face the user.
Billboards will always face the camera, but this technique can also be used to face other objects as well. For instance, this can be used to rotate a turret to face a target, or to have the head on a character follow another character.
The concepts in the document use the right handed coordinate system and assume that the billboards you are drawing will face down the +z axis, up is the +y axis, and right is the +x axis. I found this site: http://www.evl.uic.edu/ralph/508S98/coordinates.html has a good explanation.
Points sprites are the most common billboard you will usually see, and of course they have a couple flavors to them. The sprites can be billboarded collectively or individually. Collective billboarding is very quick, because you only need to create one transformation matrix to share between all the points, while individual billboards require that you calculate a new transformation matrix for each billboard.
Collective billboards all face the same direction, and start to look flat as they get closer to the edges of the screen. This is because the direction the billboards face is calculated as the inverse look direction of the camera. This makes a quick and dirty calculation, but may not create the effect you are looking for. The up vector for the collective point sprite is the same as the up vector for the camera. And the right vector is the inverse of the cameras right vector.
Individual billboards require some math to point at the camera. To start, you will need to know the camera up vector and position and the billboard position. We will use these to calculate the local billboards axis. The billboard look vector is calculated from the camera position and billboard position. The vector is from the billboard to the camera; normalize the vector when finished.
look = camera_pos - point_pos;
Next, calculate the right vector for the billboard. To do this though, you first need an up vector for the billboard. But to get the final up vector you first need the billboards right vector. Obviously were going nowhere here, but there is a simple way out. We can use the camera up vector as the temporary up vector for the billboard. This works because the final billboard up vector, the billboard look vector, and the camera up vector lie along the plane that contains the camera and billboard locations. The plane also has a normal equal to the billboard right vector. That can be a lot to take in, so look at this pretty picture to help. The blue vectors are the direction the object is facing, the green vectors are up vectors, and the red vectors are right.
Figure 1 - All three green vectors lie in the plane outlined in grey, the dark blue vector on the
particle also lies in this plane. The dark red vector is perpendicular to the plane.
right = up x look;
We can now calculate the up vector for the billboard with another cross product; this is the final up vector for the billboard.
up = look x right;
Now, you may be asking yourself why we couldnt just use the camera up vector for the billboard up vector. If we did this, our local axis for the billboard (right, up, look) wouldnt all be perpendicular to each other, that is some of the angles between the axis would not be 90º to the other axis. This would make for some odd side effects when applying the rotation matrix to use for billboarding our object.
Axis aligned billboards lock their up vector into a global axis, either x or y or z. The billboard is then rotated around the local y axis to face the camera. The calculations follow the same format as above, but we are given the local up vector to make the math simpler.
Figure 2 The three Axis Aligned billboards, each access shows the local Y axis drawn in green over
the axis that the billboard is aligned to. The billboard is draw in its axis color about that axis.
right = up x look;
Arbitrarily aligned billboards might sound difficult, heck it kind of hard to pronounce, but they follow a similar idea and code path as the rest of the billboards types. The billboard calculation starts like the rest, calculate the billboard look vector as the vector from the billboard center to the camera position. Although this value isnt the final look vector, its a temporary value used to calculate the right and up vectors. This works on the same principal as the point sprite using the camera up vector as a temporary billboard up vector. This look vector lies along the same plane as the final look vector will; but the temporary look vector is not perpendicular to the billboard up vector. The billboard up vector is the arbitrary axis we want the billboard to rotate about. Now that we have two vectors we can do a cross product to get the right vector.
right = up x look;
Figure 3 Representation of a particle billboarded about an arbitrary axis. The green vectors are up
vectors, the blue are look vectors, the red are right vectors, and the gold is the temporary
look vector. The top left object is the particle and the bottom right is the camera.
Now that we have legitimate up and right vectors, we can get back to calculating the final look vector.
look = right x up;
Not so bad after all, we can now use these vectors to calculate the billboard matrix. Read on to see how.
Ok, youve found multiple ways to create a local coordinate system for a billboard. Now youre wondering how to make use of them. Ive saved that until now because they all follow the same code to make the billboard a billboard. Keep in mind that all our billboard vectors are normalized, so we can use the rule of orthogonal matrices to create a rotation matrix for the billboard. The whole orthogonal matrix explanation is outside the scope of this document, so just implement as I show you and it will work :) The rules state that in order to transform the local coordinates into the global coordinates we must multiply by this vector.
[r1 u1 l1 px] [r2 u2 l2 py] [r3 u3 l3 pz] [0 0 0 1]
The vectors are (r)ight, (u)p, (l)ook; and the values are the offsets in the vector (1, 2, 3). The right, up, and look vectors are as you guessed, the values we calculated earlier. This matrix will transform the billboard coordinate system into the global coordinate system. Now you can multiply by this in the rendering stage and your billboard will be properly facing the camera. If you havent figured it out already, the p* values are the world position of the billboard (px, py, pz).
Make sure you push the current model view matrix before multiplying by this transformation matrix and then pop the matrix after rendering the quad. If you dont, you will end up only having the first billboard work as the billboard matrices will accumulate in the model view matrix.
Lastly, we need to know how to render a billboard. For all the above calculations, we set the Y axis to the billboard up vector, and the X axis to the right vector. So the billboard is drawn along the XY plane facing down the +Z axis.
glBegin(GL_TRIANGLE_FAN); glVertex3f(10, -12, 0); glVertex3f(10, 12, 0); glVertex3f(-10, 12, 0); glVertex3f(-10, -12, 0); glEnd();
You can change the coordinate values for the billboard as needed. They dont need to be a square or rectangle either; just make sure all the points are on the same plane. Of course if the points dont lie on the XY plane the billboard wont work.
If your billboards arent in the XY plane, youll need to adjust the billboard matrix that is created so that the billboard look vector is the normal to the plane that the billboard is on. For instance, if you billboard is in the XZ plane, the normal for that plane is the +Y axis. Your billboard look vector now needs to be rotated into the +Y axis. The billboard up vector will be rotated into the +Z axis, and the right vector is the cross from look to up, which is the +X axis.
Download the code for this article: Billboard Demo