Projection matrix from 6 arbitrary frustum planes?
What would be the formula for calculating a projection matrix from 6 arbitrary frustum planes, each expressed as a normal and distance?
If you know that it's a vanilla perspective matrix (i.e. no skew), then you can calculate the intersection between two side planes and a top/bottom plane to get the camera position. The view direction is perpendicular to the view plane, so can calculate the FOV with the two side planes and the top/bottom planes. You can then calculate the distance from the camera position to the near and far planes along the view direction, and the aspect ratio between the two FOVs. That's all the information you need to generate the perspective matrix.
If the matrix has skew, then you'll need to find someone who has dealt with generating those kinds of matrices before :) It's been a while since I took the computer graphics course that covered all the nitty-gritty. I believe the documentation for glFrustum might contain some useful information in that regard.
If the matrix has skew, then you'll need to find someone who has dealt with generating those kinds of matrices before :) It's been a while since I took the computer graphics course that covered all the nitty-gritty. I believe the documentation for glFrustum might contain some useful information in that regard.
Even if you have skew, shear, off center, whatever you want to call it, it turns out to be pretty easy.
What you want is to get the left, right, top, bottom, near, and far values (let's call them l, r, t, b, zn, zf) to pass into something like glFrustum or D3DXMatrixPerspectiveOffCenterLH or the like - see the documentation for either of those functions to see how to derive the actual projection matrix from those values if you need it.
l, r, t, and b represent the extents of the rectangle formed by the intersection of the near clipping plane on the view frustum.
The equation for each of your frustum planes are:
Ax + By + Cz + D = 0
Where (A,B,C) is your plane's normal, and D is the distance.
When computing l and r, you know that z is the near clip plane's distance, and y can be set to zero. For top and bottom, z is still the near clip plane's distance, and x can be set to zero. Conveniently, D is zero for the left, right, top, and bottom planes of the projection, and zn and zf are simply the distances for the near and far clip planes (take care with the signs, the far clip plane's distance is negative since the plane points inward, so you'll need to negate it to get zf.)
The resulting algebra is trivial, but the bottom line is this:
To compute l and r, use x = (C * zn) / A (where A and C are from the plane equations for the left and right clipping planes respectively)
To compute t and b, use y = (C * zn) / B
If you're in a left handed coordinate system, negate all of these results.
Pass them into glFrustum or its equivalent, and you're done.
What you want is to get the left, right, top, bottom, near, and far values (let's call them l, r, t, b, zn, zf) to pass into something like glFrustum or D3DXMatrixPerspectiveOffCenterLH or the like - see the documentation for either of those functions to see how to derive the actual projection matrix from those values if you need it.
l, r, t, and b represent the extents of the rectangle formed by the intersection of the near clipping plane on the view frustum.
The equation for each of your frustum planes are:
Ax + By + Cz + D = 0
Where (A,B,C) is your plane's normal, and D is the distance.
When computing l and r, you know that z is the near clip plane's distance, and y can be set to zero. For top and bottom, z is still the near clip plane's distance, and x can be set to zero. Conveniently, D is zero for the left, right, top, and bottom planes of the projection, and zn and zf are simply the distances for the near and far clip planes (take care with the signs, the far clip plane's distance is negative since the plane points inward, so you'll need to negate it to get zf.)
The resulting algebra is trivial, but the bottom line is this:
To compute l and r, use x = (C * zn) / A (where A and C are from the plane equations for the left and right clipping planes respectively)
To compute t and b, use y = (C * zn) / B
If you're in a left handed coordinate system, negate all of these results.
Pass them into glFrustum or its equivalent, and you're done.
Thanks for the replies, but I'm not sure even glFrustum is general enough. For example, I don't necessarily want the near plane to be perpendicular to the viewing direction, and the shape of the near and/or far plane when intersecting the l,r,t&b planes shouldn't necessarily be rectangular either. So there are potentially skews and shears in every possible direction for all of the planes.
Thanks for the hints on l, r, b & t, though. That D = 0 is something I need to make a necessary constraint for the input. I've now thought a bit more about how to correctly phrase the problem and realized that there are some more constraints than that D = 0, though the problem is still less constrained than the cases which glFrustum can describe.
So, here we go, a more formal statement of the problem:
Given 6 planes labeled n,f,l,r,t,b, find the 4*4 projection matrix (an invertible one that maps coordinates inside the frustum to the unit cube 0..1 after homogenization rather than setting depth to 0) given that O = {0,0,0} is the origin, with subject to the following constraints:
- l,r,t,b all have D = 0 (they pass through the origin).
- dot(l.n, r.n) < 0 (informally, that the left and right planes face each other)
- dot(t.n, b.n) < 0
- dot(n.n, f.n) < 0
- there exists some points such that it lies in the positive half space of all six planes (meaning, that the frustum isn't degenerate), which is equivalent to the constraint that the volume of the frustum must be positive
- for all points P such that P lies on the near plane, it must hold that dot(P - O, n.n) > 0. (Informally, the near plane must point away from the origin)
Those should be the only constraints: apart from this, the planes may be arbitrary.
Thanks for the hints on l, r, b & t, though. That D = 0 is something I need to make a necessary constraint for the input. I've now thought a bit more about how to correctly phrase the problem and realized that there are some more constraints than that D = 0, though the problem is still less constrained than the cases which glFrustum can describe.
So, here we go, a more formal statement of the problem:
Given 6 planes labeled n,f,l,r,t,b, find the 4*4 projection matrix (an invertible one that maps coordinates inside the frustum to the unit cube 0..1 after homogenization rather than setting depth to 0) given that O = {0,0,0} is the origin, with subject to the following constraints:
- l,r,t,b all have D = 0 (they pass through the origin).
- dot(l.n, r.n) < 0 (informally, that the left and right planes face each other)
- dot(t.n, b.n) < 0
- dot(n.n, f.n) < 0
- there exists some points such that it lies in the positive half space of all six planes (meaning, that the frustum isn't degenerate), which is equivalent to the constraint that the volume of the frustum must be positive
- for all points P such that P lies on the near plane, it must hold that dot(P - O, n.n) > 0. (Informally, the near plane must point away from the origin)
Those should be the only constraints: apart from this, the planes may be arbitrary.
Eric Lengyel's article might be helpful:
http://www.terathon.com/code/oblique.html
Also see his powerpoint on "projection matrix tricks:"
http://www.terathon.com/gdc07_lengyel.ppt
http://www.terathon.com/code/oblique.html
Also see his powerpoint on "projection matrix tricks:"
http://www.terathon.com/gdc07_lengyel.ppt
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement