-
Notifications
You must be signed in to change notification settings - Fork 1
Camera
VOID's standard Camera is a matrix-driven 2D camera with position, zoom, rotation, bounds, coordinate conversion, and conservative visible bounds for rendering.
The camera types live in:
using Void.Engine.Cameras;Normal drawing still goes through the regular batchers. You pass a camera to Begin, and the batcher carries its view-projection matrix through VOID's renderer-neutral pipeline.
var camera = new Camera
{
Position = new Vect2(500, 300),
Zoom = 2f,
Rotation = 0f,
Bounds = new Rect2(0, 0, 2000, 1200)
};Position is the world-space point shown at the center of the logical viewport.
A new camera starts:
- centered on
GameSettings.Instance.Viewport - at
Zoom = 1 - with zero rotation
- with no world bounds
Pass it to a sprite or primitive batch:
_batcher.Begin(
SortMode.BackToFront,
camera: camera);
_batcher.Draw(
playerTexture,
playerPosition,
Color.White);
_batcher.End();The same camera can be used with PrimitiveBatcher and render-target drawing.
Passing the camera to Begin(...) also triggers its automatic once-per-rendered-frame update before the batcher reads ViewProjection.
See Rendering for normal batcher usage.
camera.Position =
new Vect2(640, 360);This is the world position that appears at the center of the viewport.
A simple follow camera can therefore be:
camera.Position =
player.Position + player.Size * 0.5f;When a camera is passed to a batcher's Begin(...), VOID updates that camera automatically before reading its view-projection matrix.
A camera used by multiple batchers in the same rendered frame still updates only once for that frame. Game code does not manually call a camera update method.
camera.Zoom = 2f;Higher values show less world space and make the scene appear closer.
VOID clamps zoom values below 0.1f:
camera.Zoom = 0f;
// Effective zoom is 0.1f.Reset to normal zoom:
camera.ResetZoom();Rotation is measured in radians:
camera.Rotation =
MathHelper.HalfPI;Positive values follow VOID's positive-Y-down 2D rotation convention.
Rotation is included when VOID calculates camera bounds and visible extents.
Set a rectangle to keep the visible camera area inside a world region:
camera.Bounds =
new Rect2(0, 0, 2000, 1200);An empty rectangle disables clamping:
camera.Bounds = default;Clamping accounts for zoom and rotation, so the rotated viewport corners remain inside the configured world bounds.
If the bounded region is smaller than the visible camera area on an axis, VOID centers the camera on that axis instead of trying to clamp to an impossible range.
ScreenToWorld converts logical viewport coordinates into world space:
Vect2 worldPosition =
camera.ScreenToWorld(viewportPosition);WorldToScreen does the reverse:
Vect2 viewportPosition =
camera.WorldToScreen(worldPosition);These methods use GameSettings.Instance.Viewport.
MouseState.Position, however, is window-relative. If the native window and logical viewport differ because of Fit, PixelPerfect, Fill, supersampling, or another presentation setup, account for that presentation mapping before treating a raw mouse position as viewport coordinates.
See Input → Mouse and Window & Displays → Window Scale Modes.
Every BaseCamera exposes:
Rect2 visibleWorld =
camera.ViewBounds;ViewBounds is a conservative world-space axis-aligned rectangle derived from the four inverse-transformed viewport corners.
That matters for rotated cameras: the returned rectangle is intentionally large enough to contain the rotated visible area.
SpriteBatcher uses camera view bounds for coarse destination-rectangle culling when a camera is supplied to Begin.
A camera exposes its current view-projection matrix:
Matrix viewProjection =
camera.ViewProjection;The matrix is cached and rebuilt only after camera state invalidates it.
For the standard camera, the pipeline is:
translate world by -Position
↓
apply inverse Camera.Rotation
↓
apply Zoom
↓
project the logical viewport into clip space
VOID uses its own Matrix type rather than System.Numerics.Matrix4x4.
See Matrix for composition rules and common transforms.
Derive from BaseCamera when the standard Camera is not enough:
public sealed class OffsetCamera : BaseCamera
{
private Vect2 _offset;
public Vect2 Offset
{
get => _offset;
set
{
_offset = value;
Invalidate();
}
}
protected override Matrix CreateViewProjection()
{
Vect2 viewport =
GameSettings.Instance.Viewport;
return
Matrix.CreateTranslation(-_offset) *
Matrix.CreateOrthographic(
viewport.X,
viewport.Y);
}
}Whenever derived camera state changes the matrix, call Invalidate() so the cached view-projection and inverse matrices are rebuilt on demand.
BaseCamera also provides the cached inverse matrix to derived cameras and throws if an operation requires an inverse but the current matrix is not invertible.
Override the protected OnUpdate(FrameTime) hook for follow behavior, shake, smoothing, or transitions:
protected override void OnUpdate(
FrameTime frameTime)
{
// Update custom camera state.
// Call Invalidate() if the matrix changed.
}OnUpdate is invoked automatically when the camera is first used by a batcher during a rendered frame. In fixed timestep mode, the FrameTime seen here is in the render phase, so DeltaTime and ElapsedTime represent the actual elapsed rendered-frame time rather than the fixed simulation step.
PostProcessor.Apply can also receive a BaseCamera:
postProcessor.Apply(
sceneTarget,
camera);See Rendering → Post-Processing.
Home · Getting Started · Rendering · Custom Renderers · GitHub · Report an Issue
Built with VOID Engine · MIT License