re_renderer/importer/
stl.rs1use itertools::Itertools as _;
2use smallvec::smallvec;
3
4use crate::{CpuModel, DebugLabel, RenderContext, mesh};
5
6#[derive(thiserror::Error, Debug)]
7pub enum StlImportError {
8 #[error("Error loading STL mesh: {0}")]
9 StlIoError(std::io::Error),
10
11 #[error(transparent)]
12 MeshError(#[from] mesh::MeshError),
13}
14
15pub fn load_stl_from_buffer(
17 buffer: &[u8],
18 ctx: &RenderContext,
19) -> Result<CpuModel, StlImportError> {
20 re_tracing::profile_function!();
21
22 let mut cursor = std::io::Cursor::new(buffer);
23 let reader = stl_io::create_stl_reader(&mut cursor).map_err(StlImportError::StlIoError)?;
24
25 let name = DebugLabel::from("");
28
29 let (normals, triangles): (Vec<_>, Vec<_>) = reader
30 .into_iter()
31 .map(|triangle_res| {
32 triangle_res.map(|triangle| {
33 (
34 [triangle.normal.0, triangle.normal.0, triangle.normal.0],
35 [
36 triangle.vertices[0].0,
37 triangle.vertices[1].0,
38 triangle.vertices[2].0,
39 ],
40 )
41 })
42 })
43 .collect::<Result<Vec<_>, _>>()
44 .map_err(StlImportError::StlIoError)?
45 .into_iter()
46 .unzip();
47
48 let num_vertices = triangles.len() * 3;
49
50 let material = mesh::Material {
51 label: name.clone(),
52 index_range: 0..num_vertices as u32,
53 albedo: ctx.texture_manager_2d.white_texture_unorm_handle().clone(),
54 albedo_factor: crate::Rgba::WHITE,
55 };
56
57 let vertex_positions = bytemuck::cast_vec(triangles);
58 let bbox = macaw::BoundingBox::from_points(vertex_positions.iter().copied());
59
60 let mesh = mesh::CpuMesh {
61 label: name.clone(),
62 triangle_indices: (0..num_vertices as u32)
63 .tuples::<(_, _, _)>()
64 .map(glam::UVec3::from)
65 .collect::<Vec<_>>(),
66
67 vertex_positions,
68
69 vertex_normals: bytemuck::cast_vec(normals),
72
73 vertex_colors: vec![crate::Rgba32Unmul::WHITE; num_vertices],
75 vertex_texcoords: vec![glam::Vec2::ZERO; num_vertices],
76
77 materials: smallvec![material],
78
79 bbox,
80 };
81
82 mesh.sanity_check()?;
83
84 Ok(CpuModel::from_single_mesh(mesh))
85}