Problem with perspective

Hi,

I’m pretty new to OpenGL, and am trying to program a very simplistic game engine. Everything works fine, except for one problem with perspective.

My program draws a simple floor and walls made of textured quads. It’s basicly just a traditional tile engine, but projected into 3d, with walls added… (I won’t post direct code, since I am programming with a little known language called XBLite, a variation of XBasic. But the OpenGL routines should be quite universal…)

I set up the perspective with gluPerspective. The attributes should be pretty normal, as far as I understand them: 90 degrees field of view, 4/3 aspect (using a 800*600 window), 0.1 and 35.0 clipping planes… And then I set the viewpoint with gluLookAt. I track movement in the world with X and Y variables, and calculate the “camera” position a little behind and above this point, looking at it… The floor is drawn on the X/Y plane, so I use an up vector of 0,0,1. After this I draw the quads, in the ordinary manner…

So, the program works ok. But the perspective is clearly screwed up… Looking straight on, it looks almost ok, but nearer to the edges of the screen it becomes quite distorted, like stretched towards the edge or something… It’s hard to exactly describe it in words…

One interesting phenomenon is seen when the height (ie. z in this case) of the “camera” is set to the height of the wall tiles, which is 1 in this case, while the point the camera is trained on is a little lower. The tops of the walls in this situation are all horizontal on the screen! Like a horizon, but a little above the center of the screen. This looks very weird…

If anyone has any ideas of what could be the cause of this, it would be much appreciated… as I said, I’m still new to OpenGL so I may be missing something important… I just can’t figure out what…

Ben B.

I’ve uploaded a screenshot to: http://personal.inet.fi/koti/elcalen/perspective_problem_screenshot.jpg

The walled areas should be square, and the box in the front should be a cube…

As you can see on the box in front, there’s clearly something wrong with the way you assign the texture coordinates to vertices.

So I think the lines you see on the outer walls are the diagonals of a wall-tile and not the vertical edges between wall-tiles.

Taking this into account, the perspective effect looks ok to me.

Greetz,

Nico

Hmm, after taking a closer look at the screenshot, there may be something more going on than just the texturing problem.

Could you post the code where you define your projection matrix based on fov,up vector,etc…?

Nico

Yes, I know the textures on the box are messed up. It is a model loaded from disk, and I haven’t finished coding the routine for displaying models… However, the floor and walls are drawn with a different routine, and I can’t see anything wrong with the coordinates… That pic might not be the best possible, but if you look at the wall on the right you can clearly see it’s twisted… When moving the camera further back and up, the nearest corners look even more stretched…

If I use a smaller field of view, the distortion doesn’t seem as strong. But some problems are still visible. Especially the horizon thing I described above, when the camera is placed on the level of the wall tops and pointing slightly down…

Well, as I said, I’m coding in XBasic. If you’ve used any basic variety, then the code should be easy to ready. Anyway, it’s mostly just GL commands…

This is how I clear the buffers and set up perspective and viewpoint:

  
glViewport( 0, 0, 800, 600 )
glClear( $$GL_COLOR_BUFFER_BIT| $$GL_DEPTH_BUFFER_BIT)

glMatrixMode( $$GL_PROJECTION )
glLoadIdentity()
gluPerspective( 90, DOUBLE(4)/DOUBLE(3), 0.01, 35.0 )

glMatrixMode( $$GL_MODELVIEW )                                                   
glLoadIdentity()                                                                 
gluLookAt( CamX, CamY, CamHeight, X, Y, 0.6, 0.0, 0.0, 1.0 )

Okay, and then I proceed to draw the floor and walls, with a simple loop that reads data from a simple two dimensional map array. (Like a traditional tile engine.)

FOR x = 1 TO 20
FOR y = 1 TO 20

IF Map[0, x, y] > 0 THEN

