Billboarding is the process of rotating a quad to face the camera so that no matter what the camera position, the quad is rotated to directly face the camera.

I've been fooling around with particle effects, and I was looking for some spherical billboard rotation code - but everything I found seemed to be tutorial style, and written for clarity instead of efficiency. All I wanted was to generate a 3x3 rotation matrix that I could apply to the quad vertices given a camera position and a particle pivot position. The pivot position is the center of the quad, with each of the 4 vertices in a different quadrant on the xy plane. I also wanted to avoid calling any trigonometric functions, and rely on simple pythagorean relationships. So, I tried to simplify the calculations necessary to orient a quad to face the camera, and after a little algebraic refactoring, I came up with the following function. It does need to calculate 3 square roots, but there are no trig functions or cross products. It references the java vecmath package for the Point3f, Vector3f and Matrix3f implementations, but not for anything really important (just vector normalize and dot product). For simplicity, I present it here as a static function that creates new objects instead of reusing members.

/** * Calculates a 3x3 rotation matrix used to orient a quad billboard to directly face the camera eye. * The camera eye and the point p about which the billboard should pivot should be in world co-ordinates. * When applying the rotation matrix, first translate the vertices about the pivot point to the origin, * transform the vertices with the matrix, and then translate the new vertices back to world space. * The rotation is a 360 degree rotation around the y axis, * combined with a +/- 90 degree rotation about the x axis (the tilt up or down). * The initial billboard position assumes it is parallel to the xy plane with the normal * vector pointing to (0,0,1). * This method uses no trig functions, but it does calculate 3 square roots. */publicstaticMatrix3fcalculateBillboardRotation(Point3feye, Point3fp) {// The view vector is the direction from the point to the camera eyeVector3fview = newVector3f(eye.x - p.x, eye.y - p.y, eye.z - p.z);

// The xzp vector has the y component set to zero and is a projection// of the view vector onto the xz plane.Vector3fxzp = newVector3f(view.x, 0, view.z);

// Once normalized, the components of the xzp vector will be direction cosines.// So, xzp.z contains the direction cosine of the angle between xzp and the z-axis,// and xzp.x contains the direction cosine of the angle between xzp and the x-axis.// Consider that since xzp.y is zero, then xzp.x and xzp.y are two sides// of a right triangle, and the magnitude of the xzp vector is the hypotenuse.// Let theta be the angle between xzp and the z-axis (which is also the// counter-clockwise rotation about the y axis that we want for our billboard).// Using standard trigonometric ratios, we know that: // cos(theta) = xzp.z / ||xzp||// We can remove the ||xzp|| (magnitude) since it equals 1 (normalized vector) // therefore, cos(theta) = xzp.z.// Using the same approach, the trigonometric ratio for sine, would be:// sin(theta) = xzp.x / ||xzp||// So, xzp.z and xzp.x are the exact sines and cosines we need for the// rotation about the y-axis, and we are done.xzp.normalize();

// We have the sines and cosines for the rotation about the y axis, now// we need to get the elevation (rotation about the x axis).// The dot product of the normalized view and xzp vectors will provide// the cosine of the angle between the two vectors.// This cosine is related to the angle of elevation above the xz plane.view.normalize();floatcosp = view.dot(xzp);

// We have the cosine, but for the rotation matrix we need the sine, as well.// The sine of the elevation angle can be derived from the cosine using the// trig identity: sine = sqrt( 1 - (cosine squared) )// The sign must be negated when the view vector is looking up.// (y > 0) (i.e. camera looking down)floatsinp = (float) Math.sqrt(1 - cosp * cosp) * (view.y > 0 ? -1 : 1);

// Prepopulate a 3x3 rotation matrix with the rotation around the y axis// and the rotation around the x axis. This is how the matrix would wind// up if we created a separate rotation matrix for the y axis rotation // and the x axis rotation and then multiplied them together. // This is quicker than actually doing a full matrix multiplication// because the lack of a z axis rotation makes a lot of terms become// zero and drop out.returnnewMatrix3f(xzp.z, xzp.x * sinp, xzp.x * cosp, 0, cosp, -sinp, -xzp.x, xzp.z * sinp, xzp.z * cosp); }

I agree, the cross product isn't nearly as expensive as sqrt() or acos(). Three sqrts per quad is definitely more than I would like, and upon further thought, I think I can eliminate one of them. Then it would be better than the two sqrt() plus two acos() calls that I found in some code in this tutorial: http://www.lighthouse3d.com/opengl/billboarding/index.php?billSphe but, hey, I am a newbie, so I have to start somewhere.

If I use a point near the center of the particles to get the vector to the camera eye, then I can calculate this matrix just once per frame instead of once per quad, with the drawback that some quads near the corners of the screen may look slightly askew. For particle effects that's probably good enough.

I am very interested in the quad orientation technique you mentioned. Have you, by any chance, got a link or some code you can paste here?

I mentioned in the last reply that I thought I could eliminate a sqrt(), and it was simple. I had used a trig identity to get a sine from a cosine, but the sine was sitting there in the normalized view vector the whole time. I just had to negate it.

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org