gluPerspective

BlitzMax Forums/BlitzMax OpenGL Programming/gluPerspective

gluPerspective() takes the vertical fov, aspect, and near and far view ranges. I want the viewport to always use the same horizontal fov, and adjust the vertical fov so that it isn't stretched, regardless of the viewport height.

Viewport width=1024
Viewport height=768
desired horizontal fov=90 degrees

The aspect is the width divided by the height, which is 1024/768=1.33333333. I tried this:

gluPerspective 90.0/1.3333333,1.3333333,near,far

But this did not give me a little less than 90 degrees view in the horizontal direction. The only way I could get a perfect 90-degree view in the horizontal direction was like this:

gluPerspective 90.0/1.3333333,1.5,near,far

What's going on here? I noticed that 90.0/1.3333333/1.5=45.0, which might be significant.

Then I tried using glFrustum:
glfrustum -nearrange/zoom,nearrange/zoom,-nearrange/aspect/zoom,nearrange/aspect/zoom,nearrange,farrange

When zoom=1.0, I get a perfect 90-degree fov in the horizontal direction. However, when I try changing zoom to 2.0, for a 45-degree fov, I get a somewhat larger fov in the horizontal direction (approximately 50-60 degrees).

Well, after drawing it out on paper I saw that this takes a little trig to do. I have never seen a mention of precision zooming with the frustum, so I will post my solution here.

With zoom=1.0, the horizontal fov will be 90.0. With a zoom of 2.0, the horizontal fov will be 45.0 degrees. The vertical fov is dependent on viewport height. The aspect is the viewport width divided by the viewport height:

zoom#=2.0 // for a 45-degree fov. Use 1.0 for 90 degrees.
aspect#=width#/height#
theta#=Tan(45.0/zoom#) // temporary angle value
glfrustum -nearrange#*theta#,nearrange#*theta#,-nearrange#/aspect#*theta#,nearrange#/aspect#*theta#,nearrange#,farrange#

Here's an alternative to gluPerspective that takes the fovx as a parameter instead of the fovy. All other params stay the same.
Function Perspective( fovx:Float, ratio:Float, near:Float, far:Float )
		Local x:Float=Tan(fovx/2.0)*near
		Local y:Float=x/ratio
		glFrustum -x,x,-y,y,near,far
End Function
Hope it's of some use to you.

Here's manual versions of gluPerspective (methods in my camera type), glh.. sets the FOV horizontally, glv vertically. Might be of help.

	Method glhPerspective() '

		Local xmin:Double, xmax:Double, ymin:Double, ymax:Double
		Local m:Double[16]

		xmax = zNear * Tan(fov*.5)
		xmin = -xmax

		ymin = xmin / aspect
		ymax = xmax / aspect

		m[0] = (2 * zNear) / (xmax - xmin)
		m[5] = (2 * zNear) / (ymax - ymin)
		m[10]= -(zFar + zNear) / (zFar - zNear)

		m[2] = (xmax + xmin) / (xmax - xmin)
		m[6] = (ymax + ymin) / (ymax - ymin)
		m[11] = -1

		m[14] = -(2 * zFar * zNear) / (zFar - zNear);

		glMultMatrixd m
	End Method

	Method glvPerspective()
		Local xmin:Double, xmax:Double, ymin:Double, ymax:Double
		Local m:Double[16]

		xmax = zNear * Tan(fov*.5)
		xmin = -xmax

		ymin = xmin / aspect
		ymax = xmax / aspect

		m[0] = (2 * zNear) / (xmax - xmin)
		m[5] = (2 * zNear) / (ymax - ymin)
		m[10]= -(zFar + zNear) / (zFar - zNear)

		m[2] = (xmax + xmin) / (xmax - xmin)
		m[6] = (ymax + ymin) / (ymax - ymin)
		m[11] = -aspect

		m[14] = -(2 * zFar * zNear) / (zFar - zNear);
   
		glMultMatrixd m
	End Method


I figured it out for glfrustum, which I will just stick with. The zoom component is particularly important, and I recommend anyone setting up and opengl camera use what I write in my second post.