Billboards

From X-Plane SDK
Jump to: navigation, search

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.