• Advertisement
Sign in to follow this  

Screen-aligned Billboarding, Need help.

This topic is 1766 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

THIS HAS BEEN SOLVED.  Feel free to let this thread die, but I welcome any feedback.


Hello all,


I am trying to do screen-aligned billboarding of some text labels, and I am having some trouble.  The following is my code for calculating the billboard matrix:

// Up vector from view matrix
CEVector3 up = CEVector3Normalize(CEVector3Make(viewMatrix.m10, viewMatrix.m11, viewMatrix.m12));
// Normal vector from near plane
CEVector3 normal = [camera.viewFrustum planeAtIndex:NEAR].normal;
// Negate the normal vector
normal = CEVector3MultiplyScalar(normal, -1);
// Verify that up and normal are perpendicular.  If not, something is wrong.
double dot = CEVector3DotProduct(up, normal);
if (dot < 0.00001) {
        // Calculate the right vector
        CEVector3 right = CEVector3Normalize(CEVector3CrossProduct(up, normal));
        // Create billboard rotation matrix
        billboardMatrix = CEMatrix4Make(right.x, up.x, normal.x, 0,
                                        right.y, up.y, normal.y, 0,
                                        right.z, up.z, normal.z, 0,
                                        0, 0, 0, 1);



Then, to apply this matrix to a feature, I do the following.  


// All features are at position 0 on the z axis.
CEMatrix4 modelViewMatrix = CEMatrix4Translate(billboardMatrix, feature.position.x - cameraPosition.x, feature.position.y - cameraPosition.y, -cameraPosition.z);


I have tried also using the column vector of the view matrix instead of the row vector and transposing the billboard matrix, and all combinations, and nothing seems to produce the correct results.  


My view matrix does have some weird transformations like scaling and shearing, not typical of examples of I've seen with billboarding.  In fact, when I disable the scales and shears, the billboarding seems to work fine, but when I enable them again, it acts very very strange.  The labels do show up, but they come in from all directions as I move the scene, and most certainly are not billboarded.  


Can anyone spot my mistake? Any help would be most appreciated. Thank you.


EDIT - Update, I made the following changes:  I transpose the billboard matrix after construction, and changed my translation code to:

billboardMatrix.m30 = feature.position.x;
billboardMatrix.m31 = feature.position.y;
billboardMatrix.m32 = 0;
modelViewMatrix = CEMatrix4Multiply(inverseViewMatrix, billboardMatrix);


And this seems to produce billboarded text, as in the labels always face the camera, however, the labels are flush against the XY plane, rather than looking at the camera, so they are barely readable.  Still not sure how to fix this problem.


EDIT2 - I think I got it, by not normalizing the camera up vector, it seems to have fixed the issue.  It now appears to be properly billboarded.  I think the problem is my scale was being lost.  However, if anyone sees any errors in any of my math, please point it out, as I am certain that this is not perfect.  Thanks.

Edited by metsfan

Share this post

Link to post
Share on other sites

You have 3 choices to make this a bit more simple

1) build the matrix straight from the camera. This will always generally towards the camera, but for anything large you'll notice that it rotates relative to other objects as you rotate the camera, however it is good for things like text that you want to show up "ortho normal" to the camera anyway so they are legible.  They won't rotate as the camera translates, which can also be a nice property.

[ Camera.left, Camera.up, -Camera.at, obj.pos], as that will always have the same orientation as your camera and always be facing the opposite direction.


2) build the matrix using what is normally done with a library's "look at" matrix function. This will make your billboard behave like it is on a sphere centered at your camera, always facing the center.  They won't rotate when you rotate the camera, and won't be as good for text but better for particles.  They will however rotate as you translate your camera, so moving by one will make it seem to rotate around you.

at = normalize( camera.pos - obj.pos );

left = cross(camera.up, at)

up = cross(at, left)

"look at" matrix = [left, at, up, obj.pos]


3) if you want the object pinned on an axis (like a tree, that rotates on the Y axis only) then use technique 2, but use a constant for the "up" axis instead of calculating it (then ortho-normalize based on that axis instead of the 'at' like I showed).

Edited by KulSeran

Share this post

Link to post
Share on other sites

If it's supposed to completely face the camera, I see no need for special handling. Treat it like any other object and set the rotation part of the matrix to identity in the resulting modelview matrix.


Why? Because there is no camera, so after "moving everything the other way" you will always be at the origin and always look down negative z (by default at least). Ergo the rotation part is always identity and all you care about is the position.


In other words: why perform all those calculations, if you already know in advance what the result has to be? What you seem to be doing is to extract the cameras rotation matrix, then transpose (ie. invert it) and multiply them, just so they can cancel each other out and result in identity. That looks like more effort than


Vec4 pos = viewMatrix * Vec4(billboard. x, billboard.y, billboard.z, 1);

modelViewMatrix = {1,0,0,0,   0,1,0,0,  0,0,1,0,   pos.x, pos.y, pos.z, 1};

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement