Recompute normals without cloning faces / verts

This commit is contained in:
Connor Slade
2025-02-10 11:43:18 -05:00
parent 21d3edf6a2
commit 6a8a9ccfda
2 changed files with 21 additions and 18 deletions

View File

@@ -180,7 +180,7 @@ impl App {
} }
pub fn load_mesh<T: BufRead + Seek>(&mut self, buf: &mut T, format: &str, name: String) { pub fn load_mesh<T: BufRead + Seek>(&mut self, buf: &mut T, format: &str, name: String) {
let mut model = match slicer::mesh::load_mesh(buf, format) { let model = match slicer::mesh::load_mesh(buf, format) {
Ok(model) => model, Ok(model) => model,
Err(err) => { Err(err) => {
self.popup.open(Popup::simple( self.popup.open(Popup::simple(
@@ -193,11 +193,6 @@ impl App {
}; };
info!("Loaded model `{name}` with {} faces", model.face_count()); info!("Loaded model `{name}` with {} faces", model.face_count());
if model.normals().iter().any(|x| x.magnitude_squared() == 0.0) {
warn!("Model `{name}` has invalid normals. Recomputing.");
model.recompute_normals();
}
let rendered_mesh = RenderedMesh::from_mesh(model) let rendered_mesh = RenderedMesh::from_mesh(model)
.with_name(name.clone()) .with_name(name.clone())
.with_random_color(); .with_random_color();

View File

@@ -6,6 +6,7 @@ use std::{
use anyhow::Result; use anyhow::Result;
use nalgebra::{Matrix4, Vector3}; use nalgebra::{Matrix4, Vector3};
use obj::{Obj, Vertex}; use obj::{Obj, Vertex};
use tracing::warn;
use crate::Pos; use crate::Pos;
@@ -33,8 +34,14 @@ struct MeshInner {
impl Mesh { impl Mesh {
/// Creates a new mesh from the givin vertices and faces. The /// Creates a new mesh from the givin vertices and faces. The
/// transformations are all 0 by default. /// transformations are all 0 by default.
pub fn new(mut vertices: Vec<Pos>, faces: Vec<[u32; 3]>, normals: Vec<Pos>) -> Self { pub fn new(mut vertices: Vec<Pos>, faces: Vec<[u32; 3]>, mut normals: Vec<Pos>) -> Self {
center_vertices(&mut vertices); center_vertices(&mut vertices);
if normals.iter().any(|x| x.magnitude_squared() == 0.0) {
warn!("Model has invalid normals. Recomputing.");
normals = recompute_normals(&vertices, &faces);
}
Self::new_uncentred(vertices, faces, normals) Self::new_uncentred(vertices, faces, normals)
} }
@@ -83,17 +90,7 @@ impl Mesh {
/// Makes a copy of the mesh with normals computed from the triangles /// Makes a copy of the mesh with normals computed from the triangles
/// directly. The copy makes this operation kinda expensive. /// directly. The copy makes this operation kinda expensive.
pub fn recompute_normals(&mut self) { pub fn recompute_normals(&mut self) {
let vertices = self.vertices(); let normals = recompute_normals(self.vertices(), self.faces());
let normals = self
.faces()
.iter()
.map(|f| {
let edge1 = vertices[f[2] as usize] - vertices[f[1] as usize];
let edge2 = vertices[f[0] as usize] - vertices[f[1] as usize];
edge1.cross(&edge2).normalize()
})
.collect();
self.overwrite_normals(normals) self.overwrite_normals(normals)
} }
@@ -377,3 +374,14 @@ fn center_vertices(vertices: &mut [Pos]) {
let center = Pos::new(center.x, center.y, min.z); let center = Pos::new(center.x, center.y, min.z);
vertices.iter_mut().for_each(|v| *v -= center); vertices.iter_mut().for_each(|v| *v -= center);
} }
fn recompute_normals(vertices: &[Pos], faces: &[[u32; 3]]) -> Vec<Vector3<f32>> {
faces
.iter()
.map(|f| {
let edge1 = vertices[f[2] as usize] - vertices[f[1] as usize];
let edge2 = vertices[f[0] as usize] - vertices[f[1] as usize];
edge1.cross(&edge2).normalize()
})
.collect()
}