bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
35.03k stars 3.44k forks source link

translated skinned mesh weirdness #10447

Closed robtfm closed 7 months ago

robtfm commented 10 months ago

Bevy version

0.12

What you did

loaded this skinned mesh and modified it's translation as +1x per second (nb the file needs to be renamed to something.glb)

What went wrong

it mostly works, but a couple of vertices seem to only partly respect the translation.

i see the same behaviour with several other meshes so i don't think it's anything particular about this mesh. i didn't see this problem in 0.11.3.

Additional information

https://github.com/bevyengine/bevy/assets/50659922/951cda7d-3ce4-4417-9f8f-228cfe165874

the changes i made in scene viewer:

diff --git a/examples/tools/scene_viewer/main.rs b/examples/tools/scene_viewer/main.rs
index 1f53b5f17..e15278203 100644
--- a/examples/tools/scene_viewer/main.rs
+++ b/examples/tools/scene_viewer/main.rs
@@ -20,6 +20,7 @@ mod camera_controller_plugin;
 mod morph_viewer_plugin;
 mod scene_viewer_plugin;

+use bevy_internal::render::view::NoFrustumCulling;
 use camera_controller_plugin::{CameraController, CameraControllerPlugin};
 use morph_viewer_plugin::MorphViewerPlugin;
 use scene_viewer_plugin::{SceneHandle, SceneViewerPlugin};
@@ -86,18 +87,19 @@ fn setup_scene_after_load(
     mut setup: Local<bool>,
     mut scene_handle: ResMut<SceneHandle>,
     asset_server: Res<AssetServer>,
-    meshes: Query<(&GlobalTransform, Option<&Aabb>), With<Handle<Mesh>>>,
+    meshes: Query<(Entity, &GlobalTransform, Option<&Aabb>), With<Handle<Mesh>>>,
 ) {
     if scene_handle.is_loaded && !*setup {
         *setup = true;
         // Find an approximate bounding box of the scene from its meshes
-        if meshes.iter().any(|(_, maybe_aabb)| maybe_aabb.is_none()) {
+        if meshes.iter().any(|(_, _, maybe_aabb)| maybe_aabb.is_none()) {
             return;
         }

         let mut min = Vec3A::splat(f32::MAX);
         let mut max = Vec3A::splat(f32::MIN);
-        for (transform, maybe_aabb) in &meshes {
+        for (ent, transform, maybe_aabb) in &meshes {
+            commands.entity(ent).insert(NoFrustumCulling);
             let aabb = maybe_aabb.unwrap();
             // If the Aabb had not been rotated, applying the non-uniform scale would produce the
             // correct bounds. However, it could very well be rotated and so we first convert to
diff --git a/examples/tools/scene_viewer/scene_viewer_plugin.rs b/examples/tools/scene_viewer/scene_viewer_plugin.rs
index 3a41efe06..da3cb89b5 100644
--- a/examples/tools/scene_viewer/scene_viewer_plugin.rs
+++ b/examples/tools/scene_viewer/scene_viewer_plugin.rs
@@ -78,6 +78,7 @@ impl Plugin for SceneViewerPlugin {
                     update_lights,
                     camera_tracker,
                     toggle_bounding_boxes.run_if(input_just_pressed(KeyCode::B)),
+                    move_marked,
                 ),
             );
     }
@@ -87,7 +88,18 @@ fn toggle_bounding_boxes(mut config: ResMut<GizmoConfig>) {
     config.aabb.draw_all ^= true;
 }

+
+#[derive(Component)]
+pub struct Marker;
+
+fn move_marked(mut q: Query<&mut Transform, With<Marker>>, time: Res<Time>) {
+    for mut t in q.iter_mut() {
+        t.translation = Vec3::X * 0f32.max(time.elapsed_seconds() - 10.0);
+    }
+}
+
 fn scene_load_check(
+    mut commands: Commands,
     asset_server: Res<AssetServer>,
     mut scenes: ResMut<Assets<Scene>>,
     gltf_assets: Res<Assets<Gltf>>,
@@ -128,8 +140,14 @@ fn scene_load_check(
                             maybe_directional_light.is_some() || maybe_point_light.is_some()
                         });

+                let parent = commands.spawn((SpatialBundle {
+                    // transform: Transform::from_translation(Vec3::X * 2000.0),
+                    ..Default::default()
+                },
+                Marker,)).id();
+
                 scene_handle.instance_id =
-                    Some(scene_spawner.spawn(gltf_scene_handle.clone_weak()));
+                    Some(scene_spawner.spawn_as_child(gltf_scene_handle.clone_weak(), parent));

                 info!("Spawning scene...");
             }
robtfm commented 10 months ago

this is due to the vertex weights not summing to 1, so i can avoid it by fixing up my source data, but i think this should probably be auto-corrected.

rafalh commented 10 months ago

I stepped onto this during migration to 0.12 and it caused some headache before finding this issue. I have no opinion if it should be auto-corrected or not but maybe mentioning it in migration guide would help people with custom mesh loaders.