![]() |
Lysa
0.0
Lysa 3D Engine
|
Camera.ixx and Camera.cpp Camera implements a first-person fly camera. It wires its own input and process event handlers internally, so the application code only needs to construct it and set its initial transform.
lysa::Camera struct At the engine level a camera is just a plain data struct:
The renderer reads transform and projection each frame to build the view-projection matrix used for culling and shading. It is your responsibility to keep these fields up to date.
The application-level Camera class manages the lysa::Camera through a two-node SceneInstance hierarchy and updates camera.transform from pivot->globalTransform every PROCESS tick.
The camera is built from two SceneInstance nodes:
Camera::setTransform writes to this node.[maxCameraAngleDown, maxCameraAngleUp] ([-45°, 60°]) to prevent gimbal flip.Separating yaw (on attachment) from pitch (on pivot) avoids the gimbal lock that occurs when both rotations are composed in a single matrix: since yaw is always applied in world space and pitch is always applied in the camera's local frame, the two degrees of freedom remain independent.
The lysa::Camera view matrix is updated from pivot->globalTransform every process tick:
The projection matrix is created with lysa::perspective and re-created on window resize so the field of view is always correct for the current aspect ratio:
The camera captures and releases the mouse on click. While the mouse is captured the cursor is hidden and locked to the window centre (lysa::MouseMode::HIDDEN_CAPTURED). Pressing Escape releases it.
| Input | Effect |
|---|---|
| Click | Toggle mouse capture |
| W / A / S / D | Move forward / left / backward / right |
| Q / Z | Move up / down |
| Mouse | Yaw and pitch |
| Arrow keys | Yaw and pitch (keyboard fallback) |
| Escape | Release mouse |
| Left gamepad stick | Move |
| Right gamepad stick | Look |
Movement accelerates from minMovementsSpeed to maxMovementsSpeed while a key is held, and resets to zero immediately on release. The acceleration is applied in PHYSICS_PROCESS (fixed timestep) so movement speed is frame-rate independent.
The Camera constructor subscribes to three events and stores the returned handler IDs so they can be unregistered cleanly in the destructor:
| Event | Handler | Role |
|---|---|---|
MainLoopEvent::PHYSICS_PROCESS | onPhysicsProcess | Keyboard/gamepad input and movement |
MainLoopEvent::PROCESS | onProcess | Mouse delta and final camera.transform push |
RenderingWindowEvent::INPUT | onInput | Mouse-button capture toggle |
RenderTargetEvent::RESIZED | onResize | Rebuild projection matrix |
Storing the handler IDs (lysa::unique_id) returned by subscribe is the standard pattern for event ownership. Always call ctx().events.unsubscribe in the destructor to avoid dangling callbacks: