Error in billbording code

Hello, I’ve been going through this tutorial on billboarding, but when I finished it and ran the code I couldn’t find my billboarded sprite at all, can anyone tell me why I can’t find it? All the calculations seem to be correct.


public void drawBillBoardSprite(Texture texture, Vector3f sprPos, float r, float g, float b, int sprWidth, int sprHeight){
		 // store the current model matrix
		GL11.glPushMatrix();
			
			// bind to the appropriate texture for this sprite
			texture.bind();
		    Vector3f look = new Vector3f(0,0,0);
		    Vector3f.sub(player.pos, sprPos, look);
		    look.normalise();
		    
		    Vector3f right = new Vector3f(0,0,0);
		    Vector3f.cross(new Vector3f(0,1,0) /* <-- default up vector */, look, right);
		    right.normalise();
		    
		    Vector3f up = new Vector3f(0,0,0);
		    Vector3f.cross(look, right, up);
		    up.normalise();
		    
		    
		    Matrix4f m = new Matrix4f();
		    m.m00 = right.x;
		    m.m01 = right.y;
		    m.m02 = right.z;
		    m.m03 = 0;
		    
		    m.m10 = up.x;
		    m.m11 = up.y;
		    m.m12 = up.z;
		    m.m13 = 0;
		    
		    m.m20 = look.x;
		    m.m21 = look.y;
		    m.m22 = look.z;
		    m.m23 = 0;
		    
		    m.m30 = sprPos.x;
		    m.m31 = sprPos.y;
		    m.m32 = sprPos.z;
		    m.m33 = 1;
		    
		    java.nio.FloatBuffer fb = BufferUtils.createFloatBuffer(32);
		    m.store(fb);
		    GL11.glMultMatrix(fb);
				
			// draw a quad textured to match the sprite
		    GL11.glBegin(GL11.GL_QUADS);
				GL11.glTexCoord2f(0,0);										GL11.glVertex3f(-sprPos.x, (sprHeight/2), -sprPos.z);    // Top left Of The Quad (Left)
				GL11.glTexCoord2f(0, texture.getHeight());					GL11.glVertex3f(-(sprPos.x + sprWidth), (sprHeight/2), -sprPos.z);  // Top right Of The Quad (Left)
				GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());	GL11.glVertex3f(-(sprPos.x + sprWidth), -(sprHeight/2), -sprPos.z);   // Bottom right Of The Quad (Left)
				GL11.glTexCoord2f(texture.getWidth(), 0);					GL11.glVertex3f(-sprPos.x, -(sprHeight/2), -sprPos.z);   // Bottom left Of The Quad (Left)
			GL11.glEnd();
			
		// restore the model view matrix to prevent contamination
		GL11.glPopMatrix();

	}

You didn’t flip your FloatBuffer ;D


fb.flip();
glMultMatrix(fb);

Not again! We need a sticky’d thread telling people to flip their buffers!

Yup, that was it. Thank you very much. ;D

Okay, so I thought I had this all worked out, but I found another error. The farther away from 0,0,0 the sprite is the less the billboarding works. only being 20 units away the sprite goes nearly sideways so you can almost not see it.

Below is my new code, can anyone tell me whats going on?


public void drawBillBoardSprite(Texture texture, Vector3f sprPos, float r, float g, float b, int sprWidth, int sprHeight){
		 // store the current model matrix
		GL11.glPushMatrix();
			
			// bind to the appropriate texture for this sprite
			texture.bind();
		    Vector3f look = new Vector3f(0,0,0);
		    Vector3f.sub(player.pos, sprPos, look);
		    look.normalise();
		    
		    Vector3f right = new Vector3f(0,0,0);
		    Vector3f.cross(new Vector3f(0,1,0) /* <-- default up vector */, look, right);
		    right.normalise();
		    
		    Vector3f up = new Vector3f(0,0,0);
		    Vector3f.cross(look, right, up);
		    up.normalise();
		    
		    
		    Matrix4f m = new Matrix4f();
		    m.m00 = right.x;
		    m.m01 = right.y;
		    m.m02 = right.z;
		    m.m03 = 0;
		    
		    m.m10 = up.x;
		    m.m11 = up.y;
		    m.m12 = up.z;
		    m.m13 = 0;
		    
		    m.m20 = look.x;
		    m.m21 = look.y;
		    m.m22 = look.z;
		    m.m23 = 0;
		    
		    m.m30 = sprPos.x;
		    m.m31 = sprPos.y;
		    m.m32 = sprPos.z;
		    m.m33 = 1;
		    
		    java.nio.FloatBuffer fb = BufferUtils.createFloatBuffer(32);
		    m.store(fb);
		    fb.flip();
		    GL11.glMultMatrix(fb);
				
			// draw a quad textured to match the sprite
		    GL11.glBegin(GL11.GL_QUADS);
				GL11.glTexCoord2f(0,0);										GL11.glVertex3f( - (sprWidth/2), (sprHeight/2), 0);    // Top left Of The Quad (Left)
				GL11.glTexCoord2f(texture.getWidth(), 0);					GL11.glVertex3f( + (sprWidth/2), (sprHeight/2), 0);  // Top right Of The Quad (Left)
				GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());	GL11.glVertex3f( + (sprWidth/2), -(sprHeight/2), 0);   // Bottom right Of The Quad (Left)
				GL11.glTexCoord2f(0, texture.getHeight());					GL11.glVertex3f( - (sprWidth/2), -(sprHeight/2), 0);   // Bottom left Of The Quad (Left)
			GL11.glEnd();
			
		// restore the model view matrix to prevent contamination
		GL11.glPopMatrix();

	}

