8#include <glm/gtc/matrix_transform.hpp>
47 return -near_plane -
p_view.z;
71 const std::vector<ClipPlane> &clip_planes,
72 float &
t0,
float &
t1) {
87 if (std::abs(
denom) < 1e-12f) {
103 for (
const ClipPlane &
plane : clip_planes) {
116 throw std::invalid_argument(
"RenderOptions width and height must be > 0");
118 int aa = std::max(1,
options.aa_samples);
120 std::vector<SceneNodeRef> nodes;
121 nodes.push_back({&mesh,
Mat4(1.0f),
""});
128 throw std::invalid_argument(
"RenderOptions width and height must be > 0");
130 int aa = std::max(1,
options.aa_samples);
132 std::vector<SceneNodeRef> nodes =
scene.nodes();
138 const std::vector<Color> &colors,
144 int nv =
static_cast<int>(positions.size());
145 for (
int i = 0;
i <
nv / 3;
i++) {
151 for (
const auto &
c : colors) {
152 if (
c.a < 1.0f - 1e-6f) {
161 const std::vector<Color> &colors,
166 throw std::invalid_argument(
"RenderOptions width and height must be > 0");
168 int np =
static_cast<int>(positions.size());
169 if (
np == 0 || colors.empty()) {
176 int aa = std::max(1,
options.aa_samples);
218 for (
int i = 0;
i <
np;
i++) {
224 Vec3 normal(0.0f, 0.0f, 1.0f);
237 const std::vector<Vec3> &to,
238 const std::vector<Color> &colors,
243 throw std::invalid_argument(
"RenderOptions width and height must be > 0");
257 int aa = std::max(1,
options.aa_samples);
264void Renderer::render_pipeline(
const std::vector<SceneNodeRef> &nodes,
265 const std::vector<LineNodeRef> &line_nodes,
266 const std::vector<TextNodeRef> &text_nodes,
271 for (
size_t i = 0;
i < nodes.size(); ++
i) {
272 const auto *
mp = nodes[
i].mesh;
273 if (
mp->empty())
continue;
274 if (!
mp->is_valid()) {
275 throw std::invalid_argument(
276 "Mesh " + std::to_string(
i) +
" failed validation: "
277 "check indices, vertex data, and array sizes");
321 for (
const auto &
cp :
options.clip_planes) {
331 for (
const auto &node : nodes) {
332 const Mesh &mesh = *node.mesh;
333 if (mesh.empty())
continue;
345 if (mesh.has_uvs() && mesh.has_texture()) {
346 rasterizer.active_texture =
const_cast<Image *
>(&mesh.texture);
353 if (mesh.has_normals()) {
362 Vec3 n = (*normals_ptr)[
i];
369 const auto &
tri = mesh.triangles[
ti];
370 Vec3 v0 = mesh.vertices[
tri.v0];
371 Vec3 v1 = mesh.vertices[
tri.v1];
372 Vec3 v2 = mesh.vertices[
tri.v2];
375 if (mesh.has_face_colors()) {
376 c0 =
c1 =
c2 = mesh.face_colors[
ti];
377 }
else if (mesh.has_colors()) {
378 c0 = mesh.colors[
tri.v0];
379 c1 = mesh.colors[
tri.v1];
380 c2 = mesh.colors[
tri.v2];
394 (
c0.a < 1.0f - 1e-6f ||
c1.a < 1.0f - 1e-6f ||
c2.a < 1.0f - 1e-6f);
428 Vec3 pa(a.position.x, a.position.y, a.position.z);
429 Vec3 pb(b.position.x, b.position.y, b.position.z);
430 Vec3 pc(
c.position.x,
c.position.y,
c.position.z);
432 Color
ca(a.color),
cb(b.color),
cc(
c.color);
455 cva.position = projection *
Vec4(a.position.x, a.position.y, a.position.z, 1.0f);
456 cva.color = a.color;
cva.normal = a.normal;
457 cvb.position = projection *
Vec4(b.position.x, b.position.y, b.position.z, 1.0f);
458 cvb.color = b.color;
cvb.normal = b.normal;
459 cvc.position = projection *
Vec4(
c.position.x,
c.position.y,
c.position.z, 1.0f);
460 cvc.color =
c.color;
cvc.normal =
c.normal;
540 static_cast<float>(
output.width) /
541 static_cast<float>(std::max(1,
options.width));
542 for (
const auto &line_node : line_nodes) {
543 const LineLayer &layer = *line_node.layer;
559 float t0 = 0.0f,
t1 = 1.0f;
576 const Color color = layer.color_or(
i,
options.default_color);
581 if (color.a < 1.0f - 1e-6f) {
583 layer.lit, (
p0.z +
p1.z) * 0.5f});
604 [](
const DeferredTri &a,
const DeferredTri &b) {
605 return a.view_z < b.view_z;
608 [](
const DeferredLine &a,
const DeferredLine &b) {
609 return a.view_z < b.view_z;
624 dl.screen_v0,
dl.color0,
dl.screen_v1,
dl.color1,
630 dt.screen_v0,
dt.color0,
dt.normal0,
dt.uv0,
631 dt.screen_v1,
dt.color1,
dt.normal1,
dt.uv1,
632 dt.screen_v2,
dt.color2,
dt.normal2,
dt.uv2,
651 if (!text_nodes.empty()) {
653 static_cast<float>(
output.width) /
654 static_cast<float>(std::max(1,
options.width));
Image render_mesh(const Mesh &mesh, const Camera &camera, const RenderOptions &options)
Render a single mesh to an image.
Image render_lines_raw(const std::vector< Vec3 > &from, const std::vector< Vec3 > &to, const std::vector< Color > &colors, float width, const Camera &camera, const RenderOptions &options)
Render line segments with a screen-space width to an image.
Image render_scene(const Scene &scene, const Camera &camera, const RenderOptions &options)
Render a scene (collection of meshes) to an image.
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.
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.
Triangle clipping against planes (view frustum and clip planes).
Low-level math utilities for the rendering pipeline.
void render_text_layers(const std::vector< TextNodeRef > &layers, Image &output, const Mat4 &view_projection, float pixel_scale, const std::vector< float > &z_buffer, const Color &default_color)
Draw all text layers into an already rendered image.
glm::vec2 Vec2
2-component floating-point vector (xy).
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.
void compute_vertex_normals(const Mesh &mesh, std::vector< Vec3 > &normals)
Compute per-vertex normals by averaging adjacent face normals.
glm::vec3 Vec3
3-component floating-point vector (xyz).
Vec3 transform_direction(const Mat4 &m, const Vec3 &d)
Transform a direction vector by a 4×4 matrix (with implicit w=0).
Vec3 compute_face_normal(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2)
Compute the unit-length normal vector of a triangle face.
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.
ClipPlane clip_plane_to_view_space(const ClipPlane &plane, const Vec3 &eye, const Mat4 &view)
Convert a ClipPlane to view (eye) space, ready for clipping.
Vec3 transform_point(const Mat4 &m, const Vec3 &p)
Transform a point by a 4×4 matrix (with implicit w=1).
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.
@ SMOOTH
Smooth (Gouraud) shading: normals are interpolated across each triangle, producing a smooth,...
@ ORTHOGRAPHIC
Orthographic projection: parallel lines stay parallel.
Vec3 perspective_divide(const Vec4 &clip)
Perform perspective division: divide xyz by w.
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).
Compute per-vertex surface normals for lighting.
The Rasterizer — the per-pixel rendering engine.
float view_z
Centroid depth in view space: the camera looks down -Z, so a smaller (more negative) value is farther...
The Renderer — the main entry point for drawing meshes to images.
A virtual camera that defines the viewpoint for rendering.
ProjectionType projection
Which projection type to use.
A batch of independent line segments drawn with a fixed screen-space width.
std::vector< Vec3 > from
Segment start points, in world space.
float width
Line width in screen pixels (default: 1.0).
std::vector< Color > colors
One color per segment; may be empty (then the renderer uses RenderOptions::default_color) or shorter ...
std::vector< Vec3 > to
Segment end points, in world space (one per entry in from).
A 3D triangle mesh using an indexed face set representation.
bool has_transparency
Whether the mesh contains any transparent fragments.
std::vector< Color > colors
Per-vertex RGBA colors.
std::vector< Vec3 > vertices
3D vertex positions.
std::vector< Triangle > triangles
Triangle index triplets.
Low-level triangle rasterizer with depth buffering and lighting.
All settings that control rendering output.
A collection of Mesh objects to be rendered together.
void add_lines(const LineLayer &layer, const Mat4 &transform=Mat4(1.0f), const std::string &name="")
Add a line layer to the scene with an optional placement transform and name.
int x
Left edge of the bitmap, in image pixels.
Text labels — the TextLayer.