View Full Version : gluPerspective and it's #'s
LongJumper
2003.10.21, 03:28 PM
I'm going to write an equation that will figure how big something appears on the screen when it's pushed back on the z-axis.
In order to do that, I need to know where the FOV angle really is. Is it assuming one point in the center of the monitor where the angle originates from? Or is it one point "deep inside" the monitor where it originates from?
I have to admit, I dont understand the problem.
gluPerspective uses a simple perspective projection in which all lines focus to a single point behind the screen, in its center.
Why dont you just run the object's bounding box through the perspective transform matrix, you will then see how big it is?
MattDiamond
2003.10.21, 05:39 PM
Dooog beat me to it. I'm pretty sure gluPerspective takes an argument which represents the near plane of the frustum; you can think of this as being the plane of monitor screen if you want. Thus the apex of the frustum is "behind" that plane. (If the monitor was at the apex then everything would be projected to a single point.)
If you don't want to use the matrix projection as Dooog suggested, it should be possible to write the equation you want. When I wrote 3D Brick Bash I didn't know any matrix math (just as well, it probably would have been too slow on Macs of the day.) Instead I drew the frustum on a piece of paper (I didn't know what it was called either, just what it looked like) and used right triangles to figure the projection equation for my special case. I was also able to rearrange the equations to completely avoid any trigonometric functions, so a simple ratio was that was needed.
Of course, I used simplifying assumptions which may not apply to you. For example, I was using the screen coordinate system as my global coordinate system, so things projected directly into screen coordinates. And the viewpoint never moves or rotates... With assumptions like that, one year of high-school geometry was sufficient.
Hope this helps...
LongJumper
2003.10.21, 08:08 PM
Hmm, indulge me on the matrices idea. I am familiar with multiplying/adding etc. matrices, but have never put that to any use.
Originally posted by LongJumper
Hmm, indulge me on the matrices idea. I am familiar with multiplying/adding etc. matrices, but have never put that to any use.
Every vertex you give to OpenGL gets transformed by the current modelview matrix, and then the projection matrix, and the end of the process OpenGL knows the screen coordinates of your vertex. You could also do this manually, by extracting the matrices (or knowing them some other way) and applying the transformation to whatever vertex you'd like.
Since you get to keep the vertex, you can play around, and by transforming all corner vertices of a box, you should get an idea of how many pixels the box will cover.
MattDiamond
2003.10.21, 10:08 PM
Couple of additional comments: you don't need to project the whole bounding box, just two opposite points of it.
You can ask OpenGL to give you back the matrix it is currently using, for both the modelview or the projection matrix. Search the forum; someone else asked this earlier this year. Hint: search for glFloatv, or see appendix B of the Red Book.
If your code composes its own matrices and loads them directly to OpenGL using glLoadMatrix, as opposed to calling glMultMatrix to tell OpenGL to compose them for you, then you may already have the matrices handy.
LongJumper
2003.10.22, 12:15 AM
So basically glGetFloatv(GL_PROJECTION_MATRIX,m);
glMultMatrix(m,points); or some such thing?
Originally posted by MattDiamond
Couple of additional comments: you don't need to project the whole bounding box, just two opposite points of it.
...
That is not correct. Those two opposing points may just happen to be project onto the same pixel, in which case the size of the actual object is not assessible.
Two oppising points are ok to start, but all 8 have to be extrapolated and pushed through the transformation.
Alternatively, the box may be represented by a transformation matrix, which simplifies things somewhat.
MattDiamond
2003.10.22, 02:25 PM
Originally posted by DoooG
That is not correct. Those two opposing points may just happen to be project onto the same pixel, in which case the size of the actual object is not assessible.
Whoops, I was thinking of a box aligned with the viewer already, a very simple case.
But note that the original question asked was how to figure out how small something gets as it moves down the z-axis, so I inferred that LongJumper was talking about the case where the camera is looking down that axis. So that specific question can be answer by moving an axis- aligned rectangle (you don't even need the third dimension) down the z-axis.
Maybe Longjumper can tell us what he's trying to do, if he hasn't already gotten what he needed and moved on...
Wouldn't a bounding sphere be easier to deal with than a bounding box?
morgant
2003.10.22, 04:01 PM
My guess is that a bounding box would more accurately represent the height (or width) of the object in question. Bounding spheres tend to pad the object more.
LongJumper
2003.10.23, 09:34 PM
I think ya'll assume I'm more intelligent than I really am :)
It's a rather simple equation probably, should be solvable by geometry except that I don't understand how the FOV comes into play.
Basically, I have a quad. This quad has x and y coordinates, and it's z coordinate is always -1(so you can see it!). It's always drawn directly in front of the user, never at any angle. It is just a simple window :)
MattDiamond
2003.10.23, 11:26 PM
Originally posted by LongJumper
I think ya'll assume I'm more intelligent than I really am :)
It's a rather simple equation probably, should be solvable by geometry except that I don't understand how the FOV comes into play.
If it helps, just think in terms of width and height. (Given the FOV and the width, you can calculate the height. Given the width and height, you can calculate the FOV.)
Programmer
2003.10.24, 12:13 PM
You probably don't need to be exactly precise, right? In that case I suggest figuring out what the radius of the object by finding the greatest distance of each of its vertices from its center. Just use sqrt(x^2+y^2+z^2) on each vertex and take the largest one. This will give you the most pessimistic radius for any orientation of the object.
Second, create a pair of points by taking the distance between camera and the object as Z, the radius of the object as +/- X and zero as Y. (+R,0,D) and (-R,0,D). Actually in GL I'm not sure if +Z is visible or -Z is.
Third, fetch the projection matrix and the identity matrix and call gluProject for each of these points. The compute the XY distance between the two resulting points and that is your size. Use the identity matrix for the modelview transform because your points are already camera-relative.
Edit: Heh, just read LongJumpers latest post. The calculation of the "radius" is more trivial in this case.
LongJumper
2003.10.26, 07:16 PM
A window is drawn like this:
glTranslatef(0,0,-1); //Always this.
if(trans)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA);
}
glFrontFace(GL_CW);
glBegin(GL_QUADS);
glTexCoord2f(0,1);
glVertex3f(x,y,0);
glTexCoord2f(1,1);
glVertex3f(x+width,y,0);
glTexCoord2f(1,0);
glVertex3f(x+width,y-height,0);
glTexCoord2f(0,0);
glVertex3f(x,y-height,0);
glEnd();
User clicks a button. I get a QDpoint where it was. I run it thru this equation:
double h = (double)where->h/resolution.h;
double v = (double)where->v/resolution.v;
result[0] = h - .5;
result[1] = .5 - v;
This solves my problem, except that the window is pushed back -1 unit on the z axis, making for some minor(and in some case major) errors when I want to click inside the window.
This is solved by simple trigonometry, but I cannot solve it because I do not know the viewing angle, where it originates from, or how the object shrinks when it is projected. I don't know how to use gluProject or gluUnProject and I don't know how to multiply two points into a matrix and get a result.
LongJumper
2003.10.27, 03:22 AM
I got this, and the hilarious thing is it is almost perfect, on the width, I haven't done it for the height yet, so anything pertaining to the y coordinates is just in there because I was messing around.
bool XWindow::InBounds(Point* p)
{
double result[2];
ScreenToGLCoords(p, result);
//difference of object's new width/height when it is
//pushed back on the z-axis 1 unit
// change 27 to fov/2
double wDiff = width -
((1.0f / (2*tan(DegreesToRadians(27)))) * width);
double hDiff = height -
((1.0f / (2*tan(DegreesToRadians(27)))) * height);
//arbitrary number that seems to work times the ratio of
//the right edge of the quad over the max x-coordinate(.5),
//since 1 unit across, two quadrants makes up 1/2, .5
double ratioRight = 1.6*(fabs(x+width) / 0.5);
double ratioLeft = 1.6*(fabs(x) / 0.5);
//If in negative x quadrant, want to add ratio*diff
// otherwise subtract the ratio*diff
double xExp = x < 0 ? ratioLeft*wDiff : -1*ratioLeft*wDiff;
double xwExp = x+width < 0 ? ratioRight*wDiff : -1*ratioRight*wDiff;
if(result[0] >= x + xExp
&& result[0] <= width + x + xwExp
&& result[1] <= y + hRatio
&& result[1] >= y - height + 2*hRatio)
return true;
return false;
}
that 1.6 is kind of something I picked because it works fairly well. The closer the object is to the center of the screen(x = 0), the more accurate it is. When it is at the absolute edge of the screen in z = 0(not on the edge when z = -1, because it's being pushed back and shrank), its off by 2 pixels, which isn't that much... but could use room for improvement.
This leads me to believe that the number 1.6 is obviously not constant, but a non-linear function of the distance away from the center point, making some sort of curving ... I can't really put it in words, I could draw it though. Basically think of a baseball field, the outfield has a curve at the end, think of homeplate as the origin, and the foul lines are at an angle = to the FOV, and therefore the number that multiplies the ratio would have something to do with that.
So any suggestions would be appreciated as to why this is intelligent/********/useless.
vBulletin® v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.