EAGL.Camera (eagl v0.8.0)
View SourceCamera system for 3D navigation and control.
This module provides a comprehensive camera implementation equivalent to the LearnOpenGL camera class, offering first-person style camera controls with mouse look, keyboard movement, and scroll zoom functionality.
Original C++ Source
This camera implementation is based on the original LearnOpenGL C++ camera class: https://github.com/JoeyDeVries/LearnOpenGL/tree/master/includes/learnopengl/camera.h
The design and functionality closely follow the C++ camera class tutorial from LearnOpenGL Chapter 7 - Camera, providing equivalent behaviour and API in Elixir.
Framework Adaptation Notes
Mouse Sensitivity Adaptation: The original LearnOpenGL tutorial uses a mouse sensitivity of 0.1f, which works well with GLFW's small mouse delta values. However, EAGL's windowing system reports pixel-level mouse movements, requiring a much smaller sensitivity (0.005) to achieve natural first-person camera feel.
This adaptation addresses the "world rotation" feeling that students might experience when following camera tutorials - the camera should feel like natural first-person movement, not like rotating the entire world coordinate system.
Features
- Euler Angle Camera: Uses yaw and pitch for orientation
- WASD Movement: Standard FPS-style keyboard controls
- Mouse Look: Mouse movement for camera rotation with natural sensitivity
- Scroll Zoom: Field of view adjustment via scroll wheel
- Pitch Constraints: Prevents camera flipping at extreme angles
- Delta Time Support: Frame-rate independent movement
Usage
# Create a camera at the origin looking down negative Z-axis
camera = EAGL.Camera.new()
# Create a camera at specific position
camera = EAGL.Camera.new(position: vec3(0.0, 0.0, 5.0))
# Process keyboard input (typically in handle_event/2)
camera = EAGL.Camera.process_keyboard(camera, :forward, delta_time)
# Process mouse movement (typically in handle_event/2)
camera = EAGL.Camera.process_mouse_movement(camera, x_offset, y_offset)
# Process scroll wheel (typically in handle_event/2)
camera = EAGL.Camera.process_mouse_scroll(camera, y_offset)
# Get view matrix for rendering
view_matrix = EAGL.Camera.get_view_matrix(camera)
Movement Directions
:forward
- Move in the direction the camera is facing (-Z by default):backward
- Move opposite to camera direction (+Z by default):left
- Strafe left (perpendicular to front vector):right
- Strafe right (perpendicular to front vector)
Euler Angles
- Yaw: Rotation around Y-axis (left/right look)
- Pitch: Rotation around X-axis (up/down look)
- Roll: Not used (always 0 for FPS-style camera)
Default yaw of -90° makes the camera look down negative Z-axis initially.
Educational Context
This camera implementation serves as the foundation for LearnOpenGL camera examples 7.4-7.6, demonstrating the progression from manual camera implementation to well-designed camera abstractions. The mouse sensitivity adaptation ensures that students experience natural first-person camera controls throughout the tutorial series.
Summary
Functions
Get the view matrix for this camera.
Create a new camera with default or custom parameters.
Process keyboard input for camera movement.
Process mouse movement for camera look around.
Process mouse scroll wheel input for zoom control.
Types
@type mat4() :: EAGL.Math.mat4()
@type movement_direction() :: :forward | :backward | :left | :right
@type vec3() :: EAGL.Math.vec3()
Functions
Get the view matrix for this camera.
The view matrix transforms world coordinates to camera/view space, effectively moving the world to simulate camera movement.
Examples
camera = EAGL.Camera.new(position: vec3(0.0, 0.0, 3.0))
view = EAGL.Camera.get_view_matrix(camera)
# Use in shader
set_uniform(program, "view", view)
Create a new camera with default or custom parameters.
Options
:position
- Camera position (default: {0.0, 0.0, 0.0}):world_up
- World up vector (default: {0.0, 1.0, 0.0}):yaw
- Initial yaw angle in degrees (default: -90.0):pitch
- Initial pitch angle in degrees (default: 0.0):movement_speed
- Movement speed in units/second (default: 2.5):mouse_sensitivity
- Mouse sensitivity multiplier (default: 0.005, adapted from LearnOpenGL's 0.1 for natural feel):zoom
- Field of view in degrees (default: 45.0)
Examples
# Default camera at origin
camera = EAGL.Camera.new()
# Camera at specific position
camera = EAGL.Camera.new(position: vec3(5.0, 2.0, 5.0))
# Custom camera configuration
camera = EAGL.Camera.new(
position: vec3(0.0, 5.0, 10.0),
yaw: 180.0,
pitch: -30.0,
movement_speed: 5.0,
mouse_sensitivity: 0.01
)
Process keyboard input for camera movement.
Moves the camera based on the specified direction and delta time. Movement is frame-rate independent when delta time is provided.
Parameters
camera
- The camera structdirection
- Movement direction (:forward
,:backward
,:left
,:right
)delta_time
- Time since last frame in seconds
Examples
# Forward movement (W key)
camera = EAGL.Camera.process_keyboard(camera, :forward, delta_time)
# Backward movement (S key)
camera = EAGL.Camera.process_keyboard(camera, :backward, delta_time)
# Strafe left (A key)
camera = EAGL.Camera.process_keyboard(camera, :left, delta_time)
# Strafe right (D key)
camera = EAGL.Camera.process_keyboard(camera, :right, delta_time)
Process mouse movement for camera look around.
Updates camera orientation based on mouse movement offsets. Constrains pitch to prevent camera flipping.
Parameters
camera
- The camera structx_offset
- Horizontal mouse movement offsety_offset
- Vertical mouse movement offsetconstrain_pitch
- Whether to constrain pitch (default: true)
Examples
# Typical mouse movement processing
camera = EAGL.Camera.process_mouse_movement(camera, x_offset, y_offset)
# Allow full pitch rotation (can cause gimbal lock)
camera = EAGL.Camera.process_mouse_movement(camera, x_offset, y_offset, false)
Process mouse scroll wheel input for zoom control.
Adjusts field of view based on scroll wheel movement. Constrains zoom to reasonable range (1.0 to 45.0 degrees).
Parameters
camera
- The camera structy_offset
- Scroll wheel offset (positive = zoom in, negative = zoom out)
Examples
# Zoom in (positive offset, smaller FOV)
camera = EAGL.Camera.process_mouse_scroll(camera, 1.0)
# Zoom out (negative offset, larger FOV)
camera = EAGL.Camera.process_mouse_scroll(camera, -1.0)