2d graphics with perspective projection

Assuming that I’m stuck with a perspective projection would it be possible to
(relatively easily) be able to draw 2d graphics such as text that need
pixel-accurate placement?I know I normally use a glOrtho(0, resx, 0, resy) or
something like that but it would simplyfy overall design to just use one
projection method. Anyway if I drew the 2d opbjects(quads) on the near clipping
plane for example would I be able to compute the needed (x,y) coords(or setup a
modelview matrix to do the job) to place a vertex at pixel (x, y) or would
rounding errors and such make this unstable/impossible?

So basically what I want is:

Setup projection matrix (fovy, aspect, near, far …)

/* draw 2d stuff /
glMatrixMode(GL_MODELVIEW);
glLoadMatrix
(persp_to_ortho_matrix);
glBegin(GL_POINTS);
glVertex2*(x, y); /*this should appear exactly at pixel (x,y) */
glEnd();

Of course if neccesary a glVertex3* call can be used with some suitable z
coordinate.

Can you do what you want with gluProject? I’ve used gluProject to find window positions for 2D text that follows 3D objects through a scene.

Well in theory I can do what I want with gluUnProject(). That is given a pair of pixel coordinates (x,y) unproject them to get the world space coords (wx,wy,znear) and feed these to glVertex3f. What I don’t know is if all this will work reliably(precision/rounding won’t get the vertices to the wrong(neighbouring) pixels). Also I wonder if there would be other problems I haven’t thought of.

I guess I don’t really understand the problem you’re trying to solve. The only difficulty I can think of is that you can’t use gluUnProject to convert an xy window position to an xyz position in your scene. There’s no depth information in the original xy position.

Why can’t you just switch into Ortho, draw your 2D objects, then switch back?

I don’t know how your perspective matrix looks like but if it’s not singular, can’t you just do:

PM=Your perspective Matrix
PMinv=inverted PM
OM=Your Orthographic matrix
MV=whatever viewing you need

Setup projection matrix PM

/* draw 2d stuff /
mv = PMinv
OMMV;
glMatrixMode(GL_MODELVIEW);
glLoadMatrix
(mv);
glBegin(GL_POINTS);

glVertex2*(x, y);/*this should appear exactly at pixel (x,y) */

glEnd();

rgpc: It’s a matter of general design. It would simplify things. Hard to explain. I could do what you suggest but I’d rather avoid it.

roffe: I have thought of this but it should not be necessary. This would map (x, y, *) to (x, y) on-screen. Creating a matrix to map (x, y, z) where z is a constant like 0 to (x,y) on-screen could probably be done with a simple translation. It’s this translation matrix I’m looking for.

And btw: say I set up a projection matrix with gluPerspective. Where is the projection plane or viewing plane or whatever it’s called(that is the plane where the 3d world get projected onto). Is it the near clipping plane?

Originally posted by zen:
[b]rgpc: It’s a matter of general design. It would simplify things. Hard to explain. I could do what you suggest but I’d rather avoid it.

roffe: I have thought of this but it should not be necessary. This would map (x, y, *) to (x, y) on-screen. Creating a matrix to map (x, y, z) where z is a constant like 0 to (x,y) on-screen could probably be done with a simple translation. It’s this translation matrix I’m looking for.[/b]
So you’re saying that you’re willing to manipulate the matrix stacks, but you’re not willing to touch the projection matrix?

You can, of course, do that. Easiest would be loading an identity modelview matrix. Then you need to figure out where the near plane is, and how aspect ratio affects your x/y scaling. As a starting point, (0;0;znear) will be right at the screen center.

All right I see some explanations are in order (so that I don’t look completely stupid). Assuming that each game world entity has a postion and orientation (and no projection info since projection doesn’t have much to do with hte world itself, esp. on a per-entity basis) I thought I could use the entity model for the camera too. This way the camera will behave like a normal entity, thus will automagically have physics etc. applied to it and the general design will be simpler. So since a projection matrix doesn’t fit in there it has to be global defined by some config. variables at system boot time. So in order to have 2d objects(text, etc.) I thought I could just define an other ‘camera’ in such a way as to map all (x,y,znear) vertices to (x,y) onscreen. Thus everything is consistent etc. and not much extra work is required. You might say I could just have calls like setprojection() or something but I prefer to have the system/engine configured(via configvars) at boot time once and until restart and then given work to do (that is entities to render/simulate physics etc.)
zeckensack: So you’re saying that all vertices are projected to the near clipping plane as I thought. Then it shouldn’t be too hard to make a modelview matrix (a translation matrix I believe) to do the mapping I want. I’ll give it a try, Thanks!

It works! Just in case anyone is interested the mapping I was looking for is:

x = x’ * (r - l) / w + l
y = y’ * (t - b) / h + b
z = z’ + n

where l, r, t, b, n are the values passed to glFrustum(), x’, y’, z’ are the desired window coordinates and x, y, z are the needed world coordinates. As a matrix this can be written as:

[ (r - l) / w 0 0 l]
| 0 (t - b) / h 0 b|
| 0 0 1 -n|
[ 0 0 0 1]

So if you load this into the modelview matrix and do glVertex2f(0, 0) you’ll get a vertex at the lower left corner of the window.
Also note that if you use a vector and a 3x3 matrix to store entity position/orientation the above matrix can be encoded as a camera entity(well the rotation part won’t be a rotation but who cares?), which is what I was trying to do to begin with.
And I don’t seem to get any unexpected behaviour, too. Cool!