scimesh 0.3.2
Headless CPU-only 3D software renderer for scientific mesh visualization
Loading...
Searching...
No Matches
math_utils.h
Go to the documentation of this file.
1
7
8#pragma once
9
10#include <scimesh/types.h>
11#include <glm/gtc/matrix_transform.hpp>
12#include <algorithm>
13
14namespace scimesh {
15
16// ---------------------------------------------------------------------------
17// Geometry
18// ---------------------------------------------------------------------------
19
37inline Vec3 compute_face_normal(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2) {
38 Vec3 edge1 = v1 - v0;
39 Vec3 edge2 = v2 - v0;
40 Vec3 normal = glm::cross(edge1, edge2);
41 float len = glm::length(normal);
42 if (len < 1e-12f)
43 return Vec3(0.0f, 0.0f, 1.0f);
44 return normal / len;
45}
46
47// ---------------------------------------------------------------------------
48// Transform helpers
49// ---------------------------------------------------------------------------
50
60inline Vec3 transform_point(const Mat4 &m, const Vec3 &p) {
61 Vec4 result = m * Vec4(p, 1.0f);
62 return Vec3(result);
63}
64
75inline Vec4 transform_point_homogeneous(const Mat4 &m, const Vec3 &p) {
76 return m * Vec4(p, 1.0f);
77}
78
90inline Vec3 transform_direction(const Mat4 &m, const Vec3 &d) {
91 Vec4 result = m * Vec4(d, 0.0f);
92 return Vec3(result);
93}
94
105inline Vec3 perspective_divide(const Vec4 &clip) {
106 if (std::abs(clip.w) < 1e-12f)
107 return Vec3(clip.x, clip.y, clip.z);
108 return Vec3(clip.x / clip.w, clip.y / clip.w, clip.z / clip.w);
109}
110
125inline void ndc_to_screen(const Vec3 &ndc, int width, int height,
126 float &screen_x, float &screen_y, float &depth) {
127 screen_x = (ndc.x + 1.0f) * 0.5f * static_cast<float>(width);
128 screen_y = (1.0f - ndc.y) * 0.5f * static_cast<float>(height);
129 depth = ndc.z;
130}
131
132// ---------------------------------------------------------------------------
133// Barycentric coordinates
134// ---------------------------------------------------------------------------
135
158inline void compute_barycentric(float px, float py,
159 float x0, float y0,
160 float x1, float y1,
161 float x2, float y2,
162 float &u, float &v, float &w) {
163 float det = (y2 - y0) * (x1 - x0) - (x2 - x0) * (y1 - y0);
164 if (std::abs(det) < 1e-12f) {
165 u = v = w = 0.0f;
166 return;
167 }
168 float inv_det = 1.0f / det;
169 u = ((y1 - y2) * (px - x2) + (x2 - x1) * (py - y2)) * inv_det;
170 v = ((y2 - y0) * (px - x2) - (x2 - x0) * (py - y2)) * inv_det;
171 w = 1.0f - u - v;
172}
173
174// ---------------------------------------------------------------------------
175// Shading
176// ---------------------------------------------------------------------------
177
191inline Color shade_pixel(const Color &base_color, const Vec3 &normal,
192 const Vec3 &light_direction,
193 const Color &specular_color = Color(0, 0, 0, 0),
194 float shininess = 0.0f) {
195 Vec3 n = glm::length(normal) > 1e-12f ? glm::normalize(normal) : Vec3(0.0f, 0.0f, 1.0f);
196 Vec3 l = glm::normalize(light_direction);
197 float ndotl = std::max(0.0f, glm::dot(n, l));
198 float ambient = 0.3f;
199 float diffuse_term = (1.0f - ambient) * ndotl;
200 float intensity = ambient + diffuse_term;
201
202 float spec_r = 0.0f, spec_g = 0.0f, spec_b = 0.0f;
203 if (shininess > 0.0f && ndotl > 0.0f) {
204 float spec = std::pow(ndotl, shininess);
205 spec_r = specular_color.r * spec;
206 spec_g = specular_color.g * spec;
207 spec_b = specular_color.b * spec;
208 }
209
210 return Color(base_color.r * intensity + spec_r,
211 base_color.g * intensity + spec_g,
212 base_color.b * intensity + spec_b,
213 base_color.a);
214}
215
231inline Color shade_pixel_multi(const Color &base_color, const Vec3 &normal,
232 const std::vector<Light> &lights,
233 float ambient,
234 const Color &specular_color = Color(0, 0, 0, 0),
235 float shininess = 0.0f) {
236 Vec3 n = glm::length(normal) > 1e-12f ? glm::normalize(normal) : Vec3(0.0f, 0.0f, 1.0f);
237
238 float total_r = base_color.r * ambient;
239 float total_g = base_color.g * ambient;
240 float total_b = base_color.b * ambient;
241
242 int nlights = static_cast<int>(lights.size());
243 if (nlights == 0) return Color(total_r, total_g, total_b, base_color.a);
244
245 for (int i = 0; i < nlights; i++) {
246 const Light &light = lights[i];
247 Vec3 light_dir = glm::normalize(light.position);
248 float ndotl = std::max(0.0f, glm::dot(n, light_dir));
249 float li = light.intensity / static_cast<float>(nlights);
250 float diff = (1.0f - ambient) * ndotl * li;
251 total_r += base_color.r * diff * light.color.r;
252 total_g += base_color.g * diff * light.color.g;
253 total_b += base_color.b * diff * light.color.b;
254
255 if (shininess > 0.0f && ndotl > 0.0f) {
256 float spec = std::pow(ndotl, shininess) * li;
257 total_r += specular_color.r * spec * light.color.r;
258 total_g += specular_color.g * spec * light.color.g;
259 total_b += specular_color.b * spec * light.color.b;
260 }
261 }
262
263 return Color(std::min(total_r, 1.0f), std::min(total_g, 1.0f),
264 std::min(total_b, 1.0f), base_color.a);
265}
266
267} // namespace scimesh
void compute_barycentric(float px, float py, float x0, float y0, float x1, float y1, float x2, float y2, float &u, float &v, float &w)
Compute barycentric coordinates (u, v, w) of a point in a triangle.
Definition math_utils.h:158
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
Vec3 transform_direction(const Mat4 &m, const Vec3 &d)
Transform a direction vector by a 4×4 matrix (with implicit w=0).
Definition math_utils.h:90
Vec3 compute_face_normal(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2)
Compute the unit-length normal vector of a triangle face.
Definition math_utils.h:37
Color shade_pixel(const Color &base_color, const Vec3 &normal, const Vec3 &light_direction, const Color &specular_color=Color(0, 0, 0, 0), float shininess=0.0f)
Compute the shaded color of a pixel with a single directional light.
Definition math_utils.h:191
Color shade_pixel_multi(const Color &base_color, const Vec3 &normal, const std::vector< Light > &lights, float ambient, const Color &specular_color=Color(0, 0, 0, 0), float shininess=0.0f)
Compute the shaded color with multiple light sources.
Definition math_utils.h:231
Vec3 transform_point(const Mat4 &m, const Vec3 &p)
Transform a point by a 4×4 matrix (with implicit w=1).
Definition math_utils.h:60
Vec3 perspective_divide(const Vec4 &clip)
Perform perspective division: divide xyz by w.
Definition math_utils.h:105
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
An RGBA color with floating-point components.
Definition types.h:88
float g
Green channel, [0, 1].
Definition types.h:90
float r
Red channel, [0, 1].
Definition types.h:89
float b
Blue channel, [0, 1].
Definition types.h:91
float a
Alpha (opacity) channel, [0, 1]. 1.0 = fully opaque.
Definition types.h:92
A light source for the Blinn-Phong shading model.
Definition types.h:179
Color color
Color of the light (default: white).
Definition types.h:189
Vec3 position
Position of the light.
Definition types.h:184
float intensity
Brightness multiplier (default: 1.0).
Definition types.h:194
Fundamental types used throughout the scimesh rendering engine.