Sean
Sean

Reputation: 31

Perspective Projection, Canonical Viewing Volume

Vector3d nearC(0,0,0 -w);
Vector3d farC(0,0,0-x);
double width = y/2;
double height = z/2;
double angleOfHeight = atan(height/w);
double angleOfWidth = atan(width/w);
double adjustedHeight = tan(angleOfHeight) * x;
double adjustedWidth = tan(angleOfWidth) * x;

nearC[0] - width, nearC[1] - height, nearC[2]
nearC[0] - width, nearC[1] + height, nearC[2]
nearC[0] + width, nearC[1] + height, nearC[2]
nearC[0] + width, nearC[1] - height, nearC[2]
farC[0] - adjustedWidth, farC[1] - adjustedHeight, farC[2]
farC[0] - adjustedWidth, farC[1] + adjustedHeight, farC[2]
farC[0] + adjustedWidth, farC[1] + adjustedHeight, farC[2]
farC[0] + adjustedWidth, farC[1] - adjustedHeight, farC[2]

Above is my frustum in view coordinates. View Matrix is:

 0   0  -1   0
 0   1   0  -1
 1   0   0 -10
 0   0   0   1

All of it is right, we have a sheet.

I can't for the life of me figure how to get that frustum in canonical viewing volume. I've run through every perspective projection I could find. Current is this:

        s,        0,                      0,                     0,
        0,        s,                      0,                     0,
        0,        0,             -(f+ne)/(f-ne),            2*f*ne/(f-ne),
        0,        0,                      1,                     0;

double s = 1/tan(angleOfView * 0.5 * M_PI / 180);

I'm missing a step or something, right? Or a few steps?

Sorry to sound so hopeless now, been spinning wheels a while on this.

Any help appreciated.

Upvotes: 1

Views: 614

Answers (1)

Spektre
Spektre

Reputation: 51835

Lest start with the perspective projection. The common way in old GL is to use gluPerspective.

for that we need znear,zfar,FOV and aspect ratio of view. For more info see:

  • Calculating the perspective projection matrix according to the view plane

    I am used to use FOVx (viewing angle in x axis). To compute that you need to look at your frustrum from above looking at xz plane (in camera space):

    frustrum XY plane

    so:

    tan(FOVx/2) = znear_width / 2*focal_length
    FOVx = 2*atan(znear_width / 2*focal_length)
    

    the focal length can be computed by computing the intersection of frustrum edge lines. Or by using triangle similarity. The second is easier to write:

    zfar_width/2*(|zfar-znear|+focal_length) = znear_width/2*(focal_length)
    zfar_width/(|zfar-znear|+focal_length) = znear_width/(focal_length)
    focal_length = (|zfar-znear|+focal_length)*znear_width/zfar_width
    focal_length - focal_length*znear_width/zfar_width = |zfar-znear|*znear_width/zfar_width 
    focal_length*(1-(znear_width/zfar_width)) = |zfar-znear|*znear_width/zfar_width 
    focal_length = (|zfar-znear|*znear_width/zfar_width) / (1-(znear_width/zfar_width))
    

    and that is all we need so:

    focal_length = (|zfar-znear|*znear_width/zfar_width) / (1-(znear_width/zfar_width))
    FOVx = 2*atan(znear_width / 2*focal_length)        
    FOVx*=180.0/M_PI; // convert to degrees
    aspect=znear_width/znear_height;
    gluPerspective(FOVx/aspect,aspect,znear,zfar);
    

    just be aware of that |zfar-znear| is perpendicular distance between the planes !!! So if you do not have axis aligned ones then you need to compute that using dot product and normal ...

Upvotes: 2

Related Questions