# Billboards...

**URL:** <https://community.khronos.org/t/billboards/43714>\
**Category:** OpenGL: Advanced Coding\
**Created:** [November 23, 2000, 5:43pm UTC](https://community.khronos.org/t/billboards/43714 "2000-11-23T17:43:00Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Fiante\_Endurcie](https://community.khronos.org/letter_avatar_proxy/v4/letter/f/a87d85/32.png) [@Fiante\_Endurcie](https://community.khronos.org/u/Fiante_Endurcie)\
**Post date:** [November 23, 2000, 5:43pm UTC](https://community.khronos.org/t/billboards/43714/1 "2000-11-23T17:43:00Z")

</div>

Sorry to nag you guys with this question as you may find it trivial but I have failed over and over again while trying to get my billboards going and I really really need them to do nefty special effects as it seems that they are used so often in great games for different tasks (particule systems, trees, lights etc)

What I have:  
The eye position (x,y,z), the up vector for the eye.  
I know how to retrieve the modelview and the projection matrix.

What I want:  
After calling glLookAt and glPerspective I want to be able to draw spherical and cylindrical billboards. I want these to drawn at a given spot. By that I mean after some calls to gltranslate and glrotate I want to be able to do math equations giving me the theta needed to turn my 2 triangles so that it is flat to the camera.

I have looked in the message board alot of time and over the internet and I have not found what I was looking for. There was some code but it seemed that it didn’t fit my needs.

I have tried to implement Sisgraph97 section 5.7 only to fail miserably. The code is the following on that page:

Veye = [M] [0 0 -1 0]

where M is the modelview at a given time and where [M] -1 is the inverse to that matrix (I

think). Then:

cos Theta = Veye DOT Vfront = val1  
sin Theta = Veye DOT Vright = val2  
where  
vfront = [0 0 1]  
vright = [1 0 0]

So the rotation along Y is if i am not mistaken:  
sin theta / cos theta = val2 / val1  
= \> tetha = atan2 (val2 / val1)

It doesn’t work.  
I know the basic algebra:  
a DOT b = ax \* bx + ay \* by+ az \* bz = angle between 2 pts

a CROSS b = [aybz-azby bxaz-axbz axby-aybx] = An ortogonal vector between a and b (thumbs rule)

I have tried other things such as multiplying [0 0 1] and [1 0 0] by the modelview then using the same atan2 thing with the view direction only to fail again and again.  
I am seeking the solution I admit defeat (and alot of wasted time) please help me!

[This message has been edited by Fiante Endurcie (edited 11-23-2000).]

---

<div class="post-metadata">

**Author:** ![zed](https://community.khronos.org/user_avatar/community.khronos.org/zed/32/8_2.png) [@zed](https://community.khronos.org/u/zed)\
**Post date:** [November 23, 2000, 11:53pm UTC](https://community.khronos.org/t/billboards/43714/2 "2000-11-23T23:53:00Z")

</div>

a nice billboarding method is one nate miller stuck on his site recently [http://nate.scuzzy.net/](http://nate.scuzzy.net/)

---

<div class="post-metadata">

**Author:** ![DFrey](https://community.khronos.org/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@DFrey](https://community.khronos.org/u/DFrey)\
**Post date:** [November 24, 2000, 5:58am UTC](https://community.khronos.org/t/billboards/43714/3 "2000-11-24T05:58:00Z")

</div>

I do all my billboards in eye-space so no turning is necessary. (Well, at least the billboards don’t need turning, everything else does to line up with my eye-space.)

---

<div class="post-metadata">

**Author:** ![Fiante\_Endurcie](https://community.khronos.org/letter_avatar_proxy/v4/letter/f/a87d85/32.png) [@Fiante\_Endurcie](https://community.khronos.org/u/Fiante_Endurcie)\
**Post date:** [November 24, 2000, 7:26pm UTC](https://community.khronos.org/t/billboards/43714/4 "2000-11-24T19:26:00Z")

</div>

The problem with Nate’s Miller example is that his camera is fix. If you call gluLookAt(something) you will see that his billboard donesn’t face the camera but only a fixed point in the modelview. While this is fun to do a simple effect it doesn’t work in a game where I want a billboard to be scaled appropriatly depending to the distance to the eye and to always face the moving camera.

Do I have to take the perspective into acount anyway and  
does my object need to point at the coordinates of the camera in modelview or does the paremeter of the projection matrix have to be taken into account. I don’t know and am mistified quite frankly!

---

<div class="post-metadata">

**Author:** ![Moz](https://community.khronos.org/letter_avatar_proxy/v4/letter/m/48db29/32.png) [@Moz](https://community.khronos.org/u/Moz)\
**Post date:** [November 25, 2000, 2:11am UTC](https://community.khronos.org/t/billboards/43714/5 "2000-11-25T02:11:00Z")

</div>

I’ve got an idea, but that’s just an idea, I’ve never tried it.  
Try to transform the world coordinates of the point(s) where you want your billboard(s) to be to window coordinates with gluProject.  
Then change the projection matrix to an orthogonal projection and display your billboard(s) in 2D, facing the camera. You’ll have to scale the billboard(s) manually depending on the Z window coordinate of its position.  
Afterwards, you can return to your perspective projection.

Moz

---

<div class="post-metadata">

**Author:** ![msteinberg](https://community.khronos.org/letter_avatar_proxy/v4/letter/m/e9a140/32.png) [@msteinberg](https://community.khronos.org/u/msteinberg)\
**Post date:** [November 25, 2000, 3:08am UTC](https://community.khronos.org/t/billboards/43714/6 "2000-11-25T03:08:00Z")

</div>

If you look somewhere, you’ll have an right-axis-vector and an up-axis-vector. The billboard simply has to lay on a plane that is parallel to the plane of these two axises. So you can get the coordinates of the vertices of a billboard quad through linear combination of these vectors and the place-vector where the billboard should be positioned.

---

<div class="post-metadata">

**Author:** ![msteinberg](https://community.khronos.org/letter_avatar_proxy/v4/letter/m/e9a140/32.png) [@msteinberg](https://community.khronos.org/u/msteinberg)\
**Post date:** [November 25, 2000, 3:12am UTC](https://community.khronos.org/t/billboards/43714/7 "2000-11-25T03:12:00Z")

</div>

Oh, wait, that sounds somehow strange…

Uhmmm, another try, get the vector that moves the billboard to the viewpoint. That vector is orthogonal (is the normal) to the plane where the billboard should lay on.

---

<div class="post-metadata">

**Author:** ![zed](https://community.khronos.org/user_avatar/community.khronos.org/zed/32/8_2.png) [@zed](https://community.khronos.org/u/zed)\
**Post date:** [November 25, 2000, 10:20am UTC](https://community.khronos.org/t/billboards/43714/8 "2000-11-25T10:20:00Z")

</div>

> Originally posted by Fiante Endurcie:  
> [b]The problem with Nate’s Miller example is that his camera is fix. If you call gluLookAt(something) you will see that his billboard donesn’t face the camera but only a fixed point in the modelview. While this is fun to do a simple effect it doesn’t work in a game where I want a billboard to be scaled appropriatly depending to the distance to the eye and to always face the moving camera.  
> B]

yes it does you have to first position the ‘camera’ and then use the code to work out the billboard

---

<div class="post-metadata">

**Author:** ![jammer](https://community.khronos.org/letter_avatar_proxy/v4/letter/j/df705f/32.png) [@jammer](https://community.khronos.org/u/jammer)\
**Post date:** [November 25, 2000, 7:17pm UTC](https://community.khronos.org/t/billboards/43714/9 "2000-11-25T19:17:00Z")

</div>

Hello,  
well, I’m sure there are many methods, but here’s the one I use, which works very well:  
First, reset the camera to be at position 0,0,0, facing in the -z axis direction ( This is usually you’re starting mode, so a PopMatrix and a PushMatrix should do the trick). Second, rotate according to the direction of the camera in the following order: z axis, x axis, y axis. Now, translate using the position of the particle minus the position of the camera. Finally, rotate again using the direction of the camera, but this time with the values and the order reversed: -y axis, -x axis, -z axis. Now, you draw the particle along the x axis, facing positive z, centered at 0,0,0.  
Here’s a sample piece of code:

// set camera to 0,0,0 facing -z. Usually: PopMatrix(); PushMatrix();  
glRotatef(camera.zdir, 0, 0, 1);  
glRotatef(camera.xdir, 1, 0, 0);  
glRotatef(camera.ydir, 0, 1, 0);  
glTranslatef(particle.x - cam.x, particle.y - cam.y, particle.z - cam.z);  
glRotatef(-cam.ydir, 0, 1, 0);  
glRotatef(-cam.xdir, 1, 0, 0);  
glRotatef(-cam.zdir, 0, 0, 1);  
glBegin(GL\_TRIANGLE\_STRIP);  
glVertex3f( -1, 1, 0);  
glVertex3f( -1, -1, 0);  
glVertex3f( 1, 1, 0);  
glVertex3f( 1, -1, 0);  
glEnd();

See if that works.

---

<div class="post-metadata">

**Author:** ![jammer](https://community.khronos.org/letter_avatar_proxy/v4/letter/j/df705f/32.png) [@jammer](https://community.khronos.org/u/jammer)\
**Post date:** [November 25, 2000, 7:38pm UTC](https://community.khronos.org/t/billboards/43714/10 "2000-11-25T19:38:00Z")

</div>

oops, on the glTranslatef and the second set of rotations, it’s supposed to be camera, not cam. I changed it from my original code to be easier to read. Doh! Well, I’m sure you guys figured that out anyway.

---

<div class="post-metadata">

**Author:** ![Fiante\_Endurcie](https://community.khronos.org/letter_avatar_proxy/v4/letter/f/a87d85/32.png) [@Fiante\_Endurcie](https://community.khronos.org/u/Fiante_Endurcie)\
**Post date:** [November 26, 2000, 6:21am UTC](https://community.khronos.org/t/billboards/43714/11 "2000-11-26T06:21:00Z")

</div>

Here is the code I got working for the cylindrical billboards. Any comments (other then my functions and data names are a bit whacky) ?

void billboardy (Matrix4x4 \* transform) {  
if (!transform)  
{  
Matrix4x4 modelview;  
glGetFloatv(GL\_MODELVIEW\_MATRIX , modelview);  
transform= &modelview;  
}

```
Vector3d vfront (0,0,-1), vright (-1,0,0);
vfront.multAlpha0 (*transform); //multAlpha0 =&gt; don't use the translation components
vright.multAlpha0 (*transform);

float val = view.Dot (vfront);
float val2 = view.Dot (vright);

float angle = (float) atan2 (val2, val);

glRotatef ((angle*180.0f / pi), 0, 1, 0);

```

//draw here  
}

I am now trying to get the spherical billboards working. Any pointers anyone?

---

<div class="post-metadata">

**Author:** ![Eric](https://community.khronos.org/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@Eric](https://community.khronos.org/u/Eric)\
**Post date:** [November 26, 2000, 11:01pm UTC](https://community.khronos.org/t/billboards/43714/12 "2000-11-26T23:01:00Z")

</div>

That’s my code for both billboards.

* * *

void HGL\_BillBoard\_Cylindrical\_Mode(HGL\_Vector3Df vNormal,HGL\_Vector3Df vUp)  
{

GLfloat fModelViewMatrix[16];

glGetFloatv(GL\_MODELVIEW\_MATRIX, fModelViewMatrix);  
HGL\_Matrix\_4x4f ModelViewMatrix(fModelViewMatrix);  
HGL\_Matrix\_4x4f InvModelViewMatrix=ModelViewMatrix.Invert();  
HGL\_Vector3Df vOriginalView(0,0,1);  
HGL\_Vector3Df vOriginalViewSide(1,0,0);  
HGL\_Vector3Df vView=InvModelViewMatrix\*vOriginalView;  
vView.Normalize();  
HGL\_Vector3Df vOrtho=vView.CrossProduct(vUp);  
vOrtho.Normalize();  
vView=vUp.CrossProduct(vOrtho);

// Dot Product to see if flipping needed //  
float fDot=vOriginalViewSide.DotProduct(vView);

// Rotation //  
HGL\_Vector3Df vAxis=vNormal.CrossProduct(vView);  
float cAngle1=vNormal.DotProduct(vView);  
float sAngle1=vAxis.Norm();  
if (fDot\>0)  
sAngle1=-sAngle1;  
vAxis.Normalize();  
HGL\_Matrix\_4x4f R;  
R.LoadRotate(cAngle1,sAngle1,vUp.U,vUp.V,vUp.W);  
glMultMatrixf(R.Matrix);

}

void HGL\_BillBoard\_Spherical\_Mode(HGL\_Vector3Df vNormal,HGL\_Vector3Df vUp)  
{

GLfloat fModelViewMatrix[16];

glGetFloatv(GL\_MODELVIEW\_MATRIX, fModelViewMatrix);  
HGL\_Matrix\_4x4f ModelViewMatrix(fModelViewMatrix);  
HGL\_Matrix\_4x4f InvModelViewMatrix=ModelViewMatrix.Invert();  
HGL\_Vector3Df vOriginalView(0,0,1);  
HGL\_Vector3Df vView=InvModelViewMatrix_vOriginalView;  
HGL\_Vector3Df vOriginalViewSide(1,0,0);  
HGL\_Vector3Df vOriginalViewUp(0,1,0);  
HGL\_Vector3Df vViewUp=InvModelViewMatrix_vOriginalViewUp;  
vView.Normalize();  
vViewUp.Normalize();  
// First Rotation //  
HGL\_Vector3Df vAxis=vNormal.CrossProduct(vView);  
float cAngle1=vNormal.DotProduct(vView);  
float sAngle1=vAxis.Norm();  
vAxis.Normalize();  
HGL\_Matrix\_4x4f R,R1,R2;  
R1.LoadRotate(cAngle1,sAngle1,vAxis.U,vAxis.V,vAxis.W);  
// Second Rotation //  
HGL\_Vector3Df vTransformedUp=R1_vUp;  
HGL\_Vector3Df vUpAxis=vTransformedUp.CrossProduct(vViewUp);  
float cAngle2=vTransformedUp.DotProduct(vViewUp);  
float sAngle2=vUpAxis.Norm();  
R2.LoadRotate(cAngle2,sAngle2,vUpAxis.U,vUpAxis.V,vUpAxis.W);  
// Whole Rotation //  
R=R2_R1;  
glMultMatrixf(R.Matrix);

}

template \<class T\> void HGL\_Matrix\_4x4\<T\>::LoadRotate(T cAngle,T sAngle,T X,T Y,T Z)  
{

HGL\_Vector3D\<T\> V(X,Y,Z);  
V.Normalize();  
Matrix[0]=V.U_V.U+cAngle_(1-V.U_V.U)+sAngle_0;  
Matrix[1]=V.V_V.U+cAngle_(0-V.V_V.U)+sAngle_V.W;  
Matrix[2]=V.W_V.U+cAngle_(0-V.W_V.U)+sAngle_-V.V;  
Matrix[3]=0;  
Matrix[4]=V.U_V.V+cAngle_(0-V.U_V.V)+sAngle_-V.W;  
Matrix[5]=V.V_V.V+cAngle_(1-V.V_V.V)+sAngle_0;  
Matrix[6]=V.W_V.V+cAngle_(0-V.W_V.V)+sAngle_V.U;  
Matrix[7]=0;  
Matrix[8]=V.U_V.W+cAngle_(0-V.U_V.W)+sAngle_V.V;  
Matrix[9]=V.V_V.W+cAngle_(0-V.V_V.W)+sAngle_-V.U;  
Matrix[10]=V.W_V.W+cAngle_(1-V.W_V.W)+sAngle_0;  
Matrix[11]=0;  
Matrix[12]=0;  
Matrix[13]=0;  
Matrix[14]=0;  
Matrix[15]=1;

}

template \<class T\> HGL\_Point3D\<T\> HGL\_Matrix\_4x4\<T\>::operator\*(HGL\_Point3D\<T\>& Point)  
{

T rX,rY,rZ;

rX=Matrix[0]\*Point.X+Matrix[4]\*Point.Y+Matrix[8]\*Point.Z+Matrix[12];  
rY=Matrix[1]\*Point.X+Matrix[5]\*Point.Y+Matrix[9]\*Point.Z+Matrix[13];  
rZ=Matrix[2]\*Point.X+Matrix[6]\*Point.Y+Matrix[10]\*Point.Z+Matrix[14];  
return(HGL\_Point3D\<T\>(rX,rY,rZ));

}

template \<class T\> HGL\_Vector3D\<T\> HGL\_Matrix\_4x4\<T\>::operator\*(HGL\_Vector3D\<T\>& Vector)  
{

T rU,rV,rW;

rU=Matrix[0]\*Vector.U+Matrix[4]\*Vector.V+Matrix[8]\*Vector.W;  
rV=Matrix[1]\*Vector.U+Matrix[5]\*Vector.V+Matrix[9]\*Vector.W;  
rW=Matrix[2]\*Vector.U+Matrix[6]\*Vector.V+Matrix[10]\*Vector.W;  
return(HGL\_Vector3D\<T\>(rU,rV,rW));

}

* * *

I haven’t cleaned it but it works well.

Regards.

Eric

---

<div class="post-metadata">

**Author:** ![msteinberg](https://community.khronos.org/letter_avatar_proxy/v4/letter/m/e9a140/32.png) [@msteinberg](https://community.khronos.org/u/msteinberg)\
**Post date:** [November 27, 2000, 5:20am UTC](https://community.khronos.org/t/billboards/43714/13 "2000-11-27T05:20:00Z")

</div>

Oh man, C++ is so complicated!!! It also looks ugly… Sorry guys…

---

<div class="post-metadata">

**Author:** ![Kilam\_Malik](https://community.khronos.org/letter_avatar_proxy/v4/letter/k/b9e5f3/32.png) [@Kilam\_Malik](https://community.khronos.org/u/Kilam_Malik)\
**Post date:** [November 27, 2000, 1:08pm UTC](https://community.khronos.org/t/billboards/43714/14 "2000-11-27T13:08:00Z")

</div>

To do the same in pure C, it would look really ugly. When you get used to C++, you love it (even templates \>;-)).

---

<div class="post-metadata">

**Author:** ![Deiussum](https://community.khronos.org/letter_avatar_proxy/v4/letter/d/c89c15/32.png) [@Deiussum](https://community.khronos.org/u/Deiussum)\
**Post date:** [November 27, 2000, 1:44pm UTC](https://community.khronos.org/t/billboards/43714/15 "2000-11-27T13:44:00Z")

</div>

> Originally posted by Michael Steinberg:  
> Oh man, C++ is so complicated!!! It also looks ugly… Sorry guys…

I don’t think I can talk to you anymore. ![](http://www.opengl.org/discussion_boards/ubb/smile.gif)

---

<div class="post-metadata">

**Author:** ![Fiante\_Endurcie](https://community.khronos.org/letter_avatar_proxy/v4/letter/f/a87d85/32.png) [@Fiante\_Endurcie](https://community.khronos.org/u/Fiante_Endurcie)\
**Post date:** [November 28, 2000, 2:09pm UTC](https://community.khronos.org/t/billboards/43714/16 "2000-11-28T14:09:00Z")

</div>

Thanks for your help you guys. I will go with jammer’s code.  
By the way jammer do you have a cylindrical version of your code (the code you posted is for spherical billboards) ?

---

<div class="post-metadata">

**Author:** ![msteinberg](https://community.khronos.org/letter_avatar_proxy/v4/letter/m/e9a140/32.png) [@msteinberg](https://community.khronos.org/u/msteinberg)\
**Post date:** [November 29, 2000, 7:52am UTC](https://community.khronos.org/t/billboards/43714/17 "2000-11-29T07:52:00Z")

</div>

If I look at that overhead (maybe it is no pverhead) it should was performance, no? I’m probably wrong with that.

---

<div class="post-metadata">

**Author:** ![jammer](https://community.khronos.org/letter_avatar_proxy/v4/letter/j/df705f/32.png) [@jammer](https://community.khronos.org/u/jammer)\
**Post date:** [November 30, 2000, 12:21pm UTC](https://community.khronos.org/t/billboards/43714/18 "2000-11-30T12:21:00Z")

</div>

The billboard will always face the camera, regardless of your direction. I assume that’s what you mean by spherical, so yes, it’s spherical. By cylindrical, do you mean that it will face you on certain angles, but will act like a regular polygon on others ( what many games do to produce grass, vines, wires, etc )? If so, then I’m not completely sure how to do it. I haven’t experimented with that effect yet, but I might in the future.

By the way, if you try my method and it acts funky, try putting the -axis rotations first, and the regular rotations last. This isn’t somehting that should come up or anything, just something to keep in mind.
