bevyengine / bevy

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

Panic on `Transform::local_?` calls #12981

Closed DanteMarshal closed 5 months ago

DanteMarshal commented 5 months ago

Bevy version

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

[Optional] Relevant system information

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 commented 5 months ago

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 commented 5 months ago

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 commented 5 months ago

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.

pablo-lua commented 5 months ago

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 commented 5 months ago

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 commented 5 months ago

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 commented 5 months ago

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 commented 2 months ago

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 commented 2 months ago

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 commented 2 months ago

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.