glDrawPixels: centering inside a list

Hi,

I’m rendering a 3d geometry with some 2d labels, these labels basically are 2d bitmaps located with a 3d point, I’m using glDrawPixels to draw the bitmap of those labels, since I need those bitmaps allways face to the front I can’t use textured quads, well, I could… but I can’t be converting that quad every time because I’m using a display list…

Inside the list creation, I have a call to glDrawPixels, and first I call glRasterPos3d, but I need to have the bitmap displayed with glDrawPixels centered, not in the lower left coords, the only way I see, is converting the 3d point to 2d and move that 2d point the bitmap width/2 and height/2, but the calls of glGet* are not stored inside the list… with glBitmap I can center the bitmap easily within the glBitmap call, and I would NOT need to convert the 3d point to 2d, the problem if I use glBitmap is it will go monochrome, is there a way to center the glDrawPixels without projecting the point (no glGet* calls) ???.. any ideas ??

Thanks.

Hi,

First, I think you should not use glDrawPixels for this since I think this is a little too slow if you have lots of labels.

Not sure if I understood - you are drawing these labels in ortho projection (on 2d screen) or have these labels as billboards in 3d space?

For drawing in 2d space (screen), you can use quad with texture, where I can see you already have texture generated,don’t see any problem with using list and facing quads to the front??? If you mean that positioning is the problem, glTranslatef(…) should be outside the list. For facing the front - well if you do draw in ortho proj. I see no problem neither connection between facing the front and using the list.

For drawing in 3d space, quad & texture are doing great job, you can draw them after entire scene is drawn and depth buffer is cleared, so these “3d labels” will be drawn over the scene but still in correct z order among each other. To face them to camera (if this was the problem), just use same camera angles (billboarding technique)- there are no calculations at all to face them to camera since you already have angles (if your cam works with angles or matrix if your cam works with matrices).

This helps you a bit?

And do not put your labels inside the display list.

hey, thanks for the replies !

I tried removing the labels from the list, it works but becomes very slow, I’ll try the textured quads then…
I don’t know about that billboarding techinique, but as I said, these labels are 2D but drawn within the 3D model, I mean, the labels coords are 3D, but the width and height are in screen size and allways facing front…

So, you want to position them to be always the same size on the screen (to have it as “overlay”) and not to really exist in 3d space.

I would use GL_QUADS, draw quad of desired size and with texture on it, in ortho projection. Or even in default projection and modelview matrix, since you know that coordinate [-1,-1,0] is in the lower-left corner and [1,1,0] in upper-right corner, and with glGet you can get current viewport position and size inside the window, you can do something like:

glMatrixMode(GL_PROJECTION);
if(first_time) glLoadIdentity(); // here,make sure first time you run the app, to initialize proj matrix with default values
glPushMatrix(); // now, dig in, to be able to save original matrix and do some changes later

// here set projection for camera to render 3d scene

glMatrixMode(GL_MODELVIEW);
if(first_time) glLoadIdentity(); // same thing as for proj matrix
glPushMatrix();// same thing as for proj matrix

// here set modelview for camera to render 3d scene

// render 3d scene here

first_time = false;

// Now, go back to the original proj and modview matrices
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

// now again dig in modview matrix, to give us ability do draw in real pixel coordinates, by scaling it.
glPushMatrix();
{
GLfloat vport[4];
glGetFloatv(GL_VIEWPORT, vport);
if(vport[2] > 0 && vport[3] > 0)
{
glScalef(1.f/vport[2], 1.f/vport[3], 1.f);
glPushMatrix();
{
// here draw your labels (quads with texture) in screen coordinates you got from gluUnproject and 3d coordinates in scene.
}
glPopMatrix();
}
}
glPopMatrix();

// pay attention: num of pushes must be the same as num of pops. this is critical.

Hi,

I have already coded the necesary for drawing textured quads, but for some reason, I just see the quad but no texture, what exactly are the limitations of the texture image ?, for what the red book says, the width and height must be an even number, or is it a power of 2 ?, if that is the case how can I resize the image properly ???

Thanks.

