Skip to main content

Camera

The Camera struct defines the virtual camera that views the scene. It supports position, target-based aiming, field of view, and interactive orbit controls.

Definition

cpp/include/Camera.h
struct Camera {
Vec3 position; // Camera location in world space
Vec3 target; // Point the camera looks at
Vec3 up; // World up direction
float fov; // Field of view in degrees
float aspectRatio; // Width / height

// Computed basis vectors
Vec3 forward; // Camera forward direction
Vec3 right; // Camera right direction
Vec3 upDir; // Camera up direction
float viewportHeight;
float viewportWidth;
};

Initialization

Camera()
: position(Vec3(0.0f, 0.0f, -3.0f))
, target(Vec3(0.0f, 0.0f, 0.0f))
, up(Vec3(0.0f, 1.0f, 0.0f))
, fov(60.0f)
, aspectRatio(1.0f) {
updateBasis();
}

Basis Vectors

The camera uses an orthonormal basis (three perpendicular unit vectors):

void updateBasis() {
// Forward: from camera toward target
forward = (target - position).normalize();

// Right: perpendicular to forward and world up
right = forward.cross(up).normalize();

// Up: perpendicular to forward and right
upDir = right.cross(forward).normalize();

// Viewport size based on FOV
float theta = fov * 3.14159265f / 180.0f;
viewportHeight = 2.0f * std::tan(theta / 2.0f);
viewportWidth = viewportHeight * aspectRatio;
}
        upDir (Y')


│ forward (Z')
│ ╱
│ ╱
│ ╱
●─────────→ right (X')
Camera

Ray Generation

For each pixel, generate a ray from the camera:

Ray getRay(float u, float v) const {
// u, v are in range [-1, 1] (normalized screen coordinates)
Vec3 horizontal = right * (u * viewportWidth * 0.5f);
Vec3 vertical = upDir * (v * viewportHeight * 0.5f);
Vec3 direction = forward + horizontal + vertical;
return Ray(position, direction);
}
Screen Space:          World Space:
(-1,1)──(1,1) ╲ │ ╱
│ │ ╲ │ ╱
│ ● │ ╲ │ ╱
│ │ ╲│╱
(-1,-1)─(1,-1) ● Camera

Field of View

FOV controls how much of the scene is visible:

void setFov(float newFov) {
fov = std::fmax(10.0f, std::fmin(120.0f, newFov));
updateBasis();
}
FOVEffect
20°Telephoto - objects appear closer, flatter
60°Normal - similar to human vision
90°Wide angle - more visible, some distortion
120°Ultra wide - extreme distortion at edges
Narrow FOV (20°):        Wide FOV (120°):
╱╲ ╱────────╲
╱ ╲ ╱ ╲
╱ ╲ ╱ ╲
╱ ╲ ╱ ╲
● ● ● ●

Look-At Target

The camera always points at the target:

void setTarget(float x, float y, float z) {
target = Vec3(x, y, z);
updateBasis();
}

Moving the target:

  • Points camera at different parts of the scene
  • Useful for focusing on specific objects
  • Combined with orbit for cinematic angles

Orbit Controls

The camera can orbit around its target:

void orbit(float deltaX, float deltaY) {
Vec3 offset = position - target;
float radius = offset.length();

// Convert to spherical coordinates
float theta = std::atan2(offset.x, offset.z); // Azimuth
float phi = std::acos(offset.y / radius); // Elevation

// Apply rotation from mouse movement
theta += deltaX * 0.01f;
phi += deltaY * 0.01f;

// Clamp phi to avoid gimbal lock
phi = std::fmax(0.1f, std::fmin(3.04f, phi));

// Convert back to Cartesian
position.x = target.x + radius * std::sin(phi) * std::sin(theta);
position.y = target.y + radius * std::cos(phi);
position.z = target.z + radius * std::sin(phi) * std::cos(theta);

updateBasis();
}

This is triggered by mouse drag on the canvas.

Zoom Controls

void zoom(float delta) {
Vec3 direction = (position - target).normalize();
float distance = (position - target).length();

// Clamp distance
distance = std::fmax(1.0f, std::fmin(20.0f, distance + delta));

position = target + direction * distance;
updateBasis();
}

Triggered by scroll wheel.

UI Controls

The Camera tab provides:

ControlRangeDescription
Position X-10 to 10Camera X position
Position Y-10 to 10Camera Y position
Position Z-15 to -1Camera Z position
Target X-5 to 5Look-at X
Target Y-5 to 5Look-at Y
Target Z-5 to 5Look-at Z
FOV20° to 120°Field of view

Plus interactive controls:

  • Drag on canvas - Orbit camera
  • Scroll wheel - Zoom in/out
  • Reset button - Return to default view