ak_vis/render/
render_faces.rs

1use 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}