BillBoarding (Particles..)

Hello.
I’ve implemented a 3D particles fountain.
I have some problem to find out how set the particles face to the camera. My particles are build with QUADS. I’ve read some tutorials on this subject but they always refers to a trick about right/up vector inside the ModelView matrix ?

First, I will give you the position of my camera and so why I need to get a spherical BillBoard effect.

Coord of my camera :
CamPos.vX = 0.0;
CamPos.vY = 80.0;
CamPos.vZ = 180.0;
CamLook.vX = 0.0;
CamLook.vY = 20.0;
CamLook.vZ = 0.0;

Set my camera in the 3D world :
gluLookAt( CamPos.vX, CamPos.vY, CamPos.vZ,
CamLook.vX, CamLook.vY,CamLook.vZ,
0.0, 1.0, 0.0 );

Move the camera around the fountain :
CamPos.vX := sin(DegresRot) * 160.0;
CamPos.vZ := cos(DegresRot) * 160.0;

Call the fountain function :
glPushMatrix();
glDepthMask( GL_FALSE );
glEnable(GL_BLEND);
AnimParticles;
glDisable(GL_BLEND);
glDepthMask( GL_TRUE );
glPopMatrix();

In the AnimParticles, I just compute the news coord of the particles and I draw the QUADS that reprensent it. (I don’t use any Translation or Rotations, I draw the particles right there, so At the current position).

There is my two problems :

First, is that I don’t want the camera rotation affect the fountain/particles, I just want to rotate around it…

Secondly, the billboarding effects

A BIG Thanks.
Martin

For each frame, do this:

GLfloat mat[4*4];

// Get modelview matrix. We will only use the upper left 3x3 part of
// the matrix, which represents the rotation.
glGetFloatv( GL_MODELVIEW_MATRIX, mat );

// Although not obvious, the following six lines represent two matrix/
// vector multiplications. The matrix is the inverse 3x3 rotation
// matrix (i.e. the transpose of the same matrix), and the two vectors
// represent the lower left corner of the quad, PARTICLE_SIZE/2 *
// (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0).
// The upper left/right corners of the quad is always the negative of
// the opposite corners (regardless of rotation).
quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]);
quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]);
quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]);
quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]);
quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]);
quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]);

For every particle n, do this:

glColor4f( ... );
glTexCoord2f( 0.0f, 0.0f );
glVertex3f( particle[n].x + quad_lower_left.x,
            particle[n].y + quad_lower_left.y,
            particle[n].z + quad_lower_left.z );
glTexCoord2f( 1.0f, 0.0f );
glVertex3f( particle[n].x + quad_lower_right.x,
            particle[n].y + quad_lower_right.y,
            particle[n].z + quad_lower_right.z );
glTexCoord2f( 1.0f, 1.0f );
glVertex3f( particle[n].x - quad_lower_left.x,
            particle[n].y - quad_lower_left.y,
            particle[n].z - quad_lower_left.z );
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( particle[n].x - quad_lower_right.x,
            particle[n].y - quad_lower_right.y,
            particle[n].z - quad_lower_right.z );

Hope that helps. What we do here is basically:

  1. Create a quad around origo that is always facing the screen (a.k.a. billboarding)
  2. For each particle, translate the quad to the particle position (note: we do translation in software, since it would be too much overhead to do it with glTranslate)

Effects:

  1. All particles face the viwer
  2. We are independent of the modelview matrix
  3. We do not need to modify the modelview matrix (no push/pop required)
  4. The billboarding procedure only has to be done once / frame => fast!

[This message has been edited by marcus256 (edited 12-17-2001).]