# The Projection Matrix

Specifically, the perspective projection matrix.
I need a good, clear explaination on how to create one properly from more information than simply the distance of the 6 clip planes (as in the red book).
The information I would like to create the matrix from is: the 6 clipping planes + a focal plane. The focal plane in my mind is the distance at which an object is 1-to-1 size with no scale.
Every explaination of the projection matrix I have encountered seems to combine the near plane with the focal plane in it’s explaination, when in reality they are not the same thing.
Any pointers would be appreciated, especially in the context of achieving true stereo.

As I have dealt with 3d stereo, I can say that the 1-to-1 focal plane is whatever you need it to be. Sometimes it is best placed at zfar, sometimes at znear, sometimes anywhere in between. Believe me.

To my experiments, it is best placed at about 1.5 times znear. The 3d objects may appear a bit small thought. But it depends on the fov too.

To have “real world” 3d depth effect, you need to take in account the distance between the real eye of the user as znear, the dimensions of the real visible screen as dimensions of the virtually visible znear plane. Then the focal point will be exactly at znear. Beware though, the farthest objects may be hard to focus, but it depends on your exact hardware 3d stereo method.

Hope it helps.

You want the impossible.

You cannot lock the 4 planes that define the field of view and then have a variable which gives an object at 1:1, the 6 planes (actually 4 of them) determine it’s scale at the given range. To do what you want would require modelview manipulations and that has nothing to do with projection.

To do what you want on the projection matrix you would have to compute the 4 planes based on the distance from the object required. Basically projecting the display size onto a plane at the object range and working out the distance.

It turns out this is trivial because you can use glFrustum and simple ratios.

With the near plane nominally at the object distance you generate window dimensions on that plane to match your display dimensions. You can then divide the 4 parameters by the object_distance/frustun_near to give you the values you need to give to the dimensions on the near plane to feed into the frustum.

This will give you 1:1 on your display for that distance.

P.S. the issue of stereo convergence is slightly different, there are infact multiple related issues there. Virtual IPD determines scale and the rest involves the correct geometry for the relationship of viewer to physical display (the only way to correctly change the FOV in a VR stereo display). When done correctly in is analogous to what’s been discussed. So again to correctly position something at 1:1 on the display requires modelview manipulations of the object or changing the viewer distance from the display, unless you adjust the virtual IPD scaling the world (which would be flawed for 1:1 viewing, since this would scale the objects but could place the scaled version 1:1 onscreen) or you can get things horribly wrong. There is no other option.

OTOH people tend to do heinous things with stereo display setups that are mostly geometrically wrong and spend a long time fudging things trying to compensate.

[This message has been edited by dorbie (edited 01-06-2004).]

KuriousOrange, the explanation you seek can be found in Chapter 4 of Mathematics for 3D Game Programming and Computer Graphics:

http://www.terathon.com/books/mathgames2.html

It explains how to construct a view frustum using a horizontal field of view angle and a viewport aspect ratio. It also assumes that the focal plane (where -1 <= x <= 1) lies at a distance of 1 from the camera, and it describes the relationship with the distance to the near plane that must be passed to the glFrustum() function.

Eric Lengyel, you’ll get my money out of my cold dead hands - shame on you charging people for answers on a public forum. Despicable.

To the others, well, I’ve got my answer from Ken Perlin, in a round about way: http://mrl.nyu.edu/~perlin/courses/fall2001/perspective.html

To sum up, this is how glFrustum generates the projection matrix (test code):

float* glFrustum(float left, float right, float bottom, float top, float nearval, float farval)
{
static float m[16];

float x, y, a, b, c, d;
float width = right-left;
float height = top-bottom;
float depth = farval-nearval;

x = (2.0fnearval) / width;
y = (2.0f
nearval) / height;
a = (right+left) / width;
b = (top+bottom) / height;
c = -(farval+nearval) / depth;
d = -(2.0ffarvalnearval) / depth;

m[0] = x; m[4] = 0.0f; m[8] = a; m[12] = 0.0f;
m[1] = 0.0f; m[5] = y; m[9] = b; m[13] = 0.0f;
m[2] = 0.0f; m[6] = 0.0f; m[10] = c; m[14] = d;
m[3] = 0.0f; m[7] = 0.0f; m[11] = -1.0f; m[15] = 0.0f;

return m;
}

But this is how I want to generate the projection matrix, with specific control over the focal plane:

float* myfrustum(float left, float right, float bottom, float top, float nearval, float farval, float focal)
{
static float m[16];

float x, y, a, b, c, d;
float width = right-left;
float height = top-bottom;
float depth = farval-nearval;

x = (2.0ffocal) / width;
y = (2.0f
focal) / height;
a = (right+left) / width;
b = (top+bottom) / height;
c = -(farval+nearval) / depth;
d = -(2.0ffarvalnearval) / depth;

m[0] = x; m[4] = 0.0f; m[8] = a; m[12] = 0.0f;
m[1] = 0.0f; m[5] = y; m[9] = b; m[13] = 0.0f;
m[2] = 0.0f; m[6] = 0.0f; m[10] = c; m[14] = d;
m[3] = 0.0f; m[7] = 0.0f; m[11] = -1.0f; m[15] = 0.0f;

return m;
}

Cheers.

[This message has been edited by KuriousOrange (edited 01-09-2004).]