Why generate your own matrix instead of just using glTranslatef(…)?

Oops, I read this wrong. How would I go about using glTranslatef() for this?

Like this? it doesn’t rotate enough though, but I think I’m getting close. Any help would be greatly appreciated.


public void drawBillBoardSprite(Texture texture, Vector3f sprPos, float r, float g, float b, int sprWidth, int sprHeight){
		 // store the current model matrix
		GL11.glPushMatrix();
			GL11.glTranslatef(sprPos.x, 0, sprPos.z);
			// bind to the appropriate texture for this sprite
			texture.bind();
			
			Vector3f objToCam = new Vector3f(player.pos.x - sprPos.x, 0, player.pos.z - sprPos.x);
		    Vector3f look = new Vector3f(0,0,1);
		    
		    objToCam.normalise();
		    
		    float angleCosine = Vector3f.dot(look, objToCam);
		    
		    Vector3f upAux = new Vector3f(0,0,0);
		    Vector3f.cross(look, objToCam, upAux);
		    
		    if ((angleCosine < 0.9999999) && (angleCosine > -0.9999999)) {
	            float angle = (float) (Math.toDegrees(Math.acos(angleCosine)));
	            GL11.glRotatef(angle, upAux.x, upAux.y, upAux.z);
	        }
				
			// draw a quad textured to match the sprite
		    GL11.glBegin(GL11.GL_QUADS);
				GL11.glTexCoord2f(0,0);										GL11.glVertex3f( - (sprWidth/2), (sprHeight/2), 0);    // Top left Of The Quad (Left)
				GL11.glTexCoord2f(texture.getWidth(), 0);					GL11.glVertex3f( + (sprWidth/2), (sprHeight/2), 0);  // Top right Of The Quad (Left)
				GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());	GL11.glVertex3f( + (sprWidth/2), -(sprHeight/2), 0);   // Bottom right Of The Quad (Left)
				GL11.glTexCoord2f(0, texture.getHeight());					GL11.glVertex3f( - (sprWidth/2), -(sprHeight/2), 0);   // Bottom left Of The Quad (Left)
			GL11.glEnd();
			
		// restore the model view matrix to prevent contamination
		GL11.glPopMatrix();

	}

I don’t have much experience with neither vector math nor sprites in 3D, so I don’t know exactly how much I can help here. A few tips though:

glRotatef(angle, x, y, z) works by rotating around the axis supplied. As an example, if your camera is in front of the sprite and you rotate it around the x-axis (1, 0, 0), the sprite will make a front/back flip. In 2D, you always rotate along the z-axis (0, 0, 1) because it is the axis extending into the screen, which is the only possible rotation in 2D. I have no idea what values you are passing into glRotatef(…), but it seems to me that you’re trying to do about the same thing as gluLookAt(…) does.

Also when finding an angle between two points, I always use Math.atan2(y, x), because it works for any angle without any if-cases.

Got it working, finally ;D ;D ;D ;D ;D ;D ;D


public void drawBillBoardSprite(Texture texture, Vector3f sprPos, float r, float g, float b, int sprWidth, int sprHeight){
		 // store the current model matrix
		GL11.glPushMatrix();
			GL11.glTranslatef(sprPos.x, 0, sprPos.z);
			// bind to the appropriate texture for this sprite
			texture.bind();
			
			FloatBuffer modelview = BufferUtils.createFloatBuffer(16);

			// get the current modelview matrix
			GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelview);
			
			// Note that a row in the C convention is a column 
			// in OpenGL convention (see the red book, pg.106 in version 1.2)
			// right vector is [1,0,0]  (1st column)
			// lookAt vector is [0,0,1] (3d column)
			// leave the up vector unchanged (2nd column)
			// notice the increment in i in the first cycle (i+=2)
			for(int i=0; i<3; i+=2 ) 
				for(int j=0; j<3; j++ ) {
					if ( i==j )
						modelview.put(i*4+j, 1.0f);
					else
						modelview.put(i*4+j, 0.0f);
				}

			// set the modelview matrix
			GL11.glLoadMatrix(modelview);
				
			// draw a quad textured to match the sprite
		    GL11.glBegin(GL11.GL_QUADS);
				GL11.glTexCoord2f(0,0);										GL11.glVertex3f( - (sprWidth/2), (sprHeight/2), 0);    // Top left Of The Quad (Left)
				GL11.glTexCoord2f(texture.getWidth(), 0);					GL11.glVertex3f( + (sprWidth/2), (sprHeight/2), 0);  // Top right Of The Quad (Left)
				GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());	GL11.glVertex3f( + (sprWidth/2), -(sprHeight/2), 0);   // Bottom right Of The Quad (Left)
				GL11.glTexCoord2f(0, texture.getHeight());					GL11.glVertex3f( - (sprWidth/2), -(sprHeight/2), 0);   // Bottom left Of The Quad (Left)
			GL11.glEnd();
			
		// restore the model view matrix to prevent contamination
		GL11.glPopMatrix();
	}