Icon drawing in 3d

Hi

I’m drawing some 2d icons in 3d game using billboarding(they should always face the camera). They purpose is to sign specific places in the scene.
How can I keep icon(image ) sizes small and correct looking while drawing in 3d perspective projection? Is there any known relation between original icon size in pixels and the size to to be given in 3d metric space?

Thanks

try:


You have:
vec3 IconPos; // where the icon is
mat4 mvp; // model-view-projection matrix
float invWidth = 1.0/640; 
float invHeight= 1.0/480;
int iconSize=32; // if you want to see it always 32x32px big
//-----------------
vec4 clip = mvp * vec4(IconPos,1.0);
float dx = iconSize * invWidth * 0.5 * clip.w;
float dy = iconSize * invHeight * 0.5 * clip.w;


vec4 vout[4];
vout[0] = vec4(clip.x - dx, clip.y + dy, clip.z,clip.w);
vout[1] = vec4(clip.x - dx, clip.y - dy, clip.z,clip.w);
vout[2] = vec4(clip.x + dx, clip.y - dy, clip.z,clip.w);
vout[3] = vec4(clip.x + dx, clip.y + dy, clip.z,clip.w);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glBegin(GL_QUADS);
	glTexCoord2f(0,0);	glVertex4fv(&vout[0].x);
	glTexCoord2f(0,1);	glVertex4fv(&vout[1].x);
	glTexCoord2f(1,1);	glVertex4fv(&vout[2].x);
	glTexCoord2f(1,0);	glVertex4fv(&vout[3].x);
glEnd();
	

@llian,
I tried the code you posted and it works very, very well. :eek:

How did you ever figure out that:


vout[0] = vec4(clip.x - dx, clip.y + dy, clip.z,clip.w);
vout[1] = vec4(clip.x - dx, clip.y - dy, clip.z,clip.w);
vout[2] = vec4(clip.x + dx, clip.y - dy, clip.z,clip.w);
vout[3] = vec4(clip.x + dx, clip.y + dy, clip.z,clip.w);

would ever work?

I’m guessing he employed math :wink: All he’s doing is computing positions that will effectively reverse the perspective projection, thus keeping it at the correct size.

I figured the 4 vertices should have the same z and w, and backtraced how to “unproject” xy.

I can see you were unprojecting the icon position into clip space, but the next step you took was a stroke of genius in my opinion as it’s not immediately obvious to me that the key to this technique is dx * clip.w to ‘perspectively’ correct the icon size.

float dx = iconSize * invWidth * 0.5 * clip.w;
float dy = iconSize * invHeight * 0.5 * clip.w;

I suppose if you figure that the next step in the FF pipeline is to perform a perspective divide with a computed clip-space w (just as you did), then it all makes sense as you have just reversed the projection.

Anyway, well done!

Yes, MANY THANKS to Ilian. Sorry for late update. It solved my problem and seems like I’ll use this approach a lot.

Hi
Sorry for bringing it up again.
But now I copied the code to another project where my metric space is relatively large[-2500,2500] and when I do rendering it doesnt work anymore. I can’t see the icons anymore.
It looks like clip vector values are the problem.

Please take a look at my code:



GLfloat matProj[16];
GLfloat matModelProj[16];
float InvWidth = 1.0/winWidth;
float InvHeight= 1.0/winHeight;
float vClip[4],vPos[4] = {icon.x,icon.y,icon.fz,1.0f};

glBindTexture(GL_TEXTURE_2D, icon.TexID);
glEnable(GL_TEXTURE_2D);				 
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);	 
glEnable(GL_BLEND);

 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
 glPushMatrix();


 glGetFloatv(GL_PROJECTION_MATRIX, matProj);
 glMultMatrixf(matProj);
 glGetFloatv(GL_MODELVIEW_MATRIX,matModelProj);

 //multiply modelview-proj matrix with position
 Matrix4MultiplyByVector(matModelProj,vPos,vClip);  
 float dx = (float)icon.SizeX * (float)winWidth *0.5f * vClip[3];
 float dy = (float)icon.SizeY * (float)winHeight *0.5f * vClip[3];

 float vScr1[4] = {vClip[0] - dx, vClip[1] + dy, vClip[2],vClip[3]};
 float vScr2[4] = {vClip[0] - dx, vClip[1] - dy, vClip[2],vClip[3]};
 float vScr3[4] = {vClip[0] + dx, vClip[1] - dy, vClip[2],vClip[3]};
 float vScr4[4] = {vClip[0] + dx, vClip[1] + dy, vClip[2],vClip[3]};


 glPopMatrix();
 glBegin(GL_QUADS);
        glTexCoord2f(0,0);	glVertex4fv(vScr1);
	glTexCoord2f(0,1);	glVertex4fv(vScr2);
	glTexCoord2f(1,1);	glVertex4fv(vScr3);
	glTexCoord2f(1,0);	glVertex4fv(vScr4);
 glEnd();

 glDisable(GL_BLEND);
 glDisable(GL_TEXTURE_2D);

 

Thanks