scimesh 0.3.2
Headless CPU-only 3D software renderer for scientific mesh visualization
Loading...
Searching...
No Matches
renderer.cpp
Go to the documentation of this file.
1#include <scimesh/renderer.h>
3#include <scimesh/normals.h>
4#include <scimesh/clipping.h>
6#include <glm/glm.hpp>
7#include <glm/gtc/matrix_transform.hpp>
8#include <algorithm>
9#include <stdexcept>
10#include <string>
11
12#ifdef _OPENMP
13#include <omp.h>
14#endif
15
16namespace scimesh {
17
18namespace {
19
20struct DeferredTri {
25 bool smooth;
26 float view_z; // centroid depth in view space, for back-to-front sort
27};
28
29} // anonymous namespace
30
31Image Renderer::render_mesh(const Mesh &mesh, const Camera &camera, const RenderOptions &options) {
32 if (options.width <= 0 || options.height <= 0) {
33 throw std::invalid_argument("RenderOptions width and height must be > 0");
34 }
35 int aa = std::max(1, options.aa_samples);
36 Image internal(options.width * aa, options.height * aa);
37 std::vector<SceneNodeRef> nodes;
38 nodes.push_back({&mesh, Mat4(1.0f), ""});
39 render_pipeline(nodes, camera, options, internal);
40 return internal.downsample_box(aa);
41}
42
43Image Renderer::render_scene(const Scene &scene, const Camera &camera, const RenderOptions &options) {
44 if (options.width <= 0 || options.height <= 0) {
45 throw std::invalid_argument("RenderOptions width and height must be > 0");
46 }
47 int aa = std::max(1, options.aa_samples);
48 Image internal(options.width * aa, options.height * aa);
49 std::vector<SceneNodeRef> nodes = scene.nodes();
50 render_pipeline(nodes, camera, options, internal);
51 return internal.downsample_box(aa);
52}
53
54Image Renderer::render_triangles_raw(const std::vector<Vec3> &positions,
55 const std::vector<Color> &colors,
56 const Camera &camera,
57 const RenderOptions &options) {
58 Mesh mesh;
59 mesh.vertices = positions;
60 mesh.colors = colors;
61 int nv = static_cast<int>(positions.size());
62 for (int i = 0; i < nv / 3; i++) {
63 mesh.triangles.push_back({
64 static_cast<uint32_t>(i * 3),
65 static_cast<uint32_t>(i * 3 + 1),
66 static_cast<uint32_t>(i * 3 + 2)});
67 }
68 for (const auto &c : colors) {
69 if (c.a < 1.0f - 1e-6f) {
70 mesh.has_transparency = true;
71 break;
72 }
73 }
74 return render_mesh(mesh, camera, options);
75}
76
77Image Renderer::render_points_raw(const std::vector<Vec3> &positions,
78 const std::vector<Color> &colors,
79 float radius,
80 const Camera &camera,
81 const RenderOptions &options) {
82 if (options.width <= 0 || options.height <= 0) {
83 throw std::invalid_argument("RenderOptions width and height must be > 0");
84 }
85 int np = static_cast<int>(positions.size());
86 if (np == 0 || colors.empty()) {
87 Image img(options.width, options.height);
88 img.clear_float(options.background_color.r, options.background_color.g,
89 options.background_color.b, options.background_color.a);
90 return img;
91 }
92
93 int aa = std::max(1, options.aa_samples);
94 Image output(options.width * aa, options.height * aa);
95 output.clear_float(options.background_color.r, options.background_color.g,
96 options.background_color.b, options.background_color.a);
97
98 Rasterizer rasterizer(output.width, output.height);
99 rasterizer.clear(1.0f);
100 rasterizer.specular_color = options.specular_color;
101 rasterizer.shininess = options.shininess;
102 rasterizer.lights = options.lights;
103 rasterizer.ambient = options.ambient;
104 rasterizer.fog_enabled = options.fog_enabled;
105 rasterizer.fog_start = options.fog_start;
106 rasterizer.fog_end = options.fog_end;
107 rasterizer.fog_color = options.fog_color;
108 rasterizer.ssao_enabled = options.ssao_enabled;
109 rasterizer.ssao_radius = options.ssao_radius;
110 rasterizer.ssao_intensity = options.ssao_intensity;
111
112#ifdef _OPENMP
113 if (options.threads > 0) omp_set_num_threads(options.threads);
114#endif
115
116 Mat4 view = camera.get_view_matrix();
117 float aspect = static_cast<float>(output.width) / static_cast<float>(output.height);
118 Camera proj_cam = camera;
119 proj_cam.projection = options.projection;
120 Mat4 projection = proj_cam.get_projection_matrix(aspect, options.near_plane, options.far_plane);
121 Mat4 view_projection = projection * view;
122
123 Vec3 light_direction = Vec3(0.0f, 0.0f, 1.0f);
124 if (!options.lights.empty()) {
125 light_direction = options.lights[0].position;
126 light_direction = glm::normalize(transform_direction(view, light_direction));
127 }
128
129 float aa_radius = radius * static_cast<float>(aa);
130
131 for (int i = 0; i < np; i++) {
132 Vec4 clip_pos = transform_point_homogeneous(view_projection, positions[i]);
133 Vec3 ndc = perspective_divide(clip_pos);
134 float sx, sy, sz;
135 ndc_to_screen(ndc, output.width, output.height, sx, sy, sz);
136
137 Vec3 normal(0.0f, 0.0f, 1.0f);
138 rasterizer.rasterize_point(sx, sy, sz, aa_radius, colors[i],
139 normal, light_direction, output);
140 }
141
142 if (rasterizer.ssao_enabled) {
143 rasterizer.apply_ssao(output, options.near_plane, options.far_plane);
144 }
145
146 return output.downsample_box(aa);
147}
148
149void Renderer::render_pipeline(const std::vector<SceneNodeRef> &nodes,
150 const Camera &camera,
151 const RenderOptions &options,
152 Image &output) {
153 // Validate all non-empty meshes before rendering
154 for (size_t i = 0; i < nodes.size(); ++i) {
155 const auto *mp = nodes[i].mesh;
156 if (mp->empty()) continue; // empty is harmless
157 if (!mp->is_valid()) {
158 throw std::invalid_argument(
159 "Mesh " + std::to_string(i) + " failed validation: "
160 "check indices, vertex data, and array sizes");
161 }
162 }
163 output.clear_float(options.background_color.r, options.background_color.g,
164 options.background_color.b, options.background_color.a);
165
166 Rasterizer rasterizer(output.width, output.height);
167 rasterizer.clear(1.0f);
168 rasterizer.specular_color = options.specular_color;
169 rasterizer.shininess = options.shininess;
170 rasterizer.lights = options.lights;
171 rasterizer.ambient = options.ambient;
172 rasterizer.contrast = options.contrast;
173 rasterizer.fog_enabled = options.fog_enabled;
174 rasterizer.fog_start = options.fog_start;
175 rasterizer.fog_end = options.fog_end;
176 rasterizer.fog_color = options.fog_color;
177 rasterizer.ssao_enabled = options.ssao_enabled;
178 rasterizer.ssao_radius = options.ssao_radius;
179 rasterizer.ssao_intensity = options.ssao_intensity;
180
181#ifdef _OPENMP
182 if (options.threads > 0) omp_set_num_threads(options.threads);
183#endif
184
185 Mat4 view = camera.get_view_matrix();
186
187 for (auto &light : rasterizer.lights) {
188 light.position = glm::normalize(transform_direction(view, light.position));
189 }
190 float aspect = static_cast<float>(output.width) / static_cast<float>(output.height);
191 Camera proj_cam = camera;
192 proj_cam.projection = options.projection;
193 Mat4 projection = proj_cam.get_projection_matrix(aspect, options.near_plane, options.far_plane);
194 Mat4 view_projection = projection * view;
195
196 std::vector<ClipPlane> view_clip_planes = options.clip_planes;
197 for (auto &cp : view_clip_planes) {
198 cp.normal = glm::normalize(transform_direction(view, cp.normal));
199 }
200
201 Vec3 light_direction = Vec3(0.0f, 0.0f, 1.0f);
202
203 bool scene_has_transparency = false;
204 for (const auto &nd : nodes) {
205 if (nd.mesh->has_transparency) { scene_has_transparency = true; break; }
206 }
207
208 std::vector<DeferredTri> deferred;
209
210 for (const auto &node : nodes) {
211 const Mesh &mesh = *node.mesh;
212 if (mesh.empty()) continue;
213
214 // Placement transform for this mesh (model matrix in world space).
215 const Mat4 &model = node.transform;
216 const Mat4 view_model = view * model;
217 const Mat4 view_proj_model = view_projection * model;
218
219 if (mesh.has_uvs() && mesh.has_texture()) {
220 rasterizer.active_texture = const_cast<Image *>(&mesh.texture);
221 } else {
222 rasterizer.active_texture = nullptr;
223 }
224
225 std::vector<Vec3> computed_normals;
226 const std::vector<Vec3> *normals_ptr;
227 if (mesh.has_normals()) {
228 normals_ptr = &mesh.normals;
229 } else {
230 compute_vertex_normals(mesh, computed_normals);
231 normals_ptr = &computed_normals;
232 }
233
234 std::vector<Vec3> view_normals(normals_ptr->size());
235 for (size_t i = 0; i < normals_ptr->size(); ++i) {
236 Vec3 n = (*normals_ptr)[i];
237 if (options.invert_normals) n = -n;
238 view_normals[i] = glm::normalize(
240 }
241
242 for (int ti = 0; ti < static_cast<int>(mesh.triangles.size()); ++ti) {
243 const auto &tri = mesh.triangles[ti];
244 Vec3 v0 = mesh.vertices[tri.v0];
245 Vec3 v1 = mesh.vertices[tri.v1];
246 Vec3 v2 = mesh.vertices[tri.v2];
247
248 Color c0, c1, c2;
249 if (mesh.has_face_colors()) {
250 c0 = c1 = c2 = mesh.face_colors[ti];
251 } else if (mesh.has_colors()) {
252 c0 = mesh.colors[tri.v0];
253 c1 = mesh.colors[tri.v1];
254 c2 = mesh.colors[tri.v2];
255 } else {
256 c0 = c1 = c2 = options.default_color;
257 }
258
259 Vec3 n0 = view_normals[tri.v0];
260 Vec3 n1 = view_normals[tri.v1];
261 Vec3 n2 = view_normals[tri.v2];
262
263 Vec2 uv0 = mesh.has_uvs() ? mesh.uvs[tri.v0] : Vec2(0, 0);
264 Vec2 uv1 = mesh.has_uvs() ? mesh.uvs[tri.v1] : Vec2(0, 0);
265 Vec2 uv2 = mesh.has_uvs() ? mesh.uvs[tri.v2] : Vec2(0, 0);
266
267 bool tri_transparent = scene_has_transparency &&
268 (c0.a < 1.0f - 1e-6f || c1.a < 1.0f - 1e-6f || c2.a < 1.0f - 1e-6f);
269
270 ClipVertex cv0, cv1, cv2;
271 cv0.position = transform_point_homogeneous(view_proj_model, v0);
272 cv0.color = c0; cv0.normal = n0; cv0.uv = uv0;
273 cv1.position = transform_point_homogeneous(view_proj_model, v1);
274 cv1.color = c1; cv1.normal = n1; cv1.uv = uv1;
275 cv2.position = transform_point_homogeneous(view_proj_model, v2);
276 cv2.color = c2; cv2.normal = n2; cv2.uv = uv2;
277
278 bool has_user_clips = !view_clip_planes.empty();
279
280 std::vector<ClipVertex> clipped_vertices;
281 std::vector<Triangle> clipped_triangles;
282
283 if (has_user_clips) {
284 Vec3 vv0 = transform_point(view_model, v0);
285 Vec3 vv1 = transform_point(view_model, v1);
286 Vec3 vv2 = transform_point(view_model, v2);
287
288 std::vector<ClipVertex> view_clipped;
289 std::vector<Triangle> view_clip_tris;
290 int vc_count = clip_triangle_view_plane(
291 vv0, vv1, vv2, n0, n1, n2, c0, c1, c2,
292 uv0, uv1, uv2,
293 view_clip_planes[0], view_clipped, view_clip_tris);
294
295 for (int ci = 1; ci < static_cast<int>(view_clip_planes.size()) && vc_count > 0; ++ci) {
296 std::vector<ClipVertex> next_vertices;
297 std::vector<Triangle> next_triangles;
298 for (const auto &vt : view_clip_tris) {
299 const ClipVertex &a = view_clipped[vt.v0];
300 const ClipVertex &b = view_clipped[vt.v1];
301 const ClipVertex &c = view_clipped[vt.v2];
302 Vec3 pa(a.position.x, a.position.y, a.position.z);
303 Vec3 pb(b.position.x, b.position.y, b.position.z);
304 Vec3 pc(c.position.x, c.position.y, c.position.z);
305 Vec3 na(a.normal), nb(b.normal), nc(c.normal);
306 Color ca(a.color), cb(b.color), cc(c.color);
307 Vec2 ua(a.uv), ub(b.uv), uc(c.uv);
309 pa, pb, pc, na, nb, nc, ca, cb, cc,
310 ua, ub, uc,
311 view_clip_planes[ci], next_vertices, next_triangles);
312 }
313 view_clipped.swap(next_vertices);
314 view_clip_tris.swap(next_triangles);
315 vc_count = static_cast<int>(view_clip_tris.size());
316 if (vc_count == 0) break;
317 }
318
319 if (vc_count == 0) continue;
320
321 clipped_vertices.clear();
322 clipped_triangles.clear();
323 for (const auto &vt : view_clip_tris) {
324 const ClipVertex &a = view_clipped[vt.v0];
325 const ClipVertex &b = view_clipped[vt.v1];
326 const ClipVertex &c = view_clipped[vt.v2];
327
328 ClipVertex cva, cvb, cvc;
329 cva.position = projection * Vec4(a.position.x, a.position.y, a.position.z, 1.0f);
330 cva.color = a.color; cva.normal = a.normal;
331 cvb.position = projection * Vec4(b.position.x, b.position.y, b.position.z, 1.0f);
332 cvb.color = b.color; cvb.normal = b.normal;
333 cvc.position = projection * Vec4(c.position.x, c.position.y, c.position.z, 1.0f);
334 cvc.color = c.color; cvc.normal = c.normal;
335
336 int nc = clip_triangle_near_plane(cva, cvb, cvc,
337 clipped_vertices, clipped_triangles);
338 (void)nc;
339 }
340 if (clipped_triangles.empty()) continue;
341 } else {
342 clipped_vertices.clear();
343 clipped_triangles.clear();
344 int num_clipped = clip_triangle_near_plane(cv0, cv1, cv2,
345 clipped_vertices, clipped_triangles);
346 if (num_clipped == 0) continue;
347 }
348
349 bool smooth = (options.shading == ShadingMode::SMOOTH);
350
351 for (const auto &ct : clipped_triangles) {
352 const ClipVertex &cv_a = clipped_vertices[ct.v0];
353 const ClipVertex &cv_b = clipped_vertices[ct.v1];
354 const ClipVertex &cv_c = clipped_vertices[ct.v2];
355
356 Vec3 ndc0 = perspective_divide(cv_a.position);
357 Vec3 ndc1 = perspective_divide(cv_b.position);
358 Vec3 ndc2 = perspective_divide(cv_c.position);
359
360 float sx0, sy0, sz0, sx1, sy1, sz1, sx2, sy2, sz2;
361 ndc_to_screen(ndc0, output.width, output.height, sx0, sy0, sz0);
362 ndc_to_screen(ndc1, output.width, output.height, sx1, sy1, sz1);
363 ndc_to_screen(ndc2, output.width, output.height, sx2, sy2, sz2);
364
365 Vec3 screen_v0(sx0, sy0, sz0);
366 Vec3 screen_v1(sx1, sy1, sz1);
367 Vec3 screen_v2(sx2, sy2, sz2);
368
369 Vec3 flat_normal_a, flat_normal_b, flat_normal_c;
370 if (!smooth) {
371 Vec3 face_normal = compute_face_normal(
372 transform_point(view_model, mesh.vertices[tri.v0]),
373 transform_point(view_model, mesh.vertices[tri.v1]),
374 transform_point(view_model, mesh.vertices[tri.v2]));
375 flat_normal_a = flat_normal_b = flat_normal_c = face_normal;
376 }
377
378 const Vec3 &normal_a = smooth ? cv_a.normal : flat_normal_a;
379 const Vec3 &normal_b = smooth ? cv_b.normal : flat_normal_b;
380 const Vec3 &normal_c = smooth ? cv_c.normal : flat_normal_c;
381
382 if (tri_transparent) {
383 Vec3 centroid_vs = (transform_point(view_model, v0) +
384 transform_point(view_model, v1) +
385 transform_point(view_model, v2)) * (1.0f / 3.0f);
386 deferred.push_back({
388 cv_a.color, cv_b.color, cv_c.color,
389 normal_a, normal_b, normal_c,
390 cv_a.uv, cv_b.uv, cv_c.uv,
391 smooth, centroid_vs.z
392 });
393 } else {
394 rasterizer.rasterize_triangle(
395 screen_v0, cv_a.color, normal_a, cv_a.uv,
396 screen_v1, cv_b.color, normal_b, cv_b.uv,
397 screen_v2, cv_c.color, normal_c, cv_c.uv,
398 options.backface_culling, smooth,
399 light_direction,
400 options.wireframe, options.wireframe_color,
401 output);
402 }
403 }
404 }
405 }
406
407 if (rasterizer.ssao_enabled) {
408 rasterizer.apply_ssao(output, options.near_plane, options.far_plane);
409 }
410
411 if (!deferred.empty()) {
412 std::sort(deferred.begin(), deferred.end(),
413 [](const DeferredTri &a, const DeferredTri &b) {
414 return a.view_z > b.view_z;
415 });
416
417 rasterizer.set_blend_mode(true);
418
419 for (const auto &dt : deferred) {
420 rasterizer.rasterize_triangle(
421 dt.screen_v0, dt.color0, dt.normal0, dt.uv0,
422 dt.screen_v1, dt.color1, dt.normal1, dt.uv1,
423 dt.screen_v2, dt.color2, dt.normal2, dt.uv2,
424 options.backface_culling, dt.smooth,
425 light_direction,
426 options.wireframe, options.wireframe_color,
427 output);
428 }
429
430 rasterizer.set_blend_mode(false);
431 }
432}
433
434} // namespace scimesh
Image render_mesh(const Mesh &mesh, const Camera &camera, const RenderOptions &options)
Render a single mesh to an image.
Definition renderer.cpp:31
Image render_scene(const Scene &scene, const Camera &camera, const RenderOptions &options)
Render a scene (collection of meshes) to an image.
Definition renderer.cpp:43
Image render_points_raw(const std::vector< Vec3 > &positions, const std::vector< Color > &colors, float radius, const Camera &camera, const RenderOptions &options)
Render a point cloud (spheres at each position) to an image.
Definition renderer.cpp:77
Image render_triangles_raw(const std::vector< Vec3 > &positions, const std::vector< Color > &colors, const Camera &camera, const RenderOptions &options)
Render raw triangles (no Mesh wrapper) to an image.
Definition renderer.cpp:54
Triangle clipping against planes (view frustum and clip planes).
Low-level math utilities for the rendering pipeline.
glm::vec2 Vec2
2-component floating-point vector (xy).
Definition types.h:32
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
void compute_vertex_normals(const Mesh &mesh, std::vector< Vec3 > &normals)
Compute per-vertex normals by averaging adjacent face normals.
Definition normals.cpp:5
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
int clip_triangle_view_plane(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, const Vec3 &n0, const Vec3 &n1, const Vec3 &n2, const Color &c0, const Color &c1, const Color &c2, const Vec2 &uv0, const Vec2 &uv1, const Vec2 &uv2, const ClipPlane &plane, std::vector< ClipVertex > &output_vertices, std::vector< Triangle > &output_triangles)
Clip a triangle against an arbitrary plane in view space.
Definition clipping.cpp:162
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
int clip_triangle_near_plane(const ClipVertex &v0, const ClipVertex &v1, const ClipVertex &v2, std::vector< ClipVertex > &output_vertices, std::vector< Triangle > &output_triangles)
Clip a triangle against the near clipping plane in clip space.
Definition clipping.cpp:67
@ SMOOTH
Smooth (Gouraud) shading: normals are interpolated across each triangle, producing a smooth,...
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
Compute per-vertex surface normals for lighting.
The Rasterizer — the per-pixel rendering engine.
Vec3 normal2
Definition renderer.cpp:23
Vec3 screen_v2
Definition renderer.cpp:21
bool smooth
Definition renderer.cpp:25
float view_z
Definition renderer.cpp:26
Vec3 normal1
Definition renderer.cpp:23
Vec3 normal0
Definition renderer.cpp:23
Vec3 screen_v1
Definition renderer.cpp:21
Vec2 uv1
Definition renderer.cpp:24
Color color0
Definition renderer.cpp:22
Vec2 uv0
Definition renderer.cpp:24
Color color1
Definition renderer.cpp:22
Vec3 screen_v0
Definition renderer.cpp:21
Vec2 uv2
Definition renderer.cpp:24
Color color2
Definition renderer.cpp:22
The Renderer — the main entry point for drawing meshes to images.
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:9
ProjectionType projection
Which projection type to use.
Definition camera.h:99
Mat4 get_projection_matrix(float aspect_ratio, float near_plane, float far_plane) const
Compute the projection matrix (camera → clip space).
Definition camera.cpp:13
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 2D RGBA image buffer.
Definition image.h:87
int height
Image height in pixels.
Definition image.h:92
int width
Image width in pixels.
Definition image.h:89
void clear_float(float r, float g, float b, float a)
Fill the entire image with an RGBA color (float values 0.0–1.0).
Definition image.cpp:70
Image downsample_box(int factor) const
Downsample the image by a factor using box filtering.
Definition image.cpp:77
A 3D triangle mesh using an indexed face set representation.
Definition mesh.h:76
bool has_transparency
Whether the mesh contains any transparent fragments.
Definition mesh.h:166
std::vector< Color > colors
Per-vertex RGBA colors.
Definition mesh.h:107
std::vector< Vec3 > vertices
3D vertex positions.
Definition mesh.h:86
std::vector< Triangle > triangles
Triangle index triplets.
Definition mesh.h:94
Low-level triangle rasterizer with depth buffering and lighting.
Definition rasterizer.h:45
float ssao_radius
SSAO sample radius in pixels (default: 16).
Definition rasterizer.h:148
void clear(float clear_depth=1.0f)
Clear the depth and normal buffers.
void rasterize_point(float screen_x, float screen_y, float depth, float radius, const Color &color, const Vec3 &normal, const Vec3 &light_direction, Image &output)
Rasterize a single point (filled circle) into the output image.
float fog_end
Distance where fog is fully opaque.
Definition rasterizer.h:134
Color fog_color
The fog color (what distant objects blend into).
Definition rasterizer.h:137
bool fog_enabled
Enable depth fog (default: false).
Definition rasterizer.h:128
float fog_start
Distance where fog begins.
Definition rasterizer.h:131
void apply_ssao(Image &output, float z_near, float z_far)
Apply screen-space ambient occlusion to the output image.
float ssao_intensity
SSAO darkening intensity (0.0–1.0, default: 0.8).
Definition rasterizer.h:151
float ambient
Ambient light level (0.0–1.0, default: 0.3).
Definition rasterizer.h:112
Color specular_color
Specular highlight color.
Definition rasterizer.h:91
std::vector< Light > lights
Light sources for Blinn-Phong shading.
Definition rasterizer.h:107
float shininess
Shininess exponent (Phong model).
Definition rasterizer.h:96
bool ssao_enabled
Enable SSAO (default: false).
Definition rasterizer.h:145
All settings that control rendering output.
std::vector< Light > lights
List of light sources.
bool fog_enabled
Enable depth fog (default: false).
Color background_color
Background color (default: opaque white).
float ambient
Ambient light level (default: 0.3).
float fog_start
Distance at which fog begins (in world units).
float shininess
Shininess exponent (default: 0.0 = no specular).
float contrast
Contrast adjustment (default: 1.0 = no change).
int height
Image height in pixels (default: 600).
Color wireframe_color
Color of the wireframe lines (default: black).
int width
Image width in pixels (default: 800).
float ssao_intensity
SSAO darkening intensity (default: 0.8).
std::vector< ClipPlane > clip_planes
Optional clip planes for cross-section views.
Color default_color
Default color for meshes without explicit vertex/face colors.
float far_plane
Far clipping plane distance (default: 10000.0).
bool backface_culling
Enable backface culling (default: true).
Color specular_color
Specular highlight color (default: transparent = no specular).
bool ssao_enabled
Enable SSAO (default: false).
int threads
Number of render threads (default: 0 = auto-detect).
int aa_samples
Anti-aliasing sample count (default: 1 = no AA).
bool wireframe
Draw triangle edges as lines (default: false).
float ssao_radius
SSAO sample radius in pixels (default: 16).
ShadingMode shading
Shading mode (default: SMOOTH).
float near_plane
Near clipping plane distance (default: 0.1).
float fog_end
Distance at which fog is fully opaque (in world units).
ProjectionType projection
Projection type (default: PERSPECTIVE).
Color fog_color
The color that distant objects fade into.
bool invert_normals
Flip all surface normals (default: false).
A collection of Mesh objects to be rendered together.
Definition scene.h:57
std::vector< SceneNodeRef > nodes() const
Non-owning references to all meshes, in draw order.
Definition scene.h:134