EAGL.Camera (eagl v0.8.0)

View Source

Camera 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 scroll wheel input for zoom control.

Types

mat4()

@type mat4() :: EAGL.Math.mat4()

movement_direction()

@type movement_direction() :: :forward | :backward | :left | :right

t()

@type t() :: %EAGL.Camera{
  front: vec3(),
  mouse_sensitivity: float(),
  movement_speed: float(),
  pitch: float(),
  position: vec3(),
  right: vec3(),
  up: vec3(),
  world_up: vec3(),
  yaw: float(),
  zoom: float()
}

vec3()

@type vec3() :: EAGL.Math.vec3()

Functions

get_view_matrix(camera)

@spec get_view_matrix(t()) :: mat4()

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)

new(opts \\ [])

@spec new(keyword()) :: t()

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(camera, direction, delta_time)

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 struct
  • direction - 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(camera, x_offset, y_offset, constrain_pitch \\ true)

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 struct
  • x_offset - Horizontal mouse movement offset
  • y_offset - Vertical mouse movement offset
  • constrain_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(camera, y_offset)

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 struct
  • y_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)