No project download is available. This is a code snippet and not a complete project.

This code calculates the offsets to add to a center point to draw a billboard, by calculating the orientation of the user’s screen (“eye space” in OpenGL terms) but returning the results in the OpenGL local coordinates that you have to use to draw.

The Code

// This routine returns up to 3 camera directions: which way is "right", "up" and which way is the camera pointing ("look") 
// in OpenGL coordinates.  In other words, this is which way the user's SCREEN is pointing in OpenGL "local" coordinates.
// (If the user is facing true north at the origin and is not rolled, these functiosn would be trivially easy because 
// right would be 1,0,0, up would be 0,1,0 and look would be 0,0,1.  (NOTE: the look vector points TO the user, not 
// FROM the user.)  
// To draw a billboard centered at C, you would use these coordinates:
// c-rgt+up---c+rgt+up
// |                 |
// |        C        |
// c-rgt-up---c+rgt-up
static void camera_directions(
						float * out_rgt,		// Any can be NULL
						float * out_up ,
						float * out_look)
	float m[16];

	// Roughly speaking, a modelview matrix is made up more or less like this:
	// [ EyeX_x EyeX_y EyeX_z    a
	//   EyeY_x EyeY_y EyeY_z    b
	//   EyeZ_x EyeZ_y EyeZ_z    c
	//   um don't look down here ]
	// where a, b, c are translations in _eye_ space.  (For this reason, a,b,c is not
	// the camera location - sorry!)

	if(out_rgt) {
		out_rgt[0] = m[0];
		out_rgt[1] = m[4];
		out_rgt[2] = m[8];
	if(out_up) {
		out_up[0] = m[1];
		out_up[1] = m[5];
		out_up[2] = m[9];
	if(out_look) {
		out_up[0] = m[2];
		out_up[1] = m[6];
		out_up[2] = m[10];

Sample Usage

How to draw the billboard? Something like this would work:

void draw_billboard(float x, float y, float z)
	float r[3], u[3];

Note that this is just an example; since camera_directions reads the GL matrices, you would want to call it only once per draw callback, not once per billboard!

Usage For “Look” Vectors

One possible usage of the look vector is to measure alignment between the camera and drawing and then fade. For example, to fade a prop disc you could take the dot product of the look vector and the normal vector of the prop disc – as the dot product becomes zero, fade the prop disc.

2 comments on “Billboards

  1. Hi. I’m using this code and I have an issue. It works well in most situations BUT if I zoom out the billboards are not seen anymore. If I zoom in the billboards are visible again. I have checked the values that glGetFloatv(GL_MODELVIEW_MATRIX, m) outputs and they are quite “strange”. Every draw callback they are changing a lot, while the camera isn’t changing (for instance, from the 3D cockpit, with the aircraft on ground and view aligned to front).
    Any help and/or explanation would be appreciated.

    1. To ilustrate the problem, these are the values for four draw callbacks in a row during a moment in which the billboard is not visible:
      EyeX_x EyeX_y EyeX_z a
      EyeY_x EyeY_y EyeY_z b
      EyeZ_x EyeZ_y EyeZ_z c

      1.000000 0.000000 0.000000 0.000000
      0.000000 -1.000000 0.000000 0.000000
      0.000000 0.000000 -1.000000 0.000000
      1.000000 0.000000 0.000000 0.000000
      0.000000 -1.000000 0.000000 0.000000
      0.000000 0.000000 -1.000000 0.000000
      0.748451 -0.547821 0.373782 0.000000
      0.021908 0.583728 0.811654 0.000000
      -0.662828 -0.599295 0.448893 0.000000
      -0.448395 -0.032651 -0.893239 0.000000
      -0.011219 0.999459 -0.030902 0.000000
      0.893765 -0.003835 -0.448519 0.000000
      -0.448395 -0.032651 -0.893239 0.000000
      -0.011219 0.999459 -0.030902 0.000000
      0.893765 -0.003835 -0.448519 0.000000

Leave a Reply

Your email address will not be published. Required fields are marked *

Please do not report bugs in the blog comments.
Only bugs reported via the X-Plane Bug Reporter are tracked.