jakobhellermann / bevy-inspector-egui

Inspector plugin for the bevy game engine
Apache License 2.0
1.19k stars 173 forks source link

Quaternion values are not updated when modified outside the inspector #40

Closed mcobzarenco closed 2 years ago

mcobzarenco commented 2 years ago

Thanks so much for this great plugin :100:

I noticed that when manipulating Transforms manually, the changes to the rotation are not updated (changes to Quat in general). I tried both WorldInspectorPlugin and InspectorPlugin. Notice the rotation not updating

Peek 2022-01-23 21-19

Above is small change to examples/transform.rs to rotate and translate the cube and set data.transform from the cube's transform

fn rotate_and_translate(mut query: Query<&mut Transform, With<Cube>>) {
    query.single_mut().rotation *= Quat::from_rotation_y(0.01);
    query.single_mut().translation += 0.0001;
}

fn update(mut data: ResMut<Data>, mut query: Query<(&Cube, &mut Transform)>) {
    for (_, mut transform) in query.iter_mut() {
        data.transform = *transform;
    }
}

Looking at the code, from what I can tell, it is likely related to the fact that they are cached, maybe without updating context.id(). As long as the value can change outside the inspector, I am not sure what the correct solution is.

If it is important to avoid the recalculation (?), keeping track instead whether the raw Quat value has changed instead? Apologies if this is not correct -- could the problem be that context.id() should have changed? Not familiar with egui and how to use Id.

            QuatDisplay::Euler => {
                let mut euler_angles = ui
                    .memory()
                    .data
                    .get_temp_mut_or_insert_with(context.id(), || {
                        Euler(Vec3::from(self.to_euler(EulerRot::XYZ)))
                    })
                    .0;

                let changed = euler_angles.ui(ui, Default::default(), context);
                if changed {
                    *self = Quat::from_euler(
                        EulerRot::XYZ,
                        euler_angles.x,
                        euler_angles.y,
                        euler_angles.z,
                    );
                    ui.memory()
                        .data
                        .insert_temp(context.id(), Euler(euler_angles));
                }
                changed
            }
jakobhellermann commented 2 years ago

The reason for caching the euler angles is that going from quat -> euler angles -> quat every frame leads to very unstable results. I pushed a change that will compare the intermediate value to the actual value and if they don't match update the intermediate one, so now external changes should be properly handled.

Can you verify that the fix works by setting

[patch.crates-io]
bevy-inspector-egui = { git = "https://github.com/jakobhellermann/bevy-inspector-egui" }

in your Cargo.toml?

mcobzarenco commented 2 years ago

The reason for caching the euler angles is that going from quat -> euler angles -> quat every frame leads to very unstable results.

Very interesting -- fwiw, I just removed the caching yesterday and failed to observe these cases. To clarify, without caching, you wouldn't do the full conversion quat -> euler angles -> quat every frame

I pushed a change that will compare the intermediate value to the actual value and if they don't match update the intermediate one, so now external changes should be properly handled.

I just tried it locally -- amazing! :100: Thank you so much for the swift fix, much appreciated!