scimesh 0.3.2
Headless CPU-only 3D software renderer for scientific mesh visualization
Loading...
Searching...
No Matches
clipping.cpp
Go to the documentation of this file.
1#include <scimesh/clipping.h>
2#include <algorithm>
3
4namespace scimesh {
5
6// In OpenGL clip space (used by GLM), the near plane is at z = -w.
7// A vertex is "inside" (in front of near plane) if z + w >= 0.
8static inline bool is_inside_near(const Vec4 &p) {
9 return p.z + p.w >= 0.0f;
10}
11
12// Linear interpolation between two clip vertices based on parameter t in [0, 1]
13static inline ClipVertex lerp_clip_vertex(const ClipVertex &a, const ClipVertex &b, float t) {
14 ClipVertex result;
15 result.position = a.position + t * (b.position - a.position);
16 result.color = Color(
17 a.color.r + t * (b.color.r - a.color.r),
18 a.color.g + t * (b.color.g - a.color.g),
19 a.color.b + t * (b.color.b - a.color.b),
20 a.color.a + t * (b.color.a - a.color.a));
21 result.normal = a.normal + t * (b.normal - a.normal);
22 result.uv = a.uv + t * (b.uv - a.uv);
23 return result;
24}
25
26// Compute intersection parameter where edge a->b crosses the near plane (z + w = 0)
27static inline float intersection_t(const Vec4 &a, const Vec4 &b) {
28 float dist_a = a.z + a.w;
29 float dist_b = b.z + b.w;
30 float denom = dist_a - dist_b;
31 if (std::abs(denom) < 1e-12f)
32 return 0.0f;
33 return dist_a / denom;
34}
35
36// Sutherland-Hodgman clipping of a polygon against the near plane.
37// Input: list of polygon vertices (counter-clockwise). Output: clipped polygon.
38static void clip_polygon_near_plane(
39 const std::vector<ClipVertex> &input,
40 std::vector<ClipVertex> &output) {
41 output.clear();
42 if (input.empty())
43 return;
44
45 int n = static_cast<int>(input.size());
46 for (int i = 0; i < n; ++i) {
47 const ClipVertex &curr = input[i];
48 const ClipVertex &next = input[(i + 1) % n];
49 bool curr_inside = is_inside_near(curr.position);
50 bool next_inside = is_inside_near(next.position);
51
52 if (curr_inside) {
53 output.push_back(curr);
54 if (!next_inside) {
55 float t = intersection_t(curr.position, next.position);
56 output.push_back(lerp_clip_vertex(curr, next, t));
57 }
58 } else {
59 if (next_inside) {
60 float t = intersection_t(curr.position, next.position);
61 output.push_back(lerp_clip_vertex(curr, next, t));
62 }
63 }
64 }
65}
66
68 const ClipVertex &v0,
69 const ClipVertex &v1,
70 const ClipVertex &v2,
71 std::vector<ClipVertex> &output_vertices,
72 std::vector<Triangle> &output_triangles) {
73
74 // First pass: clip the triangle as a polygon
75 std::vector<ClipVertex> polygon = {v0, v1, v2};
76 std::vector<ClipVertex> clipped;
77 clip_polygon_near_plane(polygon, clipped);
78
79 if (clipped.size() < 3)
80 return 0;
81
82 // Fan triangulation from vertex 0
83 uint32_t base_idx = static_cast<uint32_t>(output_vertices.size());
84 for (const auto &cv : clipped) {
85 output_vertices.push_back(cv);
86 }
87
88 int num_tris = static_cast<int>(clipped.size()) - 2;
89 for (int i = 0; i < num_tris; ++i) {
90 output_triangles.push_back(Triangle{
91 base_idx,
92 base_idx + i + 1,
93 base_idx + i + 2});
94 }
95 return num_tris;
96}
97
98// ---- View-space plane clipping ----------------------------------------------
99
106
107static inline bool is_inside_view_plane(const ViewClipVertex &v, const ClipPlane &plane) {
108 return glm::dot(v.pos, plane.normal) + plane.offset >= 0.0f;
109}
110
111static inline ViewClipVertex lerp_view_vertex(const ViewClipVertex &a, const ViewClipVertex &b, float t) {
112 ViewClipVertex result;
113 result.pos = a.pos + t * (b.pos - a.pos);
114 result.color = Color(
115 a.color.r + t * (b.color.r - a.color.r),
116 a.color.g + t * (b.color.g - a.color.g),
117 a.color.b + t * (b.color.b - a.color.b),
118 a.color.a + t * (b.color.a - a.color.a));
119 result.normal = a.normal + t * (b.normal - a.normal);
120 result.uv = a.uv + t * (b.uv - a.uv);
121 return result;
122}
123
124static inline float intersection_t_view_plane(const ViewClipVertex &a, const ViewClipVertex &b,
125 const ClipPlane &plane) {
126 float dist_a = glm::dot(a.pos, plane.normal) + plane.offset;
127 float dist_b = glm::dot(b.pos, plane.normal) + plane.offset;
128 float denom = dist_a - dist_b;
129 if (std::abs(denom) < 1e-12f) return 0.0f;
130 return dist_a / denom;
131}
132
133static void clip_polygon_view_plane(
134 const std::vector<ViewClipVertex> &input,
135 const ClipPlane &plane,
136 std::vector<ViewClipVertex> &output) {
137 output.clear();
138 if (input.empty()) return;
139
140 int n = static_cast<int>(input.size());
141 for (int i = 0; i < n; ++i) {
142 const ViewClipVertex &curr = input[i];
143 const ViewClipVertex &next = input[(i + 1) % n];
144 bool curr_inside = is_inside_view_plane(curr, plane);
145 bool next_inside = is_inside_view_plane(next, plane);
146
147 if (curr_inside) {
148 output.push_back(curr);
149 if (!next_inside) {
150 float t = intersection_t_view_plane(curr, next, plane);
151 output.push_back(lerp_view_vertex(curr, next, t));
152 }
153 } else {
154 if (next_inside) {
155 float t = intersection_t_view_plane(curr, next, plane);
156 output.push_back(lerp_view_vertex(curr, next, t));
157 }
158 }
159 }
160}
161
163 const Vec3 &v0, const Vec3 &v1, const Vec3 &v2,
164 const Vec3 &n0, const Vec3 &n1, const Vec3 &n2,
165 const Color &c0, const Color &c1, const Color &c2,
166 const Vec2 &uv0, const Vec2 &uv1, const Vec2 &uv2,
167 const ClipPlane &plane,
168 std::vector<ClipVertex> &output_vertices,
169 std::vector<Triangle> &output_triangles) {
170
171 ViewClipVertex vc0{v0, c0, n0, uv0};
172 ViewClipVertex vc1{v1, c1, n1, uv1};
173 ViewClipVertex vc2{v2, c2, n2, uv2};
174
175 std::vector<ViewClipVertex> polygon{vc0, vc1, vc2};
176
177 std::vector<ViewClipVertex> clipped;
178 clip_polygon_view_plane(polygon, plane, clipped);
179
180 if (clipped.size() < 3) return 0;
181
182 uint32_t base_idx = static_cast<uint32_t>(output_vertices.size());
183 for (const auto &vcv : clipped) {
184 ClipVertex cv;
185 cv.position = Vec4(vcv.pos, 1.0f); // View-space pos stored in position field
186 cv.color = vcv.color;
187 cv.normal = vcv.normal;
188 cv.uv = vcv.uv;
189 output_vertices.push_back(cv);
190 }
191
192 int num_tris = static_cast<int>(clipped.size()) - 2;
193 for (int i = 0; i < num_tris; ++i) {
194 output_triangles.push_back(Triangle{
195 base_idx,
196 base_idx + static_cast<uint32_t>(i + 1),
197 base_idx + static_cast<uint32_t>(i + 2)});
198 }
199 return num_tris;
200}
201
202} // namespace scimesh
Triangle clipping against planes (view frustum and clip planes).
glm::vec2 Vec2
2-component floating-point vector (xy).
Definition types.h:32
glm::vec3 Vec3
3-component floating-point vector (xyz).
Definition types.h:46
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
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
glm::vec4 Vec4
4-component floating-point vector (xyzw).
Definition types.h:52
Vec2 uv1
Definition renderer.cpp:24
Vec2 uv0
Definition renderer.cpp:24
Vec2 uv2
Definition renderer.cpp:24
A clipping plane that can hide parts of the scene.
Definition types.h:224
Vec3 normal
The plane normal vector (should be unit-length).
Definition types.h:229
float offset
Offset along the normal.
Definition types.h:234
A processed vertex in clip space, ready for perspective divide.
Definition clipping.h:20
Color color
Vertex color.
Definition clipping.h:22
Vec2 uv
Texture coordinates.
Definition clipping.h:24
Vec3 normal
Vertex normal (in view space).
Definition clipping.h:23
Vec4 position
Homogeneous clip-space position (before divide by w).
Definition clipping.h:21
An RGBA color with floating-point components.
Definition types.h:88
A triangle defined by three vertex indices.
Definition types.h:127