glBindTexture( $$GL_TEXTURE_2D, #texture[Map[0, x, y]] )
glBegin( $$GL_QUADS )
glTexCoord2f(0.0, 0.0) glVertex3f(   x,   y,  0.0)
glTexCoord2f(1.0, 0.0) glVertex3f( x+1,   y,  0.0)
glTexCoord2f(1.0, 1.0) glVertex3f( x+1, y+1,  0.0)
glTexCoord2f(0.0, 1.0) glVertex3f(   x, y+1,  0.0)
glEnd()

END IF

NEXT y
NEXT x

The drawing routine also checks if the tile is a wall tile, designated by certain numbers. In this case it skips the floor drawing bit above, and instead draws up to four quads, one on each side of the square where there is a floor tile in existence…

glBegin( $$GL_QUADS )
IF Map[0, x, y+1] > 0 THEN
IF Map[0, x, y+1] < 100 THEN
glTexCoord2f(0.0, 0.0) glVertex3f( x+1, y+1,  0.0)
glTexCoord2f(1.0, 0.0) glVertex3f(   x, y+1,  0.0)
glTexCoord2f(1.0, 1.0) glVertex3f(   x, y+1,  1.0)
glTexCoord2f(0.0, 1.0) glVertex3f( x+1, y+1,  1.0)
END IF
END IF
glEnd()

This is repeated for all four sides of the square, the relative coordinates manually calculated…

Then, as I am using the GLFW lib, I finish off with a call to glfwSwapBuffers (). And that about should describe the heart of my program… From what I’ve looked at demo programs, I set up the perspective in a pretty ordinary fashion… I can’t figure out if I’m doing something wrong…

Ben B.

I took a couple of screenshots of that horizon thing.

http://personal.inet.fi/koti/elcalen/perspective_problem_screenshot2.jpg
http://personal.inet.fi/koti/elcalen/perspective_problem_screenshot3.jpg

The first one is taken with a field of view of 45, the second at 60 degrees. The height of the camera (ie. z, as the floor is drawn on the x-y plain) is 1.0, which is also the height of the wall quads, and pointed a little forward and down to 0.6…

I’m pretty sure that the tops of the walls shouldn’t be level at the top of the screen…

with gluPerspective, the fov is defined along the y-axis. If you set this to 90 degres and an aspect ratio of 4/3, the fov along the x-axis will be close to 106 degrees which is to high for a realistic look of the scene.

It’s well known to gamers that a higher fov results in great er distortion. Most gamers use a large fov to see more of the surroundings at one glance, but this is a trade-off with the accompanying distortion.

Also, could you be a little more precise about the point you are looking at? cause when you look from a point at height 1.0 towards a point at height 0.6 and 0.4 forward (meaning the length of the projection of the line that connects the camera center and the reference point onto the x-y plane is 0.4) with fov 90, the top of the walls should allign with the top of your screen.

Nico

Originally posted by -NiCo-:
with gluPerspective, the fov is defined along the y-axis. If you set this to 90 degres and an aspect ratio of 4/3, the fov along the x-axis will be close to 106 degrees which is to high for a realistic look of the scene.

I’m not sure I quite understand this… Are these in relation to screen coordinates or world coordinates?

Originally posted by -NiCo-:
Also, could you be a little more precise about the point you are looking at? cause when you look from a point at height 1.0 towards a point at height 0.6 and 0.4 forward (meaning the length of the projection of the line that connects the camera center and the reference point onto the x-y plane is 0.4) with fov 90, the top of the walls should allign with the top of your screen.

I’m not sure about this either… Does this mean the horizon is at the height of the camera, regardless of whether you’re looking up or down? Shouldn’t the horizon always be at the center of the view to get a natural perspective?

As for the specifics of my positioning: As my idea involves a third person view of a character, I’ve got X and Y coordinates for the character, and the angle he is facing. So, I want the camera behind and above… (Direction behind is angle + 180 degrees, and then I add the cosine and sine of that angle, multiplied by distance, to X and Y respectively.) The height of the camera is some value, say between 0.6 and 3.0… I’ve been trying several different values.

As for the point I’m looking at, the relation to the floor is the X and Y coordinates, as I said, and for height I’ve been experimenting different points between 0 and 1… (Like, for example, if I wanted to have a kind of fake first person view, I might set both heights to 0.6, and the distance of the camera very small…)

As I’ve said before, I’m still new to this, so there may be something wrong with the way I’m going about this…

There is nothing wrong with your perspective, really. The ‘horizon’ effect is due to the fact that the camera and the top of the walls are at the same height.

If you want to keep all the vertical lines parallel in screen space, your camera have to look straight to the horizon. There is no other way. You can bias the viewport so that the camera aims at the top of the viewport.

The ‘distortions’ are only due to perspective projection. There is not much you can do about it, apart from putting your camera farther and narrowing the fov (less than 75° horizontal). You never played Quake nor Tomb Raider ?

Originally posted by ZbuffeR:
[b]There is nothing wrong with your perspective, really. The ‘horizon’ effect is due to the fact that the camera and the top of the walls are at the same height.

If you want to keep all the vertical lines parallel in screen space, your camera have to look straight to the horizon. There is no other way. You can bias the viewport so that the camera aims at the top of the viewport.

The ‘distortions’ are only due to perspective projection. There is not much you can do about it, apart from putting your camera farther and narrowing the fov (less than 75° horizontal).[/b]
Yes, it would appear that this is the case. It does look much better with a smaller with a smaller fov. Well, I’m pretty new to 3d graphics, so I’m still learning as I go. :wink:

Originally posted by ZbuffeR:
You never played Quake nor Tomb Raider ?
Lol, yeah, but my engine is much more simple, which I think makes distortions more noticeable… :smiley:

Thanks for the advice, anyway. I’ll just have to set up my fov and camera locations so that it looks good. I think I can manage that. :wink: