I need perspective. (circles shouldn't be ovals)

Started by
4 comments, last by Jonny K 19 years, 10 months ago
I''ve got a simple little game. I''m drawing it in OpenGL using the coordinate system (0,0) (bottom left) to (1,1) (top right). All my drawing is based on this area, so if I want something in the middle of the screen, I''ll draw it at (0.5,0.5). (by the way, is there a better way I should be doing this?). Anyway, the game works nicely, except everything is a bit squished because I''m not adjusting for perspective. When the resolution/screen changes, I run this code: glViewport(0, 0, w, h); //Set the viewport to be the entire window (what the camera looks at) glMatrixMode(GL_PROJECTION); //Use projection matrix glLoadIdentity(); //Reset projection matrix gluOrtho2D(0.0, 1.0, 0.0, 1.0); //Map unit square to viewport I''m still figuring out what gluOrtho2D does... :-) But now I need to use...what, gluPerspective()? But when I play with it, I find I can''t get the screen looking at that same area as before (0,0 to 1,1). It''s as if this command sets the camera perspective for a first person shooter, not a 2D top-down game. All I want to do is set my perspective so things aren''t squished, while still keeping everything else in simple 2D fasion. Thanks, Jonny K.
Advertisement
Briefly put, gluPerspective sets up a perspective projection - i.e. a 3D to 2D projection that makes things look smaller when they are further away. gluOrtho sets up an orthographic projection, which simply means that things won't look smaller when they are further away. gluOrtho2D is just gluOrtho with the near plane set to -1 and the far plane set to 1. If you don't understand near and far planes, don't worry about it - you won't need to understand them for this.

gluOrtho2D(left,right,bottom,top) means that the left clipping plane will be at "left," the right one at "right" and so on. In your specific case this means that you map the upper left pixel to the OpenGL coordinate (0.0,1.0) and the bottom right one is mapped to the coordinate (1.0,0.0).
One way to handle this in a more elegant way, is to take w and h into account. Instead of always having the ranges (0.0,1.0), you should scale them depending on the actual width and height of the window. If you make so that the smallest of w and h is mapped to 0.0,1.0 (and the other one is scaled,) you'll know that the square are extending 0.5 in all directions from the origin is always visible, and (0.5,0.5) is the center of the window.

[edited by - TomasH on May 25, 2004 5:02:23 AM]
"Instead of always having the ranges (0.0,1.0), you should scale them depending on the actual width and height of the window."

So...I set the range to (w,h) instead? I''m still not sure what to do. Will this allow me to continue drawing into an area of 0,0 to 1,1?

Thanks.
You could use gluOrtho2D(0,w,0,h), but that would mean that you see more or less of the game area as you resize the window. This might not be what you want, but at least your circles won''t be distorted
If you want to always draw in the area (0,0) to (1,1) you could do something like this:
If width is greater than height
gluOrtho2D(0,w/(float)h,0,1)
otherwise
gluOrtho2D(0,1,0,h/(float)w)
This way you''ll always have the area you want visible and non-distorted and (0.5,0.5) is the center of this area (but not necessarily the center of the window.)
If you want the drawing area to be centered in the window you simply go from -0.5 to 0.5 instead of 0.0 to 1.0 and so on.

(Notice that you can still draw outside this area if it''s smaller than the window.)

Another option is to not allow resizing of the window.
Perhaps I should clarify a bit. I''m using the "GLUT Game Mode" - full screen only. I run at standard resolutions like 1024x768 and 1280x1024. The window will always be wider than it is tall.

With that in mind, I tried gluOrtho2D(0,w/(float)h,0,1), and yes, it does set the perspective properly, but the drawing area ended up being more on the left half of the screen. (since it draws from the left edge until it hits 1.0, and the screen may be 1.33 wide, for instance). To fix this, I wrote:

float ratio = (float)w/(float)h;
gluOrtho2D(0.0-((ratio-1.0)/2), ratio-((ratio-1.0)/2), 0.0, 1.0);

This simply takes that remaining ratio greater than 1 (the .33 part), and divides it in two. The screen is then shiften by half that value left of 0.0, and half that value right of 1.0. This has the effect of centering the 0,0 to 1,1 region on the screen! YAY!

Is this right? So then when I change resolutions, more or less of the sides will be wasted, since I''m only drawing in a square area of the screen. At 1280x1024 I will loose 0.25, while at 640x480 I will loose 0.33. Kindof what a widescreen TV does when it''s not displaying widescreen HDTV, and instead is displaying standard 4:3 material (old, regular TV).

But this leads me to wonder, is there a better way? Instead of restricting myself by drawing based on a 0,0 to 1,1 coordinate system, should I instead be drawing based on screen percentages? (ship goes at 20% down, 30% across. Ship is 1% wide, and 1% long. Missiles fired are 0.02% wide...etc).

And thanks for the help.
quote:Original post by Jonny K
Perhaps I should clarify a bit. I''m using the "GLUT Game Mode" - full screen only. I run at standard resolutions like 1024x768 and 1280x1024. The window will always be wider than it is tall.

With that in mind, I tried gluOrtho2D(0,w/(float)h,0,1), and yes, it does set the perspective properly, but the drawing area ended up being more on the left half of the screen. (since it draws from the left edge until it hits 1.0, and the screen may be 1.33 wide, for instance). To fix this, I wrote:

float ratio = (float)w/(float)h;
gluOrtho2D(0.0-((ratio-1.0)/2), ratio-((ratio-1.0)/2), 0.0, 1.0);

This simply takes that remaining ratio greater than 1 (the .33 part), and divides it in two. The screen is then shiften by half that value left of 0.0, and half that value right of 1.0. This has the effect of centering the 0,0 to 1,1 region on the screen! YAY!

Is this right?

Yes, that''s correct.

quote:Original post by Jonny K But this leads me to wonder, is there a better way? Instead of restricting myself by drawing based on a 0,0 to 1,1 coordinate system, should I instead be drawing based on screen percentages? (ship goes at 20% down, 30% across. Ship is 1% wide, and 1% long. Missiles fired are 0.02% wide...etc).

Well... When you just used gluOrtho2D(0.0,1.0,0.0,1.0) you were kind of using percentages of the screen size to draw objects. When you drew a circle of radius 0.2, you were actually saying you wanted the "vertical radius" to be 20% of the height and the "horizontal radius" to be 20% of the width. Since the width wasn''t equal to the height, you ended up with an oval instead of a circle...
What you could do, is to simply take advantage of the extra area you get for some resolutions (well, you''d get extra area for all resolutions, since none are square.) Instead of limiting the playing field to a square area, you might let it extend to the sides; just try drawing something at, say, (0.6,0.0). This might be an unfair advantage to people running at some resolutions, though.

This topic is closed to new replies.

Advertisement