`GlobalTransform::forward` sometimes panics in debug builds
Bevy version
Bevy 0.15.0
[Optional] Relevant system information
- cargo 1.83.0 (5ffbef321 2024-10-29)
- MacOS Sonoma 14.1.1 (23B81)
- SystemInfo { os: "MacOS 14.1.1 ", kernel: "23.1.0", cpu: "Apple M1 Max", core_count: "10", memory: "64.0 GiB" }
- AdapterInfo { name: "Apple M1 Max", vendor: 0, device: 0, device_type: IntegratedGpu, driver: "", driver_info: "", backend: Metal }
What you did
Called GlobalTransform::forward in debug build.
I couldn't create crashing minimal example yet, can't reproduce on minimal setup.
What went wrong
GlobalTransform::forward panics:
thread 'Compute Task Pool (1)' panicked at /Users/matrixdev/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_math-0.15.0/src/direction.rs:63:9:
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is NaN.
stack backtrace:
0: rust_begin_unwind
at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:665:5
1: core::panicking::panic_fmt
at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/core/src/panicking.rs:74:14
2: bevy_math::direction::assert_is_normalized
at /Users/matrixdev/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_math-0.15.0/src/direction.rs:63:9
3: bevy_math::direction::Dir3::new_unchecked
at /Users/matrixdev/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_math-0.15.0/src/direction.rs:402:9
4: bevy_transform::components::global_transform::GlobalTransform::back
at /Users/matrixdev/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_transform-0.15.0/src/components/global_transform.rs:61:13
5: bevy_transform::components::global_transform::GlobalTransform::forward
at /Users/matrixdev/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_transform-0.15.0/src/components/global_transform.rs:67:14
..........
Process finished with exit code 101
Additional information
This happens because GlobalTransform uses Dir3::new_unchecked before normalization:
#[doc=std::concat!("Return the local ", std::stringify!($pos_name), " vector (", std::stringify!($axis) ,").")]
#[inline]
pub fn $pos_name(&self) -> Dir3 {
Dir3::new_unchecked((self.0.matrix3 * Vec3::$axis).normalize())
}
#[doc=std::concat!("Return the local ", std::stringify!($neg_name), " vector (-", std::stringify!($axis) ,").")]
#[inline]
pub fn $neg_name(&self) -> Dir3 {
-self.$pos_name()
}
Which in its place checks for normalization:
pub fn new_unchecked(value: Vec3) -> Self {
#[cfg(debug_assertions)]
assert_is_normalized(
"The vector given to `Dir3::new_unchecked` is not normalized.",
value.length_squared(),
);
Self(value)
}
But this check defeats whole purpose of normalization afterwards... I think plain Dir3::new should be used here instead of manually normalizing it.
This happens because
GlobalTransformusesDir3::new_uncheckedbefore normalization:
Dir3::new_unchecked((self.0.matrix3 * Vec3::$axis).normalize())
It seems the vector is normalized before getting passed into Dir3::new_unchecked. I think the mystery here is why the vectors length is NaN.
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is NaN.
The alternative is Dir3::new(self.0.matrix3 * Vec3::$axis).unwrap(). This doesn't look like a better solution in my opinion.
@pemattern, I found what was happening here. I was animating scale from whatever to zero before hiding an object and panic happens when scale reached zero. because of racing between systems forward was called before despawning.
This probably should not be considered a bug so I'll close this isuue.