Cameras (3D)

Camera3D (in simvx.core.nodes_3d) is a Node3D subclass that supplies view + projection matrices to the renderer. The first Camera3D found in the scene tree is the active camera; render layers can be masked via cull_mask.

from simvx.core import Camera3D, Node, Vec3

class Scene(Node):
    def on_ready(self):
        self.add_child(Camera3D(
            position=(0, 5, 10),
            look_at=Vec3(0, 0, 0),
            fov=70.0,
            near=0.1,
            far=200.0,
        ))

Conventions

SimVX uses the following conventions for 3D math and cameras. They are load-bearing: read them once and assume they hold everywhere unless a specific subsystem (e.g. the Vulkan clip-space transposition) states otherwise.

Coordinate space

  • Right-handed, Y-up by default.

  • Forward = local -Z. Node3D.forward (and therefore Camera3D.forward) returns world_rotation * (0, 0, -1). This matches Godot, glTF, Maya, Blender’s runtime export, and the OpenGL family. It clashes with Unity and Unreal (+Z forward), so ports from those engines need to negate the forward vector once at import.

  • Right = local +X, up = local +Y.

Look-at / face-along

  • Node3D.look_at(target, up=…) rotates the node so its local -Z axis points at target in world space.

  • Node3D.face_along(direction, up=…) does the same with a direction vector, skipping the target subtraction. Convenient for steering by velocity.

  • Quat.look_at(direction, up=…) is the underlying primitive. It already bakes the -Z negation: pass the direction the node should face, not the direction the local +Z axis should land on.

Matrices

  • All matrices are stored row-major as NumPy arrays.

  • Vulkan shaders read column-major; the renderer transposes once at the GPU boundary in renderer/forward.py.

  • Camera3D.projection_matrix() flips the Y axis (proj[1, 1] *= -1) to match Vulkan’s clip-space Y-down convention. Other renderers (web / WebGPU) apply their own clip-space fixup; the row-major matrix that leaves Camera3D is the same.

Angles

  • All internal angles are in radians (fov on Camera3D is the exception: declared in degrees for the inspector and converted at matrix-build time).

  • UI / debug code converts to degrees for display. There is no separate “radians camera” type.

OrbitCamera3D

A turntable camera with yaw, pitch, distance, and pivot Properties. Useful for editor viewports and model viewers; not intended for first-person games.

Multiple cameras

The forward renderer’s ViewportManager supports multiple active cameras for split-screen or picture-in-picture. Add several Camera3D nodes and bind them to viewports via the renderer’s viewport API.