From b28f6334da3b0d08b54945cf3b0778f4a54b2112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Mon, 28 Aug 2023 18:58:45 +0200 Subject: [PATCH] only take up to the max number of joints (#9351) # Objective - Meshes with a higher number of joints than `MAX_JOINTS` are crashing - Fixes partly #9021 (doesn't crash anymore, but the mesh is not correctly displayed) ## Solution - Only take up to `MAX_JOINTS` joints when extending the buffer --- crates/bevy_gltf/src/loader.rs | 13 ++++++++++++- crates/bevy_pbr/src/render/mesh.rs | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 7b737fec0ed74..b5c1fae3c66a6 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -11,7 +11,7 @@ use bevy_log::warn; use bevy_math::{Mat4, Vec3}; use bevy_pbr::{ AlphaMode, DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight, PointLightBundle, - SpotLight, SpotLightBundle, StandardMaterial, + SpotLight, SpotLightBundle, StandardMaterial, MAX_JOINTS, }; use bevy_render::{ camera::{Camera, OrthographicProjection, PerspectiveProjection, Projection, ScalingMode}, @@ -489,6 +489,7 @@ async fn load_gltf<'a, 'b>( } } + let mut warned_about_max_joints = HashSet::new(); for (&entity, &skin_index) in &entity_to_skin_index_map { let mut entity = world.entity_mut(entity); let skin = gltf.skins().nth(skin_index).unwrap(); @@ -497,6 +498,16 @@ async fn load_gltf<'a, 'b>( .map(|node| node_index_to_entity_map[&node.index()]) .collect(); + if joint_entities.len() > MAX_JOINTS && warned_about_max_joints.insert(skin_index) { + warn!( + "The glTF skin {:?} has {} joints, but the maximum supported is {}", + skin.name() + .map(|name| name.to_string()) + .unwrap_or_else(|| skin.index().to_string()), + joint_entities.len(), + MAX_JOINTS + ); + } entity.insert(SkinnedMesh { inverse_bindposes: skinned_mesh_inverse_bindposes[skin_index].clone(), joints: joint_entities, diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index c1f0fed803d3d..a52c54557ed82 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -52,7 +52,8 @@ use crate::render::{ #[derive(Default)] pub struct MeshRenderPlugin; -const MAX_JOINTS: usize = 256; +/// Maximum number of joints supported for skinned meshes. +pub const MAX_JOINTS: usize = 256; const JOINT_SIZE: usize = std::mem::size_of::(); pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE; @@ -323,6 +324,7 @@ impl SkinnedMeshJoints { joints .iter_many(&skin.joints) .zip(inverse_bindposes.iter()) + .take(MAX_JOINTS) .map(|(joint, bindpose)| joint.affine() * *bindpose), ); // iter_many will skip any failed fetches. This will cause it to assign the wrong bones,