scimesh 0.3.4
Headless CPU-only 3D software renderer for scientific mesh visualization
Loading...
Searching...
No Matches
camera.cpp
Go to the documentation of this file.
1#include <scimesh/camera.h>
3#include <glm/gtc/matrix_transform.hpp>
4#include <glm/gtc/constants.hpp>
5#include <cmath>
6#include <stdexcept>
7
8namespace scimesh {
9
11 return glm::lookAt(eye, center, up);
12}
13
14Mat4 Camera::get_projection_matrix(float aspect_ratio, float near_plane, float far_plane) const {
16 if (aspect_ratio <= 0.0f) {
17 throw std::invalid_argument(
18 "aspect_ratio must be > 0 for perspective projection");
19 }
20 if (near_plane <= 0.0f) {
21 throw std::invalid_argument(
22 "near_plane must be > 0 for perspective projection");
23 }
24 if (far_plane <= near_plane) {
25 throw std::invalid_argument(
26 "far_plane must be > near_plane for perspective projection");
27 }
28 return glm::perspective(glm::radians(fov_degrees), aspect_ratio, near_plane, far_plane);
29 } else {
30 float dist = glm::length(eye - center);
31 if (dist < 1e-6f)
32 dist = 1.0f;
33 float half_h = dist;
34 float half_w = half_h * aspect_ratio;
35 return glm::ortho(-half_w, half_w, -half_h, half_h, near_plane, far_plane);
36 }
37}
38
39ProjectedPoint world_to_screen(const Camera &camera, const Vec3 &world, int width,
40 int height, ProjectionType projection,
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");
44 }
46
47 // Same matrices as the render pipeline: the render options decide the
48 // projection type, the camera only provides its position and framing.
49 Camera proj_cam = camera;
50 proj_cam.projection = projection;
51 const Mat4 view = camera.get_view_matrix();
52 const float aspect = static_cast<float>(width) / static_cast<float>(height);
53 const Mat4 projection_matrix =
54 proj_cam.get_projection_matrix(aspect, near_plane, far_plane);
55
56 const Vec4 clip = transform_point_homogeneous(projection_matrix * view, world);
57 if (clip.w <= 1e-6f) {
58 return out; // at or behind the camera plane: not visible
59 }
60
61 const Vec3 ndc = perspective_divide(clip);
62 float screen_x = 0.0f, screen_y = 0.0f, depth = 0.0f;
63 ndc_to_screen(ndc, width, height, screen_x, screen_y, depth);
64
65 out.pixel = Vec2(screen_x, screen_y);
66 out.depth = depth;
67 out.in_front = true;
68 return out;
69}
70
71Camera camera_look_at(const Vec3 &center, float radius,
72 const Vec3 &direction, const Vec3 &up,
73 float fov_degrees, float margin,
74 ProjectionType projection) {
75 Camera cam;
76 cam.center = center;
77 cam.up = glm::normalize(up);
78 cam.fov_degrees = fov_degrees;
79 cam.projection = projection;
80 float fov_rad = glm::radians(fov_degrees);
81 float dist;
82 if (projection == ProjectionType::ORTHOGRAPHIC) {
83 dist = radius * margin;
84 } else {
85 dist = radius / std::sin(fov_rad * 0.5f) * margin;
86 }
87 cam.eye = center + glm::normalize(direction) * dist;
88 return cam;
89}
90
91Camera camera_fit_scene(const Scene &scene, const Vec3 &direction,
92 const Vec3 &up, float fov_degrees, float margin,
93 ProjectionType projection) {
94 Vec3 bmin(0.0f), bmax(0.0f);
95 scene.compute_bounding_box(bmin, bmax);
96 Vec3 center = (bmin + bmax) * 0.5f;
97 Vec3 dir = glm::normalize(direction);
98 if (projection == ProjectionType::ORTHOGRAPHIC) {
99 float extent = max_ortho_extent(bmin, bmax, center, dir);
100 return camera_look_at(center, extent, direction, up, fov_degrees, margin, projection);
101 } else {
102 float radius = perp_extent_radius(bmin, bmax, center, dir,
103 glm::radians(fov_degrees));
104 return camera_look_at(center, radius, direction, up, fov_degrees, margin, projection);
105 }
106}
107
108Camera camera_fit_mesh(const Mesh &mesh, const Vec3 &direction,
109 const Vec3 &up, float fov_degrees, float margin,
110 ProjectionType projection) {
111 Vec3 bmin(0.0f), bmax(0.0f);
112 mesh.compute_bounding_box(bmin, bmax);
113 Vec3 center = (bmin + bmax) * 0.5f;
114 Vec3 dir = glm::normalize(direction);
115 if (projection == ProjectionType::ORTHOGRAPHIC) {
116 float extent = max_ortho_extent(bmin, bmax, center, dir);
117 return camera_look_at(center, extent, direction, up, fov_degrees, margin, projection);
118 } else {
119 float radius = perp_extent_radius(bmin, bmax, center, dir,
120 glm::radians(fov_degrees));
121 return camera_look_at(center, radius, direction, up, fov_degrees, margin, projection);
122 }
123}
124
125Camera camera_orbit(const Camera &camera, const Vec3 &axis, float angle_degrees) {
126 Camera result = camera;
127 float angle_rad = glm::radians(angle_degrees);
128 Mat4 rotation = glm::rotate(Mat4(1.0f), angle_rad, axis);
129 Vec4 rotated_dir = rotation * Vec4(camera.eye - camera.center, 0.0f);
130 result.eye = camera.center + Vec3(rotated_dir);
131 Vec4 rotated_up = rotation * Vec4(camera.up, 0.0f);
132 result.up = glm::normalize(Vec3(rotated_up));
133 return result;
134}
135
136} // namespace scimesh
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).
Definition types.h:32
Camera camera_look_at(const Vec3 &center, 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.
Definition camera.cpp:71
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.
Definition math_utils.h:125
glm::mat4 Mat4
4×4 floating-point matrix.
Definition types.h:65
glm::vec3 Vec3
3-component floating-point vector (xyz).
Definition types.h:46
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.
Definition camera.cpp:91
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.
Definition camera.cpp:108
ProjectionType
The type of 3D→2D projection used by the camera.
Definition camera.h:23
@ 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 &center, 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...
Definition camera.h:207
float max_ortho_extent(const Vec3 &bmin, const Vec3 &bmax, const Vec3 &center, const Vec3 &dir)
Compute the maximum perpendicular extent of an AABB from a view ray (for orthographic projection fram...
Definition camera.h:254
Camera camera_orbit(const Camera &camera, const Vec3 &axis, float angle_degrees)
Orbit the camera around its look-at point.
Definition camera.cpp:125
Vec3 perspective_divide(const Vec4 &clip)
Perform perspective division: divide xyz by w.
Definition math_utils.h:105
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.
Definition camera.cpp:39
Vec4 transform_point_homogeneous(const Mat4 &m, const Vec3 &p)
Transform a point by a 4×4 matrix, returning the full Vec4 result.
Definition math_utils.h:75
glm::vec4 Vec4
4-component floating-point vector (xyzw).
Definition types.h:52
float width
Definition renderer.cpp:36
A virtual camera that defines the viewpoint for rendering.
Definition camera.h:77
Mat4 get_view_matrix() const
Compute the view matrix (world → camera space).
Definition camera.cpp:10
ProjectionType projection
Which projection type to use.
Definition camera.h:99
Vec3 center
The point the camera looks at.
Definition camera.h:88
Vec3 up
The camera's "up" direction.
Definition camera.h:94
Vec3 eye
Camera position in world space.
Definition camera.h:82
float fov_degrees
Vertical field of view in degrees (perspective only).
Definition camera.h:109
Mat4 get_projection_matrix(float aspect_ratio, float near_plane, float far_plane) const
Compute the projection matrix (camera → clip space).
Definition camera.cpp:14
A 3D triangle mesh using an indexed face set representation.
Definition mesh.h:76
void compute_bounding_box(Vec3 &min_bound, Vec3 &max_bound) const
Compute the axis-aligned bounding box (AABB) of the mesh.
Definition mesh.h:350
A world-space point projected into the rendered image.
Definition camera.h:135
bool in_front
Whether the point is in front of the camera.
Definition camera.h:149
float depth
Depth in normalized device coordinates, in [-1, 1]; smaller values are closer to the camera.
Definition camera.h:143
Vec2 pixel
Pixel coordinates, origin at the top left, y growing down.
Definition camera.h:137
A collection of Mesh objects to be rendered together.
Definition scene.h:69
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...
Definition scene.h:371