How do I calculate the boundary of the game window after transforming the view?
- by Cypher
My Camera class handles zoom, rotation, and of course panning. It's invoked through SpriteBatch.Begin, like so many other XNA 2D camera classes. It calculates the view Matrix like so:
public Matrix GetViewMatrix() {
return Matrix.Identity
* Matrix.CreateTranslation(new Vector3(-this.Spatial.Position, 0.0f))
* Matrix.CreateTranslation(-( this.viewport.Width / 2 ), -( this.viewport.Height / 2 ), 0.0f)
* Matrix.CreateRotationZ(this.Rotation)
* Matrix.CreateScale(this.Scale, this.Scale, 1.0f)
* Matrix.CreateTranslation(this.viewport.Width * 0.5f, this.viewport.Height * 0.5f, 0.0f);
}
I was having a minor issue with performance, which after doing some profiling, led me to apply a culling feature to my rendering system. It used to, before I implemented the camera's zoom feature, simply grab the camera's boundaries and cull any game objects that did not intersect with the camera.
However, after giving the camera the ability to zoom, that no longer works. The reason why is visible in the screenshot below. The navy blue rectangle represents the camera's boundaries when zoomed out all the way (Camera.Scale = 0.5f). So, when zoomed out, game objects are culled before they reach the boundaries of the window. The camera's width and height are determined by the Viewport properties of the same name (maybe this is my mistake? I wasn't expecting the camera to "resize" like this).
What I'm trying to calculate is a Rectangle that defines the boundaries of the screen, as indicated by my awesome blue arrows, even after the camera is rotated, scaled, or panned.
Here is how I've more recently found out how not to do it:
public Rectangle CullingRegion {
get {
Rectangle region = Rectangle.Empty;
Vector2 size = this.Spatial.Size;
size *= 1 / this.Scale;
Vector2 position = this.Spatial.Position;
position = Vector2.Transform(position, this.Inverse);
region.X = (int)position.X;
region.Y = (int)position.Y;
region.Width = (int)size.X;
region.Height = (int)size.Y;
return region;
}
}
It seems to calculate the right size, but when I render this region, it moves around which will obviously cause problems. It needs to be "static", so to speak. It's also obscenely slow, which causes more of a problem than it solves.
What am I missing?