2
\$\begingroup\$

I am working with my camera, and am trying to improve it so that I can calculate if a world point is on screen, taking rotation into account. Currently, my camera rectangle is calculated as so:

    public Rectangle Rectangle
    {
        get
        {
            int width = (int)((ViewportWidth / _zoom));
            int height = (int)((ViewportHeight / _zoom));
            return new Rectangle((int)(_pos.X - width / 2), (int)(_pos.Y - height / 2), width, height);
        }
    }

Then, to check if a point is on screen, I call one of the following functions:

    public bool IsOnScreen(Point location)
    {
        return this.Rectangle.Contains(location);
    }

    public bool IsOnScreen(Rectangle bounds)
    {
        return this.Rectangle.Intersects(bounds);
    }

However, none of these calculations take the rotation factor into account; only position and the zoom factor. I know that I can calculate the corners of the camera, in world space, using the following transformations:

var topLeftCorner      = Vector2.Transform(new Vector2(0, 0), Matrix.Invert(ViewMatrix));
var topRightCorner     = Vector2.Transform(new Vector2(ViewportWidth, 0), Matrix.Invert(ViewMatrix));
var bottomLeftCorner   = Vector2.Transform(new Vector2(0, ViewportHeight), Matrix.Invert(ViewMatrix));
var bottomRightCorner  = Vector2.Transform(new Vector2(ViewportWidth, ViewportHeight), Matrix.Invert(ViewMatrix));

However, the rectangle object that I am using is not able to take this into account, since it cannot store rotation. What is the calculation that I can use to check if a point is inside the virtual rectangle with these points, or if a rectangle intersects with the virtual rectangle?

Here's some graphics to better illustrate some of my code:

Unrotated rect/rotated rect

\$\endgroup\$
  • 1
    \$\begingroup\$ It's not good solution, but you can try to rotate the point X by the negative angle of camera's rectangle and then check if point is inside. \$\endgroup\$ – Ocelot Jul 16 '15 at 15:28
  • \$\begingroup\$ @Ocelot what would I rotate around? The center of the rectangle? \$\endgroup\$ – Pip Jul 16 '15 at 15:31
  • \$\begingroup\$ is the Point location in world space (3d) or screen space? \$\endgroup\$ – Steve H Jul 16 '15 at 15:43
  • \$\begingroup\$ @SteveH Both location and the param for the rectangle overload are in world space, as is the rectangle. \$\endgroup\$ – Pip Jul 16 '15 at 15:48
  • \$\begingroup\$ @Pip, of course! You can use trigonometry for this. Some pseudo code: PointToRotate.X = CameraRectangleCenter.X+cos(-CameraRectangle.Angle)*distance(CameraRectangleCenter.X, CameraRectangleCenter.Y, PointToRotate.X, PointToRotate.Y); PointToRotate.Y = CameraRectangleCenter.X+sin(-CameraRectangle.Angle)*distance(CameraRectangleCenter.X, CameraRectangleCenter.Y, PointToRotate.X, PointToRotate.Y); But still, it's not good solution to use. \$\endgroup\$ – Ocelot Jul 16 '15 at 15:49
1
\$\begingroup\$

Since you are working in 3d world space, why not use the BoundingFrustum class?

BoundingFrustum cameraBounds = new BoundingFrustum(view * projection);

if(cameraBounds.contains(location))
{
   // it is in view
}
else
{
  // not in view
}

edit. I assumed you are using XNA. If not, you can still reflect the XNA code to see how to make a Bounding frustum class and a .contains method.

The mechanics behind the BoundingFrustum class:

The ctor creates 6 planes in 3d space; one that is the left edge of all that the camera sees, one that is the right edge, top, bottom, near plane, far plane. It stores those planes for intersection tests just like you want. They can be reset anytime the view or projection changes. They automatically take into account the rotation of the camera. the .Contains method checks the test point (your location) against all 6 planes to decide if it is inside the camera's view or not. http://www.monogame.net/documentation/?page=T_Microsoft_Xna_Framework_BoundingFrustum

Here is a link to many forum questions about the BoundingFrustum found on the old XNA creators hub: http://xboxforums.create.msdn.com/search/SearchResults.aspx?q=BoundingFrustum

\$\endgroup\$
  • \$\begingroup\$ I am using MonoGame, which probably has the BoundingFrustum class at this point. Could you explain some of the mechanics behind this, and explain where the view * projection came from? I assume they are matricies. \$\endgroup\$ – Pip Jul 16 '15 at 16:02
  • \$\begingroup\$ They are. Most 3d frameworks use a view & projection matrix to take a world space location and transform it to screen space. the view matrix contains the location and rotation of the camera (analogous of the camera body). The projection matrix contains the field of view, near clip, and far clip of the camera (analogous of the camera lens). here is a primer codinglabs.net/article_world_view_projection_matrix.aspx \$\endgroup\$ – Steve H Jul 16 '15 at 16:07
  • \$\begingroup\$ the mechanics behind the class: the ctor creates 6 planes in 3d space; one that is the left edge of all that the camera sees, one that is the right edge, top, bottom, near plane, far plane. It stores those planes for intersection tests just like you want. They can be reset anytime the view or projection changes. They automatically take into account the rotation of the camera. the .Contains method checks the test point (your location) against all 6 planes to decide if it is inside the camera's view or not. monogame.net/documentation/… \$\endgroup\$ – Steve H Jul 16 '15 at 16:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.