Rotating a poly to face camera using dot product?

So - here’s what I want to do: I want to rotate a poly (ok, a bunch of them - particles) to always face the camera, but I want to do it purely using the dot product of the poly normal and the camera vector - ie I do not want to call glRotate, because when I have 10,000 particles, thats alot of calls to glRotate!

Here’s what I have so far…

1)calculate normal for poly - this is easy it’s always going to be 0,0,1 (ie my polys start off in the xy plane)
2) calculate camera vector - this is easy too - I can even normalize it so no both vectors are normalized
3) take the dot product (also not hard)
4) take the acos( ) of the dot product, this gives me the angle difference between the two vectors
5) ?? how do i use this to “rotate” my poly without actually using glRotate? ie I want to apply sin(angle) cos(angle) etc to each coord of each vertex, with the end result being that the poly is facing the camera, but I don’t know how?

(the reason I want to do it this way is because once I calculate what to mulitply the x,y,z of each vertex by to achieve the rotate, I only have to do that once for all my particles, instead of calling glRotate for each individual one!)

any help? Thanks!

JDM

In my particle engine, I use a variable called size, and a variable called position (center of particle), and this is how I do it (haven’t optimized my code yet though).

I use quads to represent particles, and because I only move my camera in the x-z-plane, I dont take care of the camera looking upwards/downwards, but the technique is the same.

1: Copy the position to all four vertices.
2: To each y-component, add/substract the size of the particle.
3: To each x-component, add/substract sine of the angle.
4: To each z-component, add/substract cosine of the angle.

I’ll post the code.

memcpy(v1,p->particles[i].pos,4sizeof(float));
memcpy(v2,p->particles[i].pos,4
sizeof(float));
memcpy(v3,p->particles[i].pos,4sizeof(float));
memcpy(v4,p->particles[i].pos,4
sizeof(float));
sin_size=p->particles[i].sizefsin(cam_ang);
cos_size=p->particles[i].size
fcos(cam_ang);

v1[0] -= sin_size;
v2[0] = v1[0];
v3[0] += sin_size;
v4[0] = v3[0];

v1[2] += cos_size;
v2[2] = v1[2];
v3[2] -= cos_size;
v4[2] = v3[2];

v1[1] -= p->particles[i].size;
v2[1] += p->particles[i].size;
v3[1] = v2[1];
v4[1] = v1[1];
glColor4fv(p->particles[i].col);

glTexCoord2f(0,0);
glVertex3fv(v1);
glTexCoord2f(0,1);
glVertex3fv(v2);
glTexCoord2f(1,1);
glVertex3fv(v3);
glTexCoord2f(1,0);
glVertex3fv(v4);

v1->v4 is an array of floats holding four floats to represent the vertex.

All i do before is using glTranslatef to place the particlesystem in worldspace. From there, each particle has it’s own position relative the systems origin.

Maybe you have to change sin and cos, or maybe invert the angle.

I’m confused - JDM, you seem to want to use the same billboarding rotation for all your particles, but surely each particle requires a different rotation to get it to face the camera? (Unless all particles are aligned along a single line-of-sight vector, but that’s not a common case…)

It’ll look OK if all particles are in roughly the same region of the screen, but if you’re up close or the particle system is big then they’ll be all over the screen and the single-rotation trick isn’t going to work.

Or? What am I missing?

[This message has been edited by MikeC (edited 06-09-2000).]

I’m using this technique for my particlesystem, and I have never experienced any visual problems due to the rotation. I have tried huge systems and closeups, but still it doesn’t look too bad. But as everything else, it’s just an approximation, and approximations isn’t perfect.

thanks!

yes - with my system I think that rotating all the particles by the same amount so that the normal is the same (well, opposite) the camera eye vector is a close enough approximation… I will try your code Bob, but since my camera has 4 degrees of rotational freedom I fear i will need to rotate around another axis in addition to Y, and that rotation will be harder because the Y rotation has already been applied…

will try…

JDM

My solution to this problem is to convert the current camera angles to a set of normalised view vectors ( forward, right, up ). From here, it is extremely easy to build a poly that is always facing the viewer. You only have to calculate the view axis once per frame for the particles you are rendering, though I’m guessing the result is less than 100% accurate at the edge of your FOV…but it’s barely noticeable, especially for moving particles. Finally, this solution seems to work quite well for viewing the sprite from any angle…so you don’t have to worry about weird viewing constraints.

Don’t know if this helps, but ah well.

[This message has been edited by El Jefe (edited 06-12-2000).]

El Jefe - ah - thanks! yes this is what I am trying to do exactly - but right now I only have it working for rotation on the Y axis of the particles … the hard part is that I am trying to draw the Polys with no glRotate calls… ie I am trying to do the rotation explicitly in the vertex declarations… here is a sample…

glVertex3f(particle[i]->x + particlesizecos(angley), particle[i]->y, particle[i]->z + sizesin(angley));

so angley is the angle difference between the Camera Vector projected onto the XZ plane and the particle normal(which is drawn in the XY plane, so has a normal of 0,0,1)

so that rotation is working - however, to tilt the particle vertically, ie rotate it around it’s X or Z axis is harder, because then all 3 verticies need to change… there has to be some way of doing it that I am missing (that still involves no glRotate) - obviously since I can use the same angle for all particles I can optimize out the cos() and sin() to happen only once… but I need to know what function I need to apply to my normalized view vectors that will give me new coords for my verticies…

thanks for the help!

jdm

I had problems a couple of days ago with getting the Angles to Vectors bit down, but with a few tips from some others on this board, I was able to massage the Euler angle rotation matrix to fit my needs.

If you want the code I used to do this, please e-mail me. I can also show how I generate the vertex coords for the oriented particle.

What you want to do is apply the rotation from the current modelview matrix to all your polygons, then translate them to the particle positions. This can be accomplished very cheaply, especially when you have a bunch of particles that are all the same size.

In pseudo-code:

Matrix rotation;
Vec3 v0 = rotation * (-1, -1, 0);
Vec3 v1 = rotation * ( 1, -1, 0);
Vec3 v2 = rotation * ( 1, 1, 0);
Vec3 v3 = rotation * (-1, 1, 0);
glBegin(GL_QUADS);
for (i = 0; i < N_PARTICLES; i++) {
glTexCoord2f(0, 0);
glVertex3f(particles[i].position + v0);
glTexCoord2f(1, 0);
glVertex3f(particles[i].position + v1);
glTexCoord2f(1, 1);
glVertex3f(particles[i].position + v2);
glTexCoord2f(0, 1);
glVertex3f(particles[i].position + v3);
}
glEnd();

If the size of particles varies, you’ll need to multiply v0, v1, v2, and v3 by each particle’s size (particles[i].position + v3 * size). This solution is a lot like Bob’s, except it handles arbitrary rotations, not just y-axis ones. One very important thing: you definitely want compute the coordinates of the rotated polygons yourself–using OpenGL’s matrix stack results in one matrix state change per particle, which will absolutely slay your performance if you have a bunch of particles.

–Chris

Check out my submission to the OpenGL Challenge (http://oglchallenge.dhs.org) called Nissa’s Glitter for an example of using billboarded polygons to render a polygon. The relevant code is in the function Render() in render.cpp.

–Chris