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
This commit is contained in:
François 2023-08-28 18:58:45 +02:00 committed by GitHub
parent f38549c68d
commit b28f6334da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 2 deletions

View File

@ -11,7 +11,7 @@ use bevy_log::warn;
use bevy_math::{Mat4, Vec3}; use bevy_math::{Mat4, Vec3};
use bevy_pbr::{ use bevy_pbr::{
AlphaMode, DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight, PointLightBundle, AlphaMode, DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight, PointLightBundle,
SpotLight, SpotLightBundle, StandardMaterial, SpotLight, SpotLightBundle, StandardMaterial, MAX_JOINTS,
}; };
use bevy_render::{ use bevy_render::{
camera::{Camera, OrthographicProjection, PerspectiveProjection, Projection, ScalingMode}, 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 { for (&entity, &skin_index) in &entity_to_skin_index_map {
let mut entity = world.entity_mut(entity); let mut entity = world.entity_mut(entity);
let skin = gltf.skins().nth(skin_index).unwrap(); 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()]) .map(|node| node_index_to_entity_map[&node.index()])
.collect(); .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 { entity.insert(SkinnedMesh {
inverse_bindposes: skinned_mesh_inverse_bindposes[skin_index].clone(), inverse_bindposes: skinned_mesh_inverse_bindposes[skin_index].clone(),
joints: joint_entities, joints: joint_entities,

View File

@ -52,7 +52,8 @@ use crate::render::{
#[derive(Default)] #[derive(Default)]
pub struct MeshRenderPlugin; 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::<Mat4>(); const JOINT_SIZE: usize = std::mem::size_of::<Mat4>();
pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE; pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE;
@ -323,6 +324,7 @@ impl SkinnedMeshJoints {
joints joints
.iter_many(&skin.joints) .iter_many(&skin.joints)
.zip(inverse_bindposes.iter()) .zip(inverse_bindposes.iter())
.take(MAX_JOINTS)
.map(|(joint, bindpose)| joint.affine() * *bindpose), .map(|(joint, bindpose)| joint.affine() * *bindpose),
); );
// iter_many will skip any failed fetches. This will cause it to assign the wrong bones, // iter_many will skip any failed fetches. This will cause it to assign the wrong bones,