polyscope_structures/surface_mesh/
geometry.rs1use glam::Vec3;
11use std::collections::HashSet;
12
13use super::{ShadeStyle, SurfaceMesh};
14
15impl SurfaceMesh {
16 pub(super) fn recompute(&mut self) {
20 if !self.needs_recompute {
21 return;
22 }
23
24 self.compute_triangulation();
25 self.compute_face_normals();
26 self.compute_vertex_normals();
27 self.compute_corner_normals();
28 self.compute_edges();
29 self.compute_edge_is_real();
30
31 self.needs_recompute = false;
32 }
33
34 fn compute_triangulation(&mut self) {
39 self.triangulation.clear();
40 self.face_to_tri_range.clear();
41
42 for face in &self.faces {
43 let start_tri = self.triangulation.len();
44
45 if face.len() >= 3 {
46 let v0 = face[0];
47 for i in 1..(face.len() - 1) {
49 self.triangulation.push([v0, face[i], face[i + 1]]);
50 }
51 }
52
53 let end_tri = self.triangulation.len();
54 self.face_to_tri_range.push(start_tri..end_tri);
55 }
56 }
57
58 fn compute_face_normals(&mut self) {
60 self.face_normals.clear();
61 self.face_normals.reserve(self.faces.len());
62
63 for face in &self.faces {
64 if face.len() >= 3 {
65 let v0 = self.vertices[face[0] as usize];
66 let v1 = self.vertices[face[1] as usize];
67 let v2 = self.vertices[face[2] as usize];
68
69 let e1 = v1 - v0;
70 let e2 = v2 - v0;
71 let normal = e1.cross(e2).normalize_or_zero();
72 self.face_normals.push(normal);
73 } else {
74 self.face_normals.push(Vec3::ZERO);
75 }
76 }
77 }
78
79 fn compute_vertex_normals(&mut self) {
81 self.vertex_normals.clear();
82 self.vertex_normals.resize(self.vertices.len(), Vec3::ZERO);
83
84 for (face_idx, face) in self.faces.iter().enumerate() {
85 if face.len() < 3 {
86 continue;
87 }
88
89 let face_normal = self.face_normals[face_idx];
90
91 let v0 = self.vertices[face[0] as usize];
93 let mut area = 0.0;
94 for i in 1..(face.len() - 1) {
95 let v1 = self.vertices[face[i] as usize];
96 let v2 = self.vertices[face[i + 1] as usize];
97 let e1 = v1 - v0;
98 let e2 = v2 - v0;
99 area += e1.cross(e2).length() * 0.5;
100 }
101
102 let weighted_normal = face_normal * area;
104 for &vi in face {
105 self.vertex_normals[vi as usize] += weighted_normal;
106 }
107 }
108
109 for normal in &mut self.vertex_normals {
111 *normal = normal.normalize_or_zero();
112 }
113 }
114
115 pub(super) fn compute_corner_normals(&mut self) {
117 self.corner_normals.clear();
118 self.corner_normals.reserve(self.triangulation.len() * 3);
119
120 for (face_idx, range) in self.face_to_tri_range.iter().enumerate() {
121 let face_normal = self.face_normals[face_idx];
122
123 for tri_idx in range.clone() {
124 let tri = self.triangulation[tri_idx];
125 for vi in tri {
126 match self.shade_style {
129 ShadeStyle::Smooth => {
130 self.corner_normals.push(self.vertex_normals[vi as usize]);
131 }
132 ShadeStyle::Flat | ShadeStyle::TriFlat => {
133 self.corner_normals.push(face_normal);
134 }
135 }
136 }
137 }
138 }
139 }
140
141 fn compute_edge_is_real(&mut self) {
144 self.edge_is_real.clear();
145 self.edge_is_real.reserve(self.triangulation.len() * 3);
146
147 for range in &self.face_to_tri_range {
148 let num_tris = range.end - range.start;
149
150 for (j, _tri_idx) in range.clone().enumerate() {
151 let edge0_real = if j == 0 { 1.0 } else { 0.0 };
158 let edge1_real = 1.0; let edge2_real = if j == num_tris - 1 { 1.0 } else { 0.0 };
160
161 let edge_real = Vec3::new(edge0_real, edge1_real, edge2_real);
164 self.edge_is_real.push(edge_real);
165 self.edge_is_real.push(edge_real);
166 self.edge_is_real.push(edge_real);
167 }
168 }
169 }
170
171 fn compute_edges(&mut self) {
173 let mut edge_set: HashSet<(u32, u32)> = HashSet::new();
174
175 for face in &self.faces {
176 let n = face.len();
177 for i in 0..n {
178 let v0 = face[i];
179 let v1 = face[(i + 1) % n];
180 let edge = if v0 < v1 { (v0, v1) } else { (v1, v0) };
182 edge_set.insert(edge);
183 }
184 }
185
186 self.edges = edge_set.into_iter().collect();
187 self.edges.sort_unstable(); }
189
190 #[must_use]
192 pub fn compute_face_tangent_basis(&self) -> (Vec<Vec3>, Vec<Vec3>) {
193 let mut basis_x = Vec::with_capacity(self.faces.len());
194 let mut basis_y = Vec::with_capacity(self.faces.len());
195
196 for (face_idx, face) in self.faces.iter().enumerate() {
197 if face.len() >= 3 {
198 let v0 = self.vertices[face[0] as usize];
199 let v1 = self.vertices[face[1] as usize];
200 let normal = self.face_normals[face_idx];
201
202 let bx = (v1 - v0).normalize_or_zero();
203 let by = normal.cross(bx).normalize_or_zero();
204 basis_x.push(bx);
205 basis_y.push(by);
206 } else {
207 basis_x.push(Vec3::X);
208 basis_y.push(Vec3::Y);
209 }
210 }
211
212 (basis_x, basis_y)
213 }
214
215 #[must_use]
217 pub fn compute_vertex_tangent_basis(&self) -> (Vec<Vec3>, Vec<Vec3>) {
218 let (face_bx, _face_by) = self.compute_face_tangent_basis();
219
220 let mut vert_bx = vec![Vec3::ZERO; self.vertices.len()];
221
222 for (face_idx, face) in self.faces.iter().enumerate() {
223 if face.len() < 3 {
224 continue;
225 }
226
227 let v0 = self.vertices[face[0] as usize];
229 let mut area = 0.0f32;
230 for i in 1..(face.len() - 1) {
231 let v1 = self.vertices[face[i] as usize];
232 let v2 = self.vertices[face[i + 1] as usize];
233 area += (v1 - v0).cross(v2 - v0).length() * 0.5;
234 }
235
236 let weighted_bx = face_bx[face_idx] * area;
237 for &vi in face {
238 vert_bx[vi as usize] += weighted_bx;
239 }
240 }
241
242 let mut basis_x = Vec::with_capacity(self.vertices.len());
244 let mut basis_y = Vec::with_capacity(self.vertices.len());
245
246 for (i, normal) in self.vertex_normals.iter().enumerate() {
247 let mut bx = vert_bx[i];
248 bx -= *normal * normal.dot(bx);
250 bx = bx.normalize_or_zero();
251
252 if bx.length_squared() < 1e-6 {
254 bx = if normal.x.abs() < 0.9 {
255 Vec3::X
256 } else {
257 Vec3::Y
258 };
259 bx -= *normal * normal.dot(bx);
260 bx = bx.normalize_or_zero();
261 }
262
263 let by = normal.cross(bx).normalize_or_zero();
264 basis_x.push(bx);
265 basis_y.push(by);
266 }
267
268 (basis_x, basis_y)
269 }
270}