5#include <glm/gtc/constants.hpp>
22 ?
Vec3(0.0f, 1.0f, 0.0f)
23 :
Vec3(1.0f, 0.0f, 0.0f);
25 v = glm::cross(
dir,
u);
35static inline float batch_radius(
const std::vector<float> &
radii,
size_t i) {
45static inline Color batch_color(
const std::vector<Color> &colors,
size_t i) {
47 return Color(1.0f, 1.0f, 1.0f, 1.0f);
49 return (
i < colors.size()) ? colors[
i] : colors[0];
62 const size_t s =
static_cast<size_t>(std::max(3,
segments));
75static inline void cylinder_geometry_counts(
int segments,
bool caps,
78 const size_t s =
static_cast<size_t>(std::max(3,
segments));
97 m.vertices.push_back(center +
Vec3(0.0f,
radius, 0.0f));
98 m.colors.push_back(color);
101 float phi = glm::pi<float>() *
static_cast<float>(
ring) /
109 m.vertices.push_back(
111 m.colors.push_back(color);
116 m.vertices.push_back(center +
Vec3(0.0f, -
radius, 0.0f));
117 m.colors.push_back(color);
119 m.normals.resize(
m.vertices.size());
120 for (
size_t i = 0;
i <
m.vertices.size(); ++
i) {
121 m.normals[
i] = glm::normalize(
m.vertices[
i] - center);
142 m.triangles.push_back({a, b,
c});
143 m.triangles.push_back({a,
c,
d});
180 float step = glm::two_pi<float>() /
static_cast<float>(
segments);
182 float a =
step *
static_cast<float>(
i);
192 m.colors.push_back(color);
197 m.colors.push_back(color);
207 m.triangles.push_back({a, b,
c});
208 m.triangles.push_back({a,
c,
d});
216 m.vertices.push_back(
start);
217 m.normals.push_back(-
dir);
218 m.colors.push_back(color);
223 m.normals.push_back(-
dir);
224 m.colors.push_back(color);
240 m.vertices.push_back(
end);
241 m.normals.push_back(
dir);
242 m.colors.push_back(color);
247 m.normals.push_back(
dir);
248 m.colors.push_back(color);
271 float height = glm::length(
dir_vec);
279 float step = glm::two_pi<float>() /
static_cast<float>(
segments);
284 float a =
step *
static_cast<float>(
i);
293 m.colors.push_back(color);
296 m.vertices.push_back(
tip);
298 m.colors.push_back(color);
314 m.vertices.push_back(
base);
315 m.normals.push_back(-
dir);
316 m.colors.push_back(color);
320 float a =
step *
static_cast<float>(
i);
324 m.normals.push_back(-
dir);
325 m.colors.push_back(color);
343 const Color &color) {
363 dst.vertices.insert(
dst.vertices.end(),
src.vertices.begin(),
365 dst.colors.insert(
dst.colors.end(),
src.colors.begin(),
src.colors.end());
366 dst.normals.insert(
dst.normals.end(),
src.normals.begin(),
src.normals.end());
368 for (
const auto &
tri :
src.triangles) {
369 dst.triangles.push_back(
370 {
tri.v0 + offset,
tri.v1 + offset,
tri.v2 + offset});
375 const std::vector<float> &
radii,
376 const std::vector<Color> &colors,
393 for (
size_t i = 0;
i <
n; ++
i) {
394 float r = batch_radius(
radii,
i);
395 Color c = batch_color(colors,
i);
403 const std::vector<Vec3> &
ends,
404 const std::vector<float> &
radii,
405 const std::vector<Color> &colors,
408 const size_t n =
starts.size();
423 for (
size_t i = 0;
i <
n; ++
i) {
424 float r = batch_radius(
radii,
i);
425 Color c = batch_color(colors,
i);
440 const size_t s =
static_cast<size_t>(std::max(3,
segments));
466static std::vector<Vec3> clean_tube_path(
const std::vector<Vec3> &
path,
496 :
Vec3(0.0f, 1.0f, 0.0f);
512static std::vector<Vec3> tube_path_tangents(
const std::vector<Vec3> &
pts) {
513 const size_t n =
pts.size();
515 for (
size_t i = 0;
i <
n; ++
i) {
519 }
else if (
i + 1 ==
n) {
524 const float len = glm::length(
dir);
537 const std::vector<Vec3>
pts = clean_tube_path(
path);
538 if (
pts.size() < 2u) {
543 const size_t s =
static_cast<size_t>(
segments);
553 const std::vector<Vec3>
tangents = tube_path_tangents(
pts);
554 const float step = glm::two_pi<float>() /
static_cast<float>(
segments);
583 const float a =
step *
static_cast<float>(
j);
588 m.colors.push_back(color);
599 m.triangles.push_back({a, b,
c});
600 m.triangles.push_back({a,
c,
d});
608 m.vertices.push_back(
pts[0]);
610 m.colors.push_back(color);
612 const float a =
step *
static_cast<float>(
j);
617 m.colors.push_back(color);
635 m.colors.push_back(color);
637 const float a =
step *
static_cast<float>(
j);
642 m.colors.push_back(color);
657 const std::vector<float> &
radii,
658 const std::vector<Color> &colors,
661 const size_t n =
paths.size();
682 for (
size_t i = 0;
i <
n; ++
i) {
683 const float r = batch_radius(
radii,
i);
684 const Color c = batch_color(colors,
i);
691 const Color &color) {
696 m.normals.reserve(24);
697 m.colors.assign(24, color);
698 m.triangles.reserve(12);
721 {4, 5, 6, 7,
Vec3( 0, 0, 1)},
722 {1, 0, 3, 2,
Vec3( 0, 0, -1)},
723 {0, 1, 5, 4,
Vec3( 0, -1, 0)},
724 {7, 6, 2, 3,
Vec3( 0, 1, 0)},
725 {1, 2, 6, 5,
Vec3( 1, 0, 0)},
726 {0, 4, 7, 3,
Vec3(-1, 0, 0)}
730 for (
int i = 0;
i < 6;
i++) {
732 m.vertices.push_back(
v[
faces[
i].v0]);
733 m.vertices.push_back(
v[
faces[
i].v1]);
734 m.vertices.push_back(
v[
faces[
i].v2]);
738 for (
int j = 0;
j < 4;
j++) {
739 m.normals.push_back(
faces[
i].normal);
743 m.triangles.push_back({index, index + 1, index + 2});
744 m.triangles.push_back({index, index + 2, index + 3});
754 float hw,
const Color &color) {
759 m.normals.reserve(16);
760 m.colors.assign(16, color);
761 m.triangles.reserve(6);
770 std::vector<std::array<Vec3, 3>>
side_faces = {
782 Vec3 normal = glm::normalize(glm::cross(
B -
A,
C -
A));
785 m.vertices.push_back(
A);
786 m.vertices.push_back(
B);
787 m.vertices.push_back(
C);
789 m.normals.push_back(normal);
790 m.normals.push_back(normal);
791 m.normals.push_back(normal);
793 m.triangles.push_back({index, index + 1, index + 2});
800 m.vertices.push_back(
p0);
801 m.vertices.push_back(
p1);
802 m.vertices.push_back(
p2);
803 m.vertices.push_back(
p3);
805 for (
int i = 0;
i < 4;
i++) {
810 m.triangles.push_back({index, index + 2, index + 3});
811 m.triangles.push_back({index, index + 1, index + 2});
818 const Color &color) {
823 m.normals.reserve(12);
824 m.colors.assign(12, color);
825 m.triangles.reserve(4);
829 std::vector<std::array<Vec3, 3>>
faces = {
830 {
p0,
p1,
p2}, {
p0,
p2,
p3}, {
p0,
p3,
p1}, {
p1,
p3,
p2}
836 Vec3 normal = glm::normalize(glm::cross(
B -
A,
C -
A));
839 if (glm::dot(normal,
A -
centroid) < 0.0f) {
845 m.vertices.push_back(
A);
846 m.vertices.push_back(
B);
847 m.vertices.push_back(
C);
850 m.normals.push_back(normal);
851 m.normals.push_back(normal);
852 m.normals.push_back(normal);
854 m.triangles.push_back({index, index + 1, index + 2});
890 m.vertices.push_back(pos);
891 m.colors.push_back(color);
911 m.triangles.push_back({a,
d,
c});
912 m.triangles.push_back({a,
c, b});
920 float hx,
float hy,
const Color &color) {
922 Vec3 n = glm::length(normal) > 1e-9f ? glm::normalize(normal) :
Vec3(0,0,1);
924 if (std::abs(
n.x) < 0.9f)
u = glm::normalize(glm::cross(
n,
Vec3(1,0,0)));
925 else u = glm::normalize(glm::cross(
n,
Vec3(0,1,0)));
926 v = glm::cross(
n,
u);
934 m.vertices.reserve(8);
935 m.normals.reserve(8);
937 m.triangles.reserve(4);
940 m.vertices.insert(
m.vertices.end(), {p0, p1, p2, p3});
941 for (
int i = 0;
i < 4;
i++) {
942 m.normals.push_back(
n);
943 m.colors.push_back(color);
946 m.triangles.push_back({0, 1, 2});
947 m.triangles.push_back({0, 2, 3});
950 m.vertices.insert(
m.vertices.end(), {p0, p1, p2, p3});
951 for (
int i = 0;
i < 4;
i++) {
952 m.normals.push_back(-
n);
953 m.colors.push_back(color);
956 m.triangles.push_back({4, 6, 5});
957 m.triangles.push_back({4, 7, 6});
Low-level math utilities for the rendering pipeline.
Mesh generate_multi_tubes(const std::vector< std::vector< Vec3 > > &paths, const std::vector< float > &radii, const std::vector< Color > &colors, int segments, bool caps)
Generate multiple tubes in a single mesh (efficient batching).
Mesh generate_pyramid(const Vec3 &base_center, const Vec3 &apex, float hw, const Color &color)
Generate a square-based pyramid.
Mesh generate_tetrahedron(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, const Color &color)
Generate a tetrahedron (triangular pyramid) from four points.
Mesh generate_sphere(const Vec3 ¢er, float radius, int segments, const Color &color)
Generate a UV-sphere (latitude/longitude tessellation).
glm::vec3 Vec3
3-component floating-point vector (xyz).
Mesh generate_cuboid(const Vec3 ¢er, const Vec3 &half, const Color &color)
Generate an axis-aligned cuboid (rectangular box).
void merge_mesh(Mesh &dst, const Mesh &src)
Merge one mesh into another (append geometry).
Mesh generate_arrow(const Vec3 &from, const Vec3 &to, float shaft_radius, float head_radius, float head_length, int segments, const Color &color)
Generate a 3D arrow from from to to.
Mesh generate_torus(const Vec3 ¢er, float R, float r, int seg_major, int seg_minor, const Color &color)
Generate a torus (donut shape).
Mesh generate_multi_spheres(const std::vector< Vec3 > ¢ers, const std::vector< float > &radii, const std::vector< Color > &colors, int segments)
Generate multiple spheres in a single mesh (efficient batching).
Mesh generate_cylinder(const Vec3 &start, const Vec3 &end, float radius, int segments, const Color &color, bool caps)
Generate a cylinder between two endpoints.
Mesh generate_multi_cylinders(const std::vector< Vec3 > &starts, const std::vector< Vec3 > &ends, const std::vector< float > &radii, const std::vector< Color > &colors, int segments, bool caps)
Generate multiple cylinders in a single mesh (efficient batching).
Mesh generate_plane(const Vec3 ¢er, const Vec3 &normal, float hx, float hy, const Color &color)
Generate a flat rectangular plane.
Mesh generate_cone(const Vec3 &base, const Vec3 &tip, float radius, int segments, const Color &color)
Generate a cone from a base circle to a tip point.
Mesh generate_tube(const std::vector< Vec3 > &path, float radius, int segments, const Color &color, bool cap_start, bool cap_end)
Generate a tube (generalized cylinder) along a polyline path.
Compute per-vertex surface normals for lighting.
Procedural geometry generators.
An RGBA color with floating-point components.
A 3D triangle mesh using an indexed face set representation.
std::vector< Vec3 > vertices
3D vertex positions.
int y
Top edge of the bitmap, in image pixels.
int x
Left edge of the bitmap, in image pixels.