diff --git a/crates/bevy_pbr/src/meshlet/from_mesh.rs b/crates/bevy_pbr/src/meshlet/from_mesh.rs index 14b46e55ba46e..697d3d4aacd82 100644 --- a/crates/bevy_pbr/src/meshlet/from_mesh.rs +++ b/crates/bevy_pbr/src/meshlet/from_mesh.rs @@ -9,7 +9,7 @@ use bevy_render::{ }; use bevy_utils::HashMap; use bitvec::{order::Lsb0, vec::BitVec, view::BitView}; -use core::iter; +use core::{iter, ops::Range}; use half::f16; use itertools::Itertools; use meshopt::{ @@ -105,12 +105,11 @@ impl MeshletMesh { let mut vertex_locks = vec![false; vertices.vertex_count]; // Build further LODs - let mut simplification_queue = Vec::from_iter(0..meshlets.len()); - let mut retry_queue = Vec::new(); + let mut simplification_queue = 0..meshlets.len(); while simplification_queue.len() > 1 { // For each meshlet build a list of connected meshlets (meshlets that share a vertex) let connected_meshlets_per_meshlet = find_connected_meshlets( - &simplification_queue, + simplification_queue.clone(), &meshlets, &position_only_vertex_remap, position_only_vertex_count, @@ -118,7 +117,10 @@ impl MeshletMesh { // Group meshlets into roughly groups of size TARGET_MESHLETS_PER_GROUP, // grouping meshlets with a high number of shared vertices - let groups = group_meshlets(&connected_meshlets_per_meshlet, &simplification_queue); + let groups = group_meshlets( + &connected_meshlets_per_meshlet, + simplification_queue.clone(), + ); // Lock borders between groups to prevent cracks when simplifying lock_group_borders( @@ -131,9 +133,8 @@ impl MeshletMesh { let next_lod_start = meshlets.len(); for group_meshlets in groups.into_iter() { - // If the group only has a single meshlet, we can't simplify it well, so retry later + // If the group only has a single meshlet we can't simplify it if group_meshlets.len() == 1 { - retry_queue.push(group_meshlets[0]); continue; } @@ -146,8 +147,7 @@ impl MeshletMesh { vertex_stride, &vertex_locks, ) else { - // Couldn't simplify the group enough, retry its meshlets later - retry_queue.extend_from_slice(&group_meshlets); + // Couldn't simplify the group enough continue; }; @@ -187,12 +187,8 @@ impl MeshletMesh { ); } - // Set simplification queue to the list of newly created (and retrying) meshlets - simplification_queue.clear(); - simplification_queue.extend(next_lod_start..meshlets.len()); - if !simplification_queue.is_empty() { - simplification_queue.append(&mut retry_queue); - } + // Set simplification queue to the list of newly created meshlets + simplification_queue = next_lod_start..meshlets.len(); } // Copy vertex attributes per meshlet and compress @@ -252,22 +248,22 @@ fn compute_meshlets(indices: &[u32], vertices: &VertexDataAdapter) -> Meshlets { } fn find_connected_meshlets( - simplification_queue: &[usize], + simplification_queue: Range, meshlets: &Meshlets, position_only_vertex_remap: &[u32], position_only_vertex_count: usize, ) -> Vec> { // For each vertex, build a list of all meshlets that use it let mut vertices_to_meshlets = vec![Vec::new(); position_only_vertex_count]; - for (meshlet_queue_id, meshlet_id) in simplification_queue.iter().enumerate() { - let meshlet = meshlets.get(*meshlet_id); + for meshlet_id in simplification_queue.clone() { + let meshlet = meshlets.get(meshlet_id); for index in meshlet.triangles { let vertex_id = position_only_vertex_remap[meshlet.vertices[*index as usize] as usize]; let vertex_to_meshlets = &mut vertices_to_meshlets[vertex_id as usize]; // Meshlets are added in order, so we can just check the last element to deduplicate, // in the case of two triangles sharing the same vertex within a single meshlet - if vertex_to_meshlets.last() != Some(&meshlet_queue_id) { - vertex_to_meshlets.push(meshlet_queue_id); + if vertex_to_meshlets.last() != Some(&meshlet_id) { + vertex_to_meshlets.push(meshlet_id); } } } @@ -275,14 +271,9 @@ fn find_connected_meshlets( // For each meshlet pair, count how many vertices they share let mut meshlet_pair_to_shared_vertex_count = >::default(); for vertex_meshlet_ids in vertices_to_meshlets { - for (meshlet_queue_id1, meshlet_queue_id2) in - vertex_meshlet_ids.into_iter().tuple_combinations() - { + for (meshlet_id1, meshlet_id2) in vertex_meshlet_ids.into_iter().tuple_combinations() { let count = meshlet_pair_to_shared_vertex_count - .entry(( - meshlet_queue_id1.min(meshlet_queue_id2), - meshlet_queue_id1.max(meshlet_queue_id2), - )) + .entry((meshlet_id1.min(meshlet_id2), meshlet_id1.max(meshlet_id2))) .or_insert(0); *count += 1; } @@ -290,12 +281,12 @@ fn find_connected_meshlets( // For each meshlet, gather all other meshlets that share at least one vertex along with their shared vertex count let mut connected_meshlets_per_meshlet = vec![Vec::new(); simplification_queue.len()]; - for ((meshlet_queue_id1, meshlet_queue_id2), shared_count) in - meshlet_pair_to_shared_vertex_count - { + for ((meshlet_id1, meshlet_id2), shared_vertex_count) in meshlet_pair_to_shared_vertex_count { // We record both id1->id2 and id2->id1 as adjacency is symmetrical - connected_meshlets_per_meshlet[meshlet_queue_id1].push((meshlet_queue_id2, shared_count)); - connected_meshlets_per_meshlet[meshlet_queue_id2].push((meshlet_queue_id1, shared_count)); + connected_meshlets_per_meshlet[meshlet_id1 - simplification_queue.start] + .push((meshlet_id2, shared_vertex_count)); + connected_meshlets_per_meshlet[meshlet_id2 - simplification_queue.start] + .push((meshlet_id1, shared_vertex_count)); } // The order of meshlets depends on hash traversal order; to produce deterministic results, sort them @@ -309,15 +300,15 @@ fn find_connected_meshlets( // METIS manual: https://github.com/KarypisLab/METIS/blob/e0f1b88b8efcb24ffa0ec55eabb78fbe61e58ae7/manual/manual.pdf fn group_meshlets( connected_meshlets_per_meshlet: &[Vec<(usize, usize)>], - simplification_queue: &[usize], + simplification_queue: Range, ) -> Vec> { let mut xadj = Vec::with_capacity(simplification_queue.len() + 1); let mut adjncy = Vec::new(); let mut adjwgt = Vec::new(); for connected_meshlets in connected_meshlets_per_meshlet { xadj.push(adjncy.len() as i32); - for (connected_meshlet_queue_id, shared_vertex_count) in connected_meshlets { - adjncy.push(*connected_meshlet_queue_id as i32); + for (connected_meshlet_id, shared_vertex_count) in connected_meshlets { + adjncy.push((connected_meshlet_id - simplification_queue.start) as i32); adjwgt.push(*shared_vertex_count as i32); // TODO: Additional weight based on meshlet spatial proximity } @@ -336,8 +327,8 @@ fn group_meshlets( .unwrap(); let mut groups = vec![SmallVec::new(); partition_count]; - for (meshlet_queue_id, meshlet_group) in group_per_meshlet.into_iter().enumerate() { - groups[meshlet_group as usize].push(simplification_queue[meshlet_queue_id]); + for (i, meshlet_group) in group_per_meshlet.into_iter().enumerate() { + groups[meshlet_group as usize].push(i + simplification_queue.start); } groups }