diff --git a/src/geometry/collider_impl.rs b/src/geometry/collider_impl.rs index d98c980c..cc8752d3 100644 --- a/src/geometry/collider_impl.rs +++ b/src/geometry/collider_impl.rs @@ -3,7 +3,7 @@ use na::DVector; #[cfg(all(feature = "dim3", feature = "async-collider"))] use { bevy::prelude::*, - bevy::render::mesh::{Indices, VertexAttributeValues}, + bevy::render::mesh::{Indices, PrimitiveTopology, VertexAttributeValues}, }; use rapier::prelude::{FeatureId, Point, Ray, SharedShape, Vector, DIM}; @@ -739,7 +739,7 @@ fn extract_mesh_vertices_indices(mesh: &Mesh) -> Option<(Vec>, use rapier::na::point; let vertices = mesh.attribute(Mesh::ATTRIBUTE_POSITION)?; - let indices = mesh.indices()?; + let indices = mesh.indices(); let vtx: Vec<_> = match vertices { VertexAttributeValues::Float32(vtx) => Some( @@ -756,11 +756,40 @@ fn extract_mesh_vertices_indices(mesh: &Mesh) -> Option<(Vec>, }?; let idx = match indices { - Indices::U16(idx) => idx + Some(Indices::U16(idx)) => idx .chunks_exact(3) .map(|i| [i[0] as u32, i[1] as u32, i[2] as u32]) .collect(), - Indices::U32(idx) => idx.chunks_exact(3).map(|i| [i[0], i[1], i[2]]).collect(), + Some(Indices::U32(idx)) => idx.chunks_exact(3).map(|i| [i[0], i[1], i[2]]).collect(), + None => { + // Meshes loaded from glTF files may not necessarily have an index buffer + // in order to save memory (e.g. files generated by osm2world), in which case + // there's predefined algorithm to calculate indices for each topology. + match mesh.primitive_topology() { + PrimitiveTopology::TriangleList => { + // [[0, 1, 2], [3, 4, 5], [6, 7, 8], ...] + (0..vtx.len() as u32) + .step_by(3) + .map(|i| [i, i + 1, i + 2]) + .collect() + } + PrimitiveTopology::TriangleStrip => { + // [[0, 1, 2], [2, 1, 3], [2, 3, 4], ...] + (0..vtx.len() as u32 - 2) + .map(|i| { + if i % 2 == 0 { + [i, i + 1, i + 2] + } else { + [i + 1, i, i + 2] + } + }) + .collect() + } + // ignore PointList, LineList, LineStrip: + // they don't have meaningful colliders + _ => return None, + } + } }; Some((vtx, idx))