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];
glGetFloatv(GL_MODELVIEW_MATRIX, m);

// 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];
camera_directions(r,u,NULL);
glBegin(GL_LINE_LOOP);
glVertex3f(x-r[0]-u[0],y-r[1]-u[1],z-r[2]-u[2]);
glVertex3f(x+r[0]-u[0],y+r[1]-u[1],z+r[2]-u[2]);
glVertex3f(x+r[0]+u[0],y+r[1]+u[1],z+r[2]+u[2]);
glVertex3f(x-r[0]+u[0],y-r[1]+u[1],z-r[2]+u[2]);
glEnd();
}
```

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.

1. Carlos Palacio says:

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.
Regards.

1. Carlos Palacio says:

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

0
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
1.000000 0.000000 0.000000 0.000000
0.000000 -1.000000 0.000000 0.000000
0.000000 0.000000 -1.000000 0.000000
—-
2
0.748451 -0.547821 0.373782 0.000000
0.021908 0.583728 0.811654 0.000000
-0.662828 -0.599295 0.448893 0.000000
—-
3
-0.448395 -0.032651 -0.893239 0.000000
-0.011219 0.999459 -0.030902 0.000000
0.893765 -0.003835 -0.448519 0.000000
—-
4
-0.448395 -0.032651 -0.893239 0.000000
-0.011219 0.999459 -0.030902 0.000000
0.893765 -0.003835 -0.448519 0.000000
—-