Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic on Transform::local_? calls #12981

Closed
DanteMarshal opened this issue Apr 15, 2024 · 10 comments
Closed

Panic on Transform::local_? calls #12981

DanteMarshal opened this issue Apr 15, 2024 · 10 comments
Labels
A-Transform Translations, rotations and scales C-Bug An unexpected or incorrect behavior S-User-Error This issue was caused by a mistake in the user's approach

Comments

@DanteMarshal
Copy link

Bevy version

  • bevy 0.13.2 (from crates.io)

The release number or commit hash of the version you're using.

[Optional] Relevant system information

  • cargo 1.76.0 (c84b36747 2024-01-18)
  • Windows 11 22H2 22621.3447

What you did

I'm trying to learn bevy, and I was making a very simple scene to move a cube. Here's the code :

use bevy::{
    input::{keyboard::KeyboardInput, mouse::MouseMotion},
    prelude::*,
};
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(bevy_framepace::FramepacePlugin)
        .add_systems(Startup, setup)
        .add_systems(Update, update)
        .run();
}
fn update(
    mut cube: Query<(&mut Player, &mut Transform)>,
    mut keys: EventReader<KeyboardInput>,
    mut mouse: EventReader<MouseMotion>,
    time: Res<Time>,
) {
    let mut player = cube.single_mut();
    for event in keys.read() {
        if event.key_code == KeyCode::KeyP {
            player.0.move_direction += Vec3::from(player.1.local_y());
        }
        if event.key_code == KeyCode::KeyT {
            player.0.move_direction -= Vec3::from(player.1.local_y());
        }
        if event.key_code == KeyCode::KeyW {
            player.0.move_direction += Vec3::from(player.1.local_z());
        }
        if event.key_code == KeyCode::KeyR {
            player.0.move_direction -= Vec3::from(player.1.local_z());
        }
        if event.key_code == KeyCode::KeyA {
            player.0.move_direction -= Vec3::from(player.1.local_x());
        }
        if event.key_code == KeyCode::KeyS {
            player.0.move_direction += Vec3::from(player.1.local_x());
        }
    }
    player.1.translation += time.delta_seconds() * player.0.move_direction;
    player.1.set_changed();
    for event in mouse.read() {
        player.1.rotate_local_axis(0.001 * Vec3::X, event.delta.y);
        player.1.rotate_local_axis(0.001 * Vec3::Y, event.delta.x);
        player.1.set_changed();
    }
}
fn setup(
    mut framepace: ResMut<bevy_framepace::FramepaceSettings>,
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    framepace.limiter = bevy_framepace::Limiter::from_framerate(30.0);
    // circular base
    commands.spawn(PbrBundle {
        mesh: meshes.add(Circle::new(4.0)),
        material: materials.add(Color::WHITE),
        transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
        ..default()
    });
    // cube
    commands.spawn(PbrBundle {
        mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)),
        material: materials.add(Color::rgb_u8(124, 144, 255)),
        transform: Transform::from_xyz(0.0, 0.5, 0.0),
        ..default()
    });
    // light
    commands.spawn(PointLightBundle {
        point_light: PointLight {
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(4.0, 8.0, 4.0),
        ..default()
    });
    // camera
    commands.spawn((
        Player::default(),
        Camera3dBundle {
            transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
            ..default()
        },
    ));
}
#[derive(Default, Component)]
struct Player {
    move_direction: Vec3,
}

What went wrong

Panics on one of the local_? calls, Here's the backtrace from one of them :

