To construct a billboard, given a center point, the four points [0-3] of the billboard quad can be expressed as center + displacement[0-3]
For example:
displacement[0] = + basisX + basisY
displacement[1] = + basisX - basisY
displacement[2] = - basisX - basisY
displacement[3] = - basisX + basisY
The order will depend on which corner you want to start with and whether you want to go clockwise or not. As I generally turn off cull-face anyway, order doesn’t matter much. The texcoords will follow the same pattern as above within texture coord ranges, of course.
For “cheap” billboards, basisX is a scaled version of camera-right and basisY is a scaled version of camera-up. That makes the billboards draw parallel to the image plane, rather than rotate for each individual “at” vector, which is usually fine for me. Some people might mind the slight warping you see in billboards near the corners of the window.
For “cheap” trees, however, you want them to stand up straight, so you’d use the world “up” axis as basisY in that case, possibly with some gentle sway offset for a virtual wind.
[edit: you might also want to shift the math above to make the “center” of the tree at each tree’s base for proper swaying. In that case, the -basisY disappears and +basisY is replaced with +basisY*2. make sense?]
Now, for basisX, you have two main options: You can use the projection of the camera’s “right” vector on the groud plane. This will give you trees that are generally parallel to the image plane (at least on their X axis). The second method is better but a little slower: to take the “at” vector from the camera to each tree individually, cross it with the basisY and project that onto the ground plane, normalizing and scaling it too. The goal is to get a vector that’s parallel to the ground and perpendicular to the “at” vector.
So to sum up, whatever basis vectors you choose, those four combinations of basisX and basisY give you the four displacements for your corner points. The code can very easily fit in a tight-loop over your quads, using SSE if you have time.
If you use a VP, I suggest computing those four common displacements on the CPU and loading them into a VP constant table, so the VP code is simply
pos = center + displacement[i],
where ‘center’ and ‘i’ come in via vertex data. And the four displacements can be preloaded into vertex constant registers. (the Four Displacements keeps sounding like an old R&B band to me…)
In this case, it might be best to send in vertices of the form XYZi, so they’re 16 bytes each. Multiples of 16 or 32 bytes seem to fetch faster from AGP memory.
If you go with VP and want each tree rotated to the camera “at” vector, you’ll need to compute a new basisX for each vertex. You already have the center point passed in so all you need is the eye point passed into the VP (once, via constants) plus some more VP instructions for the extra math.
On the sort, I’d go with coarsely sorting whole objects first via the quadtree or a radix sort and then iterate the sorted list to compute an up-to-date index list for that frame. Sorting the indices directly sounds painful, since you have to do swaps in groups of four now.
Mixing the VP with the sort? Once enabled, loaded, and bound, the VP will simply work on each [new/uncached] vertex in the order specified in the index list you pass with glDrawElements. No magic there.
Avi
[This message has been edited by Cyranose (edited 10-30-2003).]