gluScale

I have two more questions,

  1. how do I render the textured quads masked ?, I tried Alpha test but no luck…

  2. how do I put the labels in front of the 3D model ?, I want to keep depth order among the labels and model, but labels should be above model…

Thanks!

man, now I have no idea what you want to do. you sad you are positioning labels in 2d screen coords, and now you ask how to put labels in front of 3d model? are labels in 2d screen coords or are billboards in 3d space?

masking is done with alpha test and 32bit texture (rgba), where alpha test should be something like glAlphaFunc(GL_EQUAL,1.f) if you want to draw only fully non-transparent pixels, or to put some tolerance use glAlphaFunc(GL_GEQUAL, 0.9f).

hey, I was able to do the masking, thanks.

about the labels, I place them above the 3D model, for example, suppose I draw a cube, and on each vertex of the cube I place a rectangle with a label, those rectangles are textured qudas drawn with a gluOrtho2D projection. Now I would like to order those quads like if they were draw with a normal 3D projection, right now they are not ordered… I don’t know what is billboard, hope what I said clarifies what I want, or perhaps should I post some code ?

Thanks.

since you know vertex position, sort quads according to vertex distances from camera.

hey, thanks, works good!

one more issue (last one hopefully), some of the texture quads are drawn a bit distorted, for what I have read using GL_NEAREST for my case should work, but it does not all the time, I mean, some of the labels are draw good, some others a bit distorted, this is what I do before the call to glTexImage2D:

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

then, when displaying the textures I do the following:

for (i=0; i < _signTextureQuantity; i++)
{
	glBindTexture(GL_TEXTURE_2D, _signTextures[i].textureName);
	pt3D = _signTextures[i].point;
	gluProject(pt3D.x, pt3D.y, pt3D.z, mvmatrix, projmatrix, viewport, &pt2D.x, &pt2D.y, &pt2D.z);
	w = _signTextures[i].width / 2;
	h = _signTextures[i].height / 2;
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f);
		glVertex3d(pt2D.x - w, pt2D.y - h, pt2D.z);
		glTexCoord2f(1.0f, 0.0f);
		glVertex3d(pt2D.x + w - 1, pt2D.y - h, pt2D.z);
		glTexCoord2f(1.0f, 1.0f);
		glVertex3d(pt2D.x + w - 1, pt2D.y + h - 1, pt2D.z);
		glTexCoord2f(0.0f, 1.0f);
		glVertex3d(pt2D.x - w, pt2D.y + h - 1, pt2D.z);
	glEnd();
}

thanks again, you have been of great help.

I think you should first check if gluProject generates some error, before continuing drawing the label.

second, you should disable writing to depth buffer while drawint the labels. you don’t want that previously drawn labels have influence on gluProject.

min and mag filter are ok, if you want to have sharp image.

why do you need that “1” in coordinates?

what is your projection and modelview matrix when you draw these labels?

problem with distortion is because the size of label quads in screen pixels is not equal to the texture size (in pixels).

you need to set correctly projection and modelview matrices and also drawin of quads to be appropriate.

In my previous posts you can see how I would do drawing of labels.

Actually I make sure the size of the label bitmap is equal to the texture quad, below is the complete function of the label drawing, I’m using Objectie-C/Cocoa so the “AABitmapData” object is made somewhere else, but I think is pretty straight forward to see what I do, remember, this function is call after I render the 3D model.

typedef struct SignTextureData
{
	GLuint width, height, textureName;
	double distance;
	AAPoint point;
} SignTextureData;

int qsortSignTextureData(const void *e1, const void *e2)
{
  return ((const SignTextureData *)e2)->distance - ((const SignTextureData *)e1)->distance;
}