thread 'Compute Task Pool (0)' panicked at A:/Prog/Dev/Rust/Win/CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_transform-0.13.2\src\components\transform.rs:229:51:
called `Result::unwrap()` on an `Err` value: Zero
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library\std\src\panicking.rs:645
   1: core::panicking::panic_fmt
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library\core\src\panicking.rs:72
   2: core::result::unwrap_failed
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library\core\src\result.rs:1649
   3: enum2$<core::result::Result<bevy_math::primitives::dim3::Direction3d,bevy_math::primitives::InvalidDirectionError> >::unwrap<bevy_math::primitives::dim3::Direction3d,bevy_math::primitives::InvalidDirectionError>
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\result.rs:1073
   4: bevy_transform::components::transform::Transform::local_z
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_transform-0.13.2\src\components\transform.rs:229
   5: learning::update
             at .\src\main.rs:31
   6: core::ops::function::FnMut::call_mut<void (*)(bevy_ecs::system::query::Query<tuple$<ref_mut$<learning::Player>,ref_mut$<bevy_transform::components::transform::Transform> >,tuple$<> >,bevy_ecs::event::EventReader<bevy_input::keyboard::KeyboardInput>,bevy_e
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\ops\function.rs:166
   7: core::ops::function::impls::impl$3::call_mut<tuple$<bevy_ecs::system::query::Query<tuple$<ref_mut$<learning::Player>,ref_mut$<bevy_transform::components::transform::Transform> >,tuple$<> >,bevy_ecs::event::EventReader<bevy_input::keyboard::KeyboardInput>,
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\ops\function.rs:294
   8: bevy_ecs::system::function_system::impl$17::run::call_inner<tuple$<>,bevy_ecs::system::query::Query<tuple$<ref_mut$<learning::Player>,ref_mut$<bevy_transform::components::transform::Transform> >,tuple$<> >,bevy_ecs::event::EventReader<bevy_input::keyboard
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_ecs-0.13.2\src\system\function_system.rs:656
   9: bevy_ecs::system::function_system::impl$17::run<tuple$<>,void (*)(bevy_ecs::system::query::Query<tuple$<ref_mut$<learning::Player>,ref_mut$<bevy_transform::components::transform::Transform> >,tuple$<> >,bevy_ecs::event::EventReader<bevy_input::keyboard::K
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_ecs-0.13.2\src\system\function_system.rs:659
  10: bevy_ecs::system::function_system::impl$6::run_unsafe<void (*)(bevy_ecs::system::query::Query<tuple$<ref_mut$<learning::Player>,ref_mut$<bevy_transform::components::transform::Transform> >,tuple$<> >,bevy_ecs::event::EventReader<bevy_input::keyboard::Keyb
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_ecs-0.13.2\src\system\function_system.rs:499
  11: bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block$0::closure$0
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_ecs-0.13.2\src\schedule\executor\multi_threaded.rs:534
  12: core::ops::function::FnOnce::call_once<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block$0::closure_env$0,tuple$<> >
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\ops\function.rs:250
  13: core::panic::unwind_safe::impl$23::call_once<tuple$<>,bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block$0::closure_env$0>
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\panic\unwind_safe.rs:272
  14: std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block$0::closure_env$0>,tuple$<> >  
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panicking.rs:552
  15: hashbrown::raw::inner::sse2::Group::load
  16: std::panicking::try<tuple$<>,core::panic::unwind_safe::AssertUnwindSafe<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block$0::closure_env$0> >
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panicking.rs:516
  17: std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block$0::closure_env$0>,tuple$<> >      
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panic.rs:142
  18: bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block$0
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_ecs-0.13.2\src\schedule\executor\multi_threaded.rs:529
  19: core::panic::unwind_safe::impl$26::poll<enum2$<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block_env$0> >
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\panic\unwind_safe.rs:297
  20: futures_lite::future::impl$9::poll::closure$0<core::panic::unwind_safe::AssertUnwindSafe<enum2$<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block_env$0> > >
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\futures-lite-2.3.0\src\future.rs:588
  21: core::panic::unwind_safe::impl$23::call_once<enum2$<core::task::poll::Poll<tuple$<> > >,futures_lite::future::impl$9::poll::closure_env$0<core::panic::unwind_safe::AssertUnwindSafe<enum2$<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\panic\unwind_safe.rs:272
  22: std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<futures_lite::future::impl$9::poll::closure_env$0<core::panic::unwind_safe::AssertUnwindSafe<enum2$<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_bloc
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panicking.rs:552
  23: hashbrown::raw::inner::sse2::Group::load
  24: std::panicking::try<enum2$<core::task::poll::Poll<tuple$<> > >,core::panic::unwind_safe::AssertUnwindSafe<futures_lite::future::impl$9::poll::closure_env$0<core::panic::unwind_safe::AssertUnwindSafe<enum2$<bevy_ecs::schedule::executor::multi_threaded::imp
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panicking.rs:516
  25: std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<futures_lite::future::impl$9::poll::closure_env$0<core::panic::unwind_safe::AssertUnwindSafe<enum2$<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block_en
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panic.rs:142
  26: futures_lite::future::impl$9::poll<core::panic::unwind_safe::AssertUnwindSafe<enum2$<bevy_ecs::schedule::executor::multi_threaded::impl$3::spawn_system_task::async_block_env$0> > >       
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\futures-lite-2.3.0\src\future.rs:588
  27: async_executor::impl$5::spawn_inner::async_block$0<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::any::Any,core::marker::Send>,alloc::alloc::Global> > >,futures_lite::future::CatchUnwind<core::panic::unwind_safe::AssertUnwindSafe<enum2$
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\async-executor-1.11.0\src\lib.rs:243
  28: async_task::raw::impl$3::run::closure$1<enum2$<async_executor::impl$5::spawn_inner::async_block_env$0<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::any::Any,core::marker::Send>,alloc::alloc::Global> > >,futures_lite::future::CatchUnwin
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\async-task-4.7.0\src\raw.rs:550
  29: core::ops::function::FnOnce::call_once<async_task::raw::impl$3::run::closure_env$1<enum2$<async_executor::impl$5::spawn_inner::async_block_env$0<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::any::Any,core::marker::Send>,alloc::alloc::G
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\ops\function.rs:250
  30: core::panic::unwind_safe::impl$23::call_once<enum2$<core::task::poll::Poll<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::any::Any,core::marker::Send>,alloc::alloc::Global> > > > >,async_task::raw::impl$3::run::closure_env$1<enum2$<asyn
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\panic\unwind_safe.rs:272
  31: std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<async_task::raw::impl$3::run::closure_env$1<enum2$<async_executor::impl$5::spawn_inner::async_block_env$0<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::any::Any,co
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panicking.rs:552
  32: hashbrown::raw::inner::sse2::Group::load
  33: std::panicking::try<enum2$<core::task::poll::Poll<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::any::Any,core::marker::Send>,alloc::alloc::Global> > > > >,core::panic::unwind_safe::AssertUnwindSafe<async_task::raw::impl$3::run::closure
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panicking.rs:516
  34: std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<async_task::raw::impl$3::run::closure_env$1<enum2$<async_executor::impl$5::spawn_inner::async_block_env$0<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::any::Any,core::
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panic.rs:142
  35: async_task::raw::RawTask<enum2$<async_executor::impl$5::spawn_inner::async_block_env$0<enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<dyn$<core::any::Any,core::marker::Send>,alloc::alloc::Global> > >,futures_lite::future::CatchUnwind<core::panic::
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\async-task-4.7.0\src\raw.rs:549
  36: async_task::runnable::Runnable<tuple$<> >::run<tuple$<> >
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\async-task-4.7.0\src\runnable.rs:781
  37: async_executor::impl$5::run::async_fn$0::async_block$0<enum2$<core::result::Result<tuple$<>,async_channel::RecvError> >,futures_lite::future::Or<enum2$<bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure$0::closure$0::async_block_en
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\async-executor-1.11.0\src\lib.rs:358
  38: futures_lite::future::impl$7::poll<enum2$<core::result::Result<tuple$<>,async_channel::RecvError> >,futures_lite::future::Or<enum2$<bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure$0::closure$0::async_block_env$0>,async_channel::
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\futures-lite-2.3.0\src\future.rs:449
  39: async_executor::impl$5::run::async_fn$0<enum2$<core::result::Result<tuple$<>,async_channel::RecvError> >,futures_lite::future::Or<enum2$<bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure$0::closure$0::async_block_env$0>,async_chan
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\async-executor-1.11.0\src\lib.rs:365
  40: futures_lite::future::block_on::closure$0<enum2$<core::result::Result<tuple$<>,async_channel::RecvError> >,enum2$<async_executor::impl$5::run::async_fn_env$0<enum2$<core::result::Result<tuple$<>,async_channel::RecvError> >,futures_lite::future::Or<enum2$<
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\futures-lite-2.3.0\src\future.rs:99
  41: std::thread::local::LocalKey<core::cell::RefCell<tuple$<parking::Parker,core::task::wake::Waker> > >::try_with<core::cell::RefCell<tuple$<parking::Parker,core::task::wake::Waker> >,futures_lite::future::block_on::closure_env$0<enum2$<core::result::Result<
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\thread\local.rs:270
  42: std::thread::local::LocalKey<core::cell::RefCell<tuple$<parking::Parker,core::task::wake::Waker> > >::with<core::cell::RefCell<tuple$<parking::Parker,core::task::wake::Waker> >,futures_lite::future::block_on::closure_env$0<enum2$<core::result::Result<tupl
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\thread\local.rs:246
  43: futures_lite::future::block_on<enum2$<core::result::Result<tuple$<>,async_channel::RecvError> >,enum2$<async_executor::impl$5::run::async_fn_env$0<enum2$<core::result::Result<tuple$<>,async_channel::RecvError> >,futures_lite::future::Or<enum2$<bevy_tasks:
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\futures-lite-2.3.0\src\future.rs:78
  44: bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure$0::closure$0
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_tasks-0.13.2\src\task_pool.rs:180
  45: std::panicking::try::do_call<bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure$0::closure_env$0,enum2$<core::result::Result<tuple$<>,async_channel::RecvError> > >
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panicking.rs:552
  46: concurrent_queue::sync::prelude::impl$1::with_mut<tuple$<>,concurrent_queue::bounded::impl$1::drop::closure_env$0<tuple$<> > >
  47: std::panicking::try<enum2$<core::result::Result<tuple$<>,async_channel::RecvError> >,bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure$0::closure_env$0>
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panicking.rs:516
  48: std::panic::catch_unwind<bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure$0::closure_env$0,enum2$<core::result::Result<tuple$<>,async_channel::RecvError> > >    
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\panic.rs:142
  49: bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure$0
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_tasks-0.13.2\src\task_pool.rs:174
  50: std::thread::local::LocalKey<async_executor::LocalExecutor>::try_with<async_executor::LocalExecutor,bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure_env$0,tuple$<> >
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\thread\local.rs:270
  51: std::thread::local::LocalKey<async_executor::LocalExecutor>::with<async_executor::LocalExecutor,bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0::closure_env$0,tuple$<> >
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\std\src\thread\local.rs:246
  52: bevy_tasks::task_pool::impl$2::new_internal::closure$0::closure$0
             at A:\Prog\Dev\Rust\Win\CargoHome\registry\src\index.crates.io-6f17d22bba15001f\bevy_tasks-0.13.2\src\task_pool.rs:167
  53: core::hint::black_box
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce\library\core\src\hint.rs:286
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Encountered a panic in system `learning::update`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!

Additional information

I think it happens the moment I press a key that is the opposite of a key I pressed before. For example, if I press Left (KeyA) nothing happens, but then pressing Right (KeyS) will panic afterwards.

@DanteMarshal DanteMarshal added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Apr 15, 2024
@DanteMarshal
Copy link
Author

Update

Made a few changes, after removing the for loop on mouse.read() I don't get the panics anymore.

I don't know if I'm doing something wrong or if this is really a bug !

Here's the new code, I still get the panics when I uncomment the mouse.read() loop.

use bevy::{
    input::{keyboard::KeyboardInput, mouse::MouseMotion, ButtonState},
    prelude::*,
};
fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(bevy_framepace::FramepacePlugin)
        .add_systems(Startup, setup)
        .add_systems(Update, update)
        .run();
}
fn update(
    mut cube: Query<(&mut Player, &mut Transform)>,
    mut keys: EventReader<KeyboardInput>,
    mut mouse: EventReader<MouseMotion>,
    time: Res<Time>,
) {
    let mut player = cube.single_mut();
    for event in keys.read() {
        if event.key_code == KeyCode::KeyR {
            match event.state {
                ButtonState::Pressed => player.0.move_direction.y = 1.0,
                ButtonState::Released => player.0.move_direction.y = 0.0,
            }
        }
        if event.key_code == KeyCode::KeyF {
            match event.state {
                ButtonState::Pressed => player.0.move_direction.y = -1.0,
                ButtonState::Released => player.0.move_direction.y = 0.0,
            }
        }
        if event.key_code == KeyCode::KeyW {
            match event.state {
                ButtonState::Pressed => player.0.move_direction.z = -1.0,
                ButtonState::Released => player.0.move_direction.z = 0.0,
            }
        }
        if event.key_code == KeyCode::KeyS {
            match event.state {
                ButtonState::Pressed => player.0.move_direction.z = 1.0,
                ButtonState::Released => player.0.move_direction.z = 0.0,
            }
        }
        if event.key_code == KeyCode::KeyD {
            match event.state {
                ButtonState::Pressed => player.0.move_direction.x = 1.0,
                ButtonState::Released => player.0.move_direction.x = 0.0,
            }
        }
        if event.key_code == KeyCode::KeyA {
            match event.state {
                ButtonState::Pressed => player.0.move_direction.x = -1.0,
                ButtonState::Released => player.0.move_direction.x = 0.0,
            }
        }
    }
    let translation = time.delta_seconds()
        * Vec3::new(
            player.1.local_x().dot(player.0.move_direction),
            player.1.local_y().dot(player.0.move_direction),
            player.1.local_z().dot(player.0.move_direction),
        );
    player.1.translation += translation;
    // for event in mouse.read() {
    //     player
    //         .1
    //         .rotate_local_axis(time.delta_seconds() * Vec3::X, event.delta.y);
    //     player
    //         .1
    //         .rotate_local_axis(time.delta_seconds() * Vec3::Y, event.delta.x);
    // }
    player.1.set_changed();
}
fn setup(
    mut framepace: ResMut<bevy_framepace::FramepaceSettings>,
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    framepace.limiter = bevy_framepace::Limiter::from_framerate(30.0);
    // circular base
    commands.spawn(PbrBundle {
        mesh: meshes.add(Circle::new(4.0)),
        material: materials.add(Color::WHITE),
        transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
        ..default()
    });
    // cube
    commands.spawn(PbrBundle {
        mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)),
        material: materials.add(Color::rgb_u8(124, 144, 255)),
        transform: Transform::from_xyz(0.0, 0.5, 0.0),
        ..default()
    });
    // light
    commands.spawn(PointLightBundle {
        point_light: PointLight {
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(4.0, 8.0, 4.0),
        ..default()
    });
    // camera
    commands.spawn((
        Player::default(),
        Camera3dBundle {
            transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
            ..default()
        },
    ));
}
#[derive(Default, Component)]
struct Player {
    move_direction: Vec3,
}

@mweatherley
Copy link
Contributor

I haven't looked really deeply into this yet, but I'm guessing this is caused by repeated calls to rotate_local_axis causing the rotation quaternion to denormalize, since Transform::rotate_local just multiplies the current rotation quaternion by another one (so errors accumulate).

@mweatherley
Copy link
Contributor

Oh, on second glance, Quat::from_axis_angle, which is called in Transform::rotate_local_axis, expects the input vector to be normalized. It looks like our API doesn't explain this, but the first input to rotate_local_axis is definitely supposed to be a unit vector.

github-merge-queue bot pushed a commit that referenced this issue Apr 16, 2024
…`Dir3` (#12986)

# Objective

Related to #12981

Presently, there is a footgun where we allow non-normalized vectors to
be passed in the `axis` parameters of `Transform::rotate_axis` and
`Transform::rotate_local_axis`. These methods invoke
`Quat::from_axis_angle` which expects the vector to be normalized. This
PR aims to address this.

## Solution

Require `Dir3`-valued `axis` parameters for these functions so that the
vector's normalization can be enforced at type-level.

---

## Migration Guide

All calls to `Transform::rotate_axis` and `Transform::rotate_local_axis`
will need to be updated to use a `Dir3` for the `axis` parameter rather
than a `Vec3`. For a general input, this means calling `Dir3::new` and
handling the `Result`, but if the previous vector is already known to be
normalized, `Dir3::new_unchecked` can be called instead. Note that
literals like `Vec3::X` also have corresponding `Dir3` literals; e.g.
`Dir3::X`, `Dir3::NEG_Y` and so on.

---

## Discussion

This axis input is unambigiously a direction instead of a vector, and
that should probably be reflected and enforced by the function
signature. In previous cases where we used, e.g., `impl TryInto<Dir3>`,
the associated methods already implemented (and required!) additional
fall-back logic, since the input is conceptually more complicated than
merely specifying an axis. In this case, I think it's fairly
cut-and-dry, and I'm pretty sure these methods just predate our
direction types.
@pablo-lua pablo-lua added S-User-Error This issue was caused by a mistake in the user's approach A-Transform Translations, rotations and scales and removed S-Needs-Triage This issue needs to be labelled labels Apr 16, 2024
@pablo-lua
Copy link
Contributor

Well, this is a user error that is now solved by #12986, So I'm closing this as completed, feel free to open this again if you see something wrong!

@DanteMarshal
Copy link
Author

DanteMarshal commented Apr 18, 2024

Thanks guys. One question though, I still didn't get what the cause is.
I'm guessing it's because I wrote time.delta_seconds() * Vec3::X which is not a unit vector, so in that case will it be fixed by rotate_local_axis(Vec3::X, time.delta_seconds() * event.delta.y) ?
Just wanna make sure I understood correctly.

@pablo-lua
Copy link
Contributor

pablo-lua commented Apr 18, 2024

The problem is that the Vec is not normalized. If you have a look at the internal function, it uses a function Quat::from_axis (IIRC) that will panic if you use a denormalized vec. So, to solve this, you just need to normalize your final vec. Now, using Dir3, we will assert that everything is normalized.

@mweatherley
Copy link
Contributor

The problem is that the Vec is not normalized. If you have a look at the internal function, it uses a function Quat::from_axis (IIRC) that will panic if you use a denormalized vec. So, to solve this, you just need to normalize your final vec. Now, using Dir3, we will assert that everything is normalized.

I don't think it actually panics unless glam_assert is enabled, but it would still cause other weird behaviors which could easily be at the root of the problem (e.g. causing the quaternion to denormalize).

That being said, do try using a normalized vector as input and seeing if the crash still occurs; if it does, you might need to renormalize the rotation quaternion every so often.

@ramirezmike
Copy link
Contributor

I'm getting a panic on this on 0.14 when I leave my game running long enough that it randomly happens.

thread 'Compute Task Pool (6)' panicked at /home/mramirez/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_transform-0.14.0/src/components/transform.rs:264:44:

In my code I'm just doing calls to transform.forward() but it seems there's a scenario that causes the Dir3::new(self.rotation * Vec3::Z).unwrap() in local_z to panic. I'll see if I can gather more context for why this happens.

@mweatherley
Copy link
Contributor

Are you changing the transform incrementally? The only way that unwrap should ever fail is if the quaternion representing the rotation is extremely denormalized.

@ramirezmike
Copy link
Contributor

Are you changing the transform incrementally?

Not.. intentionally... I'm using Avian physics and the transform of this object is being modified by impulses.. it looks like at some point the rotation gets set to this denormalized value. So this panics

Transform::from_rotation(Quat::from_array([0.0, -0.0, 0.0, 0.0])).forward();

I'm unsure what causes the rotation to end up 0.0, -0.0, 0.0, 0.0, but it's pretty unexpected that calling Transform::forward can panic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Transform Translations, rotations and scales C-Bug An unexpected or incorrect behavior S-User-Error This issue was caused by a mistake in the user's approach
Projects
None yet
Development

No branches or pull requests

4 participants