Learn / QUBICENGINE HANDBOOK

Transforms & cameras

Move an object, orbit a camera, and change perspective while keeping each coordinate space clear.

Coordinates need a reference#

A point at x = 1 is incomplete information without knowing the coordinate space. In a model’s local space it might be one unit from that model’s origin. In world space it is one unit from the scene origin. In camera space it is measured relative to the viewing camera. A transform is a rule for converting between spaces. Translation moves, rotation changes orientation, and scale changes size. A matrix stores several such operations in a compact form that can be composed with other matrices. You can use the concept before studying how to multiply all its entries.

INTERACTIVE ILLUSTRATIONSIMULATION / BROWSER

Move the world. Move the camera. This illustration uses canvas. The explanation below describes the same process.

Change a control to inspect the result. Values describe the simulation, not native engine benchmarks. Open full lab ↗

The three transformations to distinguish#

Model-to-world places the object in the scene. World-to-view expresses the scene relative to a camera. Projection maps view-space coordinates toward a screen image. After clipping and a divide by clip w, a viewport maps normalized coordinates to pixel coordinates. Change model translation and watch the object move relative to the axes. Change camera distance and watch perspective alter its apparent size. Change field of view and watch a wider camera fit more of the world without changing the model’s actual dimensions.

A convention must stay consistent#

The handbook uses left-handed camera space with forward along positive Z, row vectors, and row-major matrix storage. In its native sample, DirectXMath composes world × view × projection, and HLSL computes mul(position, worldViewProjection). Storage order and multiplication order are related choices but are not the same definition.

Read the native math
cpp · REFERENCE EXCERPT
XMMATRIX world = XMMatrixRotationY(angle);
XMMATRIX view = XMMatrixLookAtLH(eye, target, up);
XMMATRIX projection = XMMatrixPerspectiveFovLH(
    verticalFov, float(width) / height, 0.1f, 100.0f);
XMMATRIX worldViewProjection = world * view * projection;

The near/far planes limit what the camera can render. Their values also affect depth precision. A very small near plane paired with a very distant far plane can waste precision in a conventional depth setup. Advanced renderers often use reverse Z, with corresponding projection, clear value, and comparison changes.

Parent relationships#

A child object’s local pose is relative to its parent. Moving the parent moves the child. With row vectors, childWorld equals childLocal × parentWorld. Reparenting while preserving the child’s world pose requires the inverse of the new parent transform. A singular transform cannot be inverted. Normals are directions, not positions. Translation should not move a normal. Nonuniform scale can change the direction perpendicular to a surface, so normals use the appropriate inverse-transpose transformation and are normalized afterward. Simply using the position matrix is not always correct.

Inside QubicEngine#

Scene computes world transforms in hierarchy order. CameraData stores view/projection and frustum information. RenderWorld carries immutable matrices for each visible instance. The backend copies or binds them through frame-owned data and keeps that storage valid until the GPU is finished.

Common mistakes#

A cube disappearing when moved may have crossed a clip plane. A stretched image after resizing usually has a stale aspect ratio. Rotation around an unexpected point often means translation and rotation were composed in the wrong order. If native code and shader disagree about matrix packing, inspect a single known point instead of transposing every matrix at random. Read scene hierarchy and the DX12 textured sample for those contracts in practice.

Search titles and full article text.