3#include <glm/gtc/matrix_transform.hpp>
4#include <glm/gtc/constants.hpp>
16 if (aspect_ratio <= 0.0f) {
17 throw std::invalid_argument(
18 "aspect_ratio must be > 0 for perspective projection");
20 if (near_plane <= 0.0f) {
21 throw std::invalid_argument(
22 "near_plane must be > 0 for perspective projection");
24 if (far_plane <= near_plane) {
25 throw std::invalid_argument(
26 "far_plane must be > near_plane for perspective projection");
28 return glm::perspective(glm::radians(
fov_degrees), aspect_ratio, near_plane, far_plane);
34 float half_w = half_h * aspect_ratio;
35 return glm::ortho(-half_w, half_w, -half_h, half_h, near_plane, far_plane);
41 float near_plane,
float far_plane) {
42 if (
width <= 0 || height <= 0) {
43 throw std::invalid_argument(
"world_to_screen: width and height must be > 0");
52 const float aspect =
static_cast<float>(
width) /
static_cast<float>(height);
53 const Mat4 projection_matrix =
57 if (clip.w <= 1e-6f) {
62 float screen_x = 0.0f, screen_y = 0.0f, depth = 0.0f;
72 const Vec3 &direction,
const Vec3 &up,
73 float fov_degrees,
float margin,
77 cam.
up = glm::normalize(up);
80 float fov_rad = glm::radians(fov_degrees);
83 dist = radius * margin;
85 dist = radius / std::sin(fov_rad * 0.5f) * margin;
87 cam.
eye = center + glm::normalize(direction) * dist;
92 const Vec3 &up,
float fov_degrees,
float margin,
94 Vec3 bmin(0.0f), bmax(0.0f);
96 Vec3 center = (bmin + bmax) * 0.5f;
97 Vec3 dir = glm::normalize(direction);
100 return camera_look_at(center, extent, direction, up, fov_degrees, margin, projection);
103 glm::radians(fov_degrees));
104 return camera_look_at(center, radius, direction, up, fov_degrees, margin, projection);
109 const Vec3 &up,
float fov_degrees,
float margin,
111 Vec3 bmin(0.0f), bmax(0.0f);
113 Vec3 center = (bmin + bmax) * 0.5f;
114 Vec3 dir = glm::normalize(direction);
117 return camera_look_at(center, extent, direction, up, fov_degrees, margin, projection);
120 glm::radians(fov_degrees));
121 return camera_look_at(center, radius, direction, up, fov_degrees, margin, projection);
127 float angle_rad = glm::radians(angle_degrees);
128 Mat4 rotation = glm::rotate(
Mat4(1.0f), angle_rad, axis);
131 Vec4 rotated_up = rotation *
Vec4(camera.
up, 0.0f);
132 result.
up = glm::normalize(
Vec3(rotated_up));
Camera definition and helper functions for view setup.
Low-level math utilities for the rendering pipeline.
glm::vec2 Vec2
2-component floating-point vector (xy).
Camera camera_look_at(const Vec3 ¢er, float radius, const Vec3 &direction, const Vec3 &up, float fov_degrees, float margin, ProjectionType projection)
Create a camera that looks at a point from a given distance and direction.
void ndc_to_screen(const Vec3 &ndc, int width, int height, float &screen_x, float &screen_y, float &depth)
Convert from normalized device coordinates (NDC) to screen (pixel) coordinates.
glm::mat4 Mat4
4×4 floating-point matrix.
glm::vec3 Vec3
3-component floating-point vector (xyz).
Camera camera_fit_scene(const Scene &scene, const Vec3 &direction, const Vec3 &up, float fov_degrees, float margin, ProjectionType projection)
Create a camera that automatically frames an entire Scene.
Camera camera_fit_mesh(const Mesh &mesh, const Vec3 &direction, const Vec3 &up, float fov_degrees, float margin, ProjectionType projection)
Create a camera that automatically frames a single Mesh.
ProjectionType
The type of 3D→2D projection used by the camera.
@ ORTHOGRAPHIC
Orthographic projection: parallel lines stay parallel.
@ PERSPECTIVE
Perspective projection: objects farther away appear smaller.
float perp_extent_radius(const Vec3 &bmin, const Vec3 &bmax, const Vec3 ¢er, const Vec3 &dir, float fov_radians, float *out_dist=nullptr)
Compute the "perpendicular extent radius" of an axis-aligned bounding box relative to a view directio...
float max_ortho_extent(const Vec3 &bmin, const Vec3 &bmax, const Vec3 ¢er, const Vec3 &dir)
Compute the maximum perpendicular extent of an AABB from a view ray (for orthographic projection fram...
Camera camera_orbit(const Camera &camera, const Vec3 &axis, float angle_degrees)
Orbit the camera around its look-at point.
Vec3 perspective_divide(const Vec4 &clip)
Perform perspective division: divide xyz by w.
ProjectedPoint world_to_screen(const Camera &camera, const Vec3 &world, int width, int height, ProjectionType projection, float near_plane, float far_plane)
Project a world-space point to the pixel coordinates of a rendered image.
Vec4 transform_point_homogeneous(const Mat4 &m, const Vec3 &p)
Transform a point by a 4×4 matrix, returning the full Vec4 result.
glm::vec4 Vec4
4-component floating-point vector (xyzw).
A virtual camera that defines the viewpoint for rendering.
Mat4 get_view_matrix() const
Compute the view matrix (world → camera space).
ProjectionType projection
Which projection type to use.
Vec3 center
The point the camera looks at.
Vec3 up
The camera's "up" direction.
Vec3 eye
Camera position in world space.
float fov_degrees
Vertical field of view in degrees (perspective only).
Mat4 get_projection_matrix(float aspect_ratio, float near_plane, float far_plane) const
Compute the projection matrix (camera → clip space).
A 3D triangle mesh using an indexed face set representation.
void compute_bounding_box(Vec3 &min_bound, Vec3 &max_bound) const
Compute the axis-aligned bounding box (AABB) of the mesh.
A world-space point projected into the rendered image.
bool in_front
Whether the point is in front of the camera.
float depth
Depth in normalized device coordinates, in [-1, 1]; smaller values are closer to the camera.
Vec2 pixel
Pixel coordinates, origin at the top left, y growing down.
A collection of Mesh objects to be rendered together.
void compute_bounding_box(Vec3 &min_bound, Vec3 &max_bound) const
Compute the combined axis-aligned bounding box of all meshes, after applying each mesh's placement tr...