• Register
RSS My Blogs

Billboarding with OpenGL

onionman Blog

Standard Billboards

So billboarding in games development was something that always used to frighten me. I understood you were supposed to make an object always face the screen, but I didn't know an easy way to do that. I mean, we're you supposed to somehow calculate all the rotations needed by glRotatef() to make a picture always face you?

Anyway, eventually I found a solution with some online help that made the whole thing really easy, and I couldn't find it anywhere else, so I just thought I'd share.

Basically, you just take the current rotation matrix and invert it. Pretty simple! So here's some sample code to do that.

	GLfloat modelview[16];
	GLfloat tempModelView[16];
	glGetFloatv( GL_MODELVIEW_MATRIX, modelview );
	glGetFloatv( GL_MODELVIEW_MATRIX, tempModelView );
	
	modelview[0] = tempModelView[0];
	modelview[1] = tempModelView[4];
	modelview[2] = tempModelView[8];
	modelview[3] = 0.f;

	modelview[4] = tempModelView[1];
	modelview[5] = tempModelView[5];
	modelview[6] = tempModelView[9];
	modelview[7] = 0.f;

	modelview[8] = tempModelView[2];
	modelview[9] = tempModelView[6];
	modelview[10] = tempModelView[10];
	modelview[11] = 0.f;

//if you'd like, plug the position of the object into the transformation matrix, here I'm drawing a sun
	modelview[12] = sunPosition.position[0];
	modelview[13] = sunPosition.position[1];
	modelview[14] = sunPosition.position[2];
	modelview[15] = 1.f;

	glPushMatrix();
	glMultMatrixf(modelview);

	renderFlare(0.8f,0.8f,0.6f,1.f,5.f); //render the billboard

	glPopMatrix();

Semi-Billboards: Lasers

So a friend also asked me how I drew the lasers in our upcoming game Ensign 1. These really aren't anything special, and still need some work. Still, the basic idea is that these objects should be drawn facing the direction they are traveling, but their up vector should be pointing into the line of site of the viewer. Iunno if I explained that right, but anyway, here's the code I used to do it.
Basically you generate the forward, up, and right vectors for this object. And you need to ensure that the up vector is completely orthogonal to the forward vector.

glDepthMask(GL_FALSE);
Vector up,forward,right;
	
forward = lasers[index].velocity;
forward = forward*6.f;

up = lasers[index].position - parentModel->position;
up -= forward * forward.dot(forward,up); //ensure up vector is orthogonal to forward vector
up.normalize();

right = up.cross(forward,up);
right.normalize();
right = right*1.f;

GLfloat modelView[16];

modelView[0] = right[0];
modelView[1] = right[1];
modelView[2] = right[2];
modelView[3] = 0.f;

modelView[4] = up[0];
modelView[5] = up[1];
modelView[6] = up[2];
modelView[7] = 0.f;

modelView[8] = forward[0];
modelView[9] = forward[1];
modelView[10] = forward[2];
modelView[11] = 0.f;

modelView[12] = lasers[index].position[0];
modelView[13] = lasers[index].position[1];
modelView[14] = lasers[index].position[2];
modelView[15] = 1.f;

glPushMatrix();
	glMultMatrixf(modelView);

	glEnable(GL_BLEND);
	lasers[index].Draw(viewerPosition);
	glDisable(GL_BLEND);
glPopMatrix();

glDepthMask(GL_TRUE);

Some more tricks would might be that, when the up vector here is very small, the laser might appear flat, you might actually purposely add some forward vector to it to give it some depth. I haven't tried this myself yet though.

Anyway, enjoy!