- (void)renderSigns
{
	NSArray *bitmapsArray, *coordinatesArray;
	NSEnumerator *bitmapsArrayEnumerator, *coordinatesArrayEnumerator;
	AABitmapData *bmp, *tmpBmp;
	AAPoint pt3D, pt2D, cameraCenter;
	GLdouble mvmatrix[16], projmatrix[16];
	GLint viewport[4];
	GLuint i, w, h, *data;
	BOOL orderSigns = YES;
	
	// check to make the textures
	if (_signTextureQuantity == 0)
	{
		// create signs bitmaps and the arrays with them
		[_modelSigns renderSigns];
		bitmapsArray = [_modelSigns partSignBitmapsArray];
		bitmapsArrayEnumerator = [bitmapsArray objectEnumerator];
		coordinatesArray = [_modelSigns partSignCoordinatesArray];
		coordinatesArrayEnumerator = [coordinatesArray objectEnumerator];
		// allocate textures
		_signTextureQuantity = [bitmapsArray count];
		_signTextures = (SignTextureData *) malloc(sizeof(SignTextureData) * _signTextureQuantity);
		for (i=0; i < _signTextureQuantity; i++) glGenTextures(1, &_signTextures[i].textureName);		
		// make the textures
		for (i=0; i < _signTextureQuantity; i++)
		{
			glBindTexture(GL_TEXTURE_2D, _signTextures[i].textureName);
			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
			bmp = [bitmapsArrayEnumerator nextObject];
			w = nextPowerOfTwo([bmp width]);
			h = nextPowerOfTwo([bmp height]);
			tmpBmp = [[AABitmapData alloc] initWithWidth:w height:h];
			[tmpBmp setIsMonochrome:NO];
			[bmp maskedBlit: tmpBmp x: (w - [bmp width])/2 y: (h - [bmp height])/2];
			[tmpBmp reset];
			data = [tmpBmp drawingBytes];
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
			_signTextures[i].width = w;
			_signTextures[i].height = h;
			_signTextures[i].point = [[coordinatesArrayEnumerator nextObject] cartesianPointValue];		
			[tmpBmp release];
		}
		// release signs bitmaps arrays
		[_modelSigns releaseStoredArrays];
	}
	// setup 2D view
	glGetIntegerv(GL_VIEWPORT, viewport);
	glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
	glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0, viewport[2], 0, viewport[3]);
	// order signs
	if (orderSigns)
	{
		cameraCenter.x = mvmatrix[3];
		cameraCenter.y = mvmatrix[7];
		cameraCenter.z = mvmatrix[11];
		for (i=0; i < _signTextureQuantity; i++) 
			_signTextures[i].distance = AAPointDistance(cameraCenter, _signTextures[i].point);
		qsort(_signTextures, _signTextureQuantity, sizeof(SignTextureData), qsortSignTextureData);
	}
	// render the textures
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_ALPHA_TEST);
	glAlphaFunc(GL_GREATER, 0.5);
	glShadeModel(GL_FLAT);
	glDisable(GL_DEPTH_TEST);
	glClear(GL_DEPTH_BUFFER_BIT);
	for (i=0; i < _signTextureQuantity; i++)
	{
		glBindTexture(GL_TEXTURE_2D, _signTextures[i].textureName);
		pt3D = _signTextures[i].point;
		gluProject(pt3D.x, pt3D.y, pt3D.z, mvmatrix, projmatrix, viewport, &pt2D.x, &pt2D.y, &pt2D.z);
		w = _signTextures[i].width / 2;
		h = _signTextures[i].height / 2;
		glBegin(GL_QUADS);
			glTexCoord2f(0.0f, 0.0f);
			glVertex3d(pt2D.x - w, pt2D.y - h, pt2D.z);
			glTexCoord2f(1.0f, 0.0f);
			glVertex3d(pt2D.x + w - 1, pt2D.y - h, pt2D.z);
			glTexCoord2f(1.0f, 1.0f);
			glVertex3d(pt2D.x + w - 1, pt2D.y + h - 1, pt2D.z);
			glTexCoord2f(0.0f, 1.0f);
			glVertex3d(pt2D.x - w, pt2D.y + h - 1, pt2D.z);
		glEnd();
	}
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_ALPHA_TEST);
	glEnable(GL_DEPTH_TEST);
	// restore 3D view
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
}

hope whit this you get the idea, thanks!!

EDIT: btw, the sort I did does not work properly…