# Extract smaller frustum from camera frustum?

Background:

I was thinking of implementing multiselection by performing a frustum culling on a sub-part of the screen.

Problem:

Given total screensize, a rectangle on the screen (pos, size), and the original camera frustum (projection, pos, rot), how can I construct a sub frustum corresponding to the given rectangle? UPDATE:

To be implementation specific, I am using DirectX and in DirecXMath there is a BoundingSphere vs BoundingFrustum intersection currently used in my ordinary frustum culling. http://msdn.microsoft.com/en-us/library/windows/desktop/hh855914(v=vs.85).aspx

So presumably given a new projection matrix and a new rotation I would be able to construct a new BoundingFrustum to use in my ordinary frustum culling.

• What are you planning on using this frustum for? Another way of asking this is: How do you plan on representing this frustum? – Mokosha May 19 '13 at 21:22
• @Mokosha To be implementation specific, I am using DirectX and in the DirecXMath there is a BoundingSphere vs BoundingFrustum intersection I am currently using in my ordinary frustum culling. msdn.microsoft.com/en-us/library/windows/desktop/… So presumably given a projection matrix I would be able to construct a new BoundingFrustum to use in my ordinary frustum culling. – Adelost May 19 '13 at 21:47

I'm not familiar with DirectX, but the BoundingFrustum docs you link to say that it can be constructed from a projection matrix.

All you need to do, then, is multiply your actual projection matrix by a matrix which (if you used it to draw with) would scale/translate the graphics so that the rectangle you want fills the viewport, then use that matrix product to construct a BoundingFrustum.

The matrix should just be an appropriate scale and translation in X and Y coordinates.

You can test it out by actually drawing using the modified projection matrix.

• This doesn't seem like it will work. The bounding frustum assumes that it's oriented in the direction of the z-axis, an assumption which is lost in the question. What you're describing isn't a "projection matrix" in the computer graphics sense of the term. The way that the bounding frustum is constructed is by figuring out planes from the near, far, left, right, top, and bottom edges and using them as a 6-dop. If there was no translation, then I think your method would be fine. – Mokosha May 20 '13 at 1:50
• Why would translation be a problem? It's equivalent to left ≠ right or top ≠ bottom. In fact, you could perfectly well do the same thing by generating a projection matrix with different left/right/top/bottom values; I described it the way I did because the math is more direct (it doesn't depend on your choice of near/far distances or if you're using a FOV-angle-based projection matrix generator). – Kevin Reid May 20 '13 at 1:59
• My intuition tells me that the fact that the new "cutout" frustum could be not centered on the z-axis would cause problems with your method. It's not a frustum "shape" in this case (geometrically)... e.g. when the y-axis values of all rectangle corners are positive. I will test it to see if it works though, since now I'm curious too. =) – Mokosha May 20 '13 at 2:09
• The part I am having most trouble with is finding the rotation for the new frustum relative to the old. – Adelost May 20 '13 at 15:02
• If the new frustum is for a sub-rectangle on the screen, then it is not rotated. Use the same pos and rot as the original screen bounding frustum. – Kevin Reid May 20 '13 at 16:17

In my first attempt, I created a new projection matrix for the smaller window, and then tried to rotate the frustum using LookAt, this almost worked but had some distortion when tilting up or down.

However, using a different approach it turns out the problem was quite easy to solve in DirectX. The BoundingFrustum class that I used (while It can be constructed from a projection matrix) actually consists of a nearplane, farplane, and 4 different sloops. By multiplying the 4 sloops with the ratio between the sub window and parent window, I get a working subfrustum.

Solution

Here is a code sample in DirectX with some functionality hidden, but it should not be to hard to follow.

BoundingFrustum getSubFrustum( FloatRectangle& window, FloatRectangle& sub_window )
{
// Construct bounding frustum from camera projection
BoundingFrustum f(m_mat_projection);
f.Origin = m_position;
f.Orientation = m_rotation;

// Translates the rectangle from "0 .. 2x", to "-x .. x"
// making center 0,0 in the new coordinate system
Float2 center = window.center();
window.translate(-center);
sub_window.translate(-center);

// Adjust bounding slopes to match sub window
float left = sub_window.position.x/window.position.x;
float right = (sub_window.position.x + sub_window.size.x)/(window.position.x + window.size.x);
float top =  sub_window.position.y/window.position.y;
float bottom =  (sub_window.position.y + sub_window.size.y)/(window.position.y + window.size.y);
f.LeftSlope *= left;
f.RightSlope *= right;
f.TopSlope *= top;
f.BottomSlope *= bottom;

return f;
}

• It works! However, It feels like I have not understood the problem. I would still love to hear a solution using the projection matrix only, so it would be possible to use the projection while actually drawing.

Construct a new projection matrix, with smaller FOV and near/far planes shifted towards the middle. Then build your shrinked Frustum out of it - simple as that.