ak_vis/render/
render_faces.rs1use crate::components::FrameFace;
2use crate::visuals::FaceVisual;
3use bevy::{
4 asset::RenderAssetUsages,
5 light::{NotShadowCaster, NotShadowReceiver},
6 mesh::{Indices, PrimitiveTopology},
7 prelude::*,
8};
9
10pub fn render_faces(
11 visuals: Vec<FaceVisual>,
12 commands: &mut Commands,
13 materials: &mut ResMut<Assets<StandardMaterial>>,
14 meshes: &mut ResMut<Assets<Mesh>>,
15) {
16 for visual in visuals {
17 let Some(mesh) = build_face_mesh(&visual.vertices) else {
18 continue;
19 };
20
21 let material = materials.add(StandardMaterial {
22 base_color: visual.color,
23 alpha_mode: AlphaMode::Blend,
24 cull_mode: None,
25 double_sided: true,
26 perceptual_roughness: 0.65,
27 metallic: 0.0,
28 ..default()
29 });
30
31 commands.spawn((
32 Mesh3d(meshes.add(mesh)),
33 MeshMaterial3d(material),
34 Transform::default(),
35 FrameFace,
36 NotShadowCaster,
37 NotShadowReceiver,
38 ));
39 }
40}
41
42fn build_face_mesh(vertices: &[Vec3]) -> Option<Mesh> {
43 if vertices.len() < 3 {
44 return None;
45 }
46
47 let base = vertices[0];
48 let edge_a = vertices[1] - base;
49 let edge_b = vertices[2] - base;
50 let normal = edge_a.cross(edge_b).normalize_or_zero();
51 if normal == Vec3::ZERO {
52 return None;
53 }
54
55 let positions: Vec<[f32; 3]> = vertices.iter().map(|v| [v.x, v.y, v.z]).collect();
56 let normals = vec![[normal.x, normal.y, normal.z]; vertices.len()];
57 let mut indices = Vec::with_capacity((vertices.len() - 2) * 3);
58 for i in 1..(vertices.len() - 1) {
59 indices.push(0_u32);
60 indices.push(i as u32);
61 indices.push((i + 1) as u32);
62 }
63
64 let mut mesh = Mesh::new(
65 PrimitiveTopology::TriangleList,
66 RenderAssetUsages::default(),
67 );
68 mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);
69 mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
70 mesh.insert_indices(Indices::U32(indices));
71 Some(mesh)
72}