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

Improve error messages for denormalized directions #12278

Merged
merged 5 commits into from
Mar 4, 2024

Conversation

Jondolf
Copy link
Contributor

@Jondolf Jondolf commented Mar 3, 2024

Objective

Dir3 and Dir3A can be rotated using Quats. However, if enough floating point error accumulates or (more commonly) the rotation itself is degenerate (like not normalized), the resulting direction can also become denormalized.

Currently, with debug assertions enabled, it panics in these cases with the message rotated.is_normalized(). This error message is unclear, doesn't give information about how it is denormalized (like is the length too large, NaN, or something else), and is overall not very helpful. Panicking for small-ish error might also be a bit too strict, and has lead to unwanted crashes in crates like bevy_xpbd (although it has also helped in finding actual bugs).

The error message should be clearer and give more context, and it shouldn't cause unwanted crashes.

Solution

Change the debug_assert! to a warning for small error with a (squared length) threshold of 2e-4 and a panic for clear error with a threshold of 2e-2. The warnings mention the direction type and the length of the denormalized vector.

Here's what the error and warning look like:

Error: `Dir3` is denormalized after rotation. The length is 1.014242.
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.

I gave the same treatment to new_unchecked:

Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.

Discussion

Threshold values

The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the squared length in is_normalized (after I corrected it in bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a clear sign of something being critically wrong. I can definitely tune them if there are better thresholds though.

Logging

bevy_math doesn't have bevy_log, so we can't use warn! or error!. This is why I made it use just eprintln! and panic! for now. Let me know if there's a better way of logging errors in bevy_math.

@Jondolf Jondolf added the A-Math Fundamental domain-agnostic mathematical operations label Mar 3, 2024
@alice-i-cecile alice-i-cecile added the C-Usability A targeted quality-of-life change that makes Bevy easier to use label Mar 3, 2024
/// The format used for the logged warning is `"Warning: {warning} The length is {length}`,
/// and similarly for the error.
#[cfg(debug_assertions)]
fn assert_is_normalized(message: &str, length_squared: f32) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it could be a macro, but that might be overkill. It could be nice to have different messages for the warning and error though?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, let's avoid adding macros unless we really need to.

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think we should probably pull in tracing as a direct dependency for bevy_math, but I'm not keen to do so in this PR.

Code looks good though, and since it's behind the debug assertions flag I don't mind.

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Mar 4, 2024
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Mar 4, 2024
Merged via the queue into bevyengine:main with commit 983da76 Mar 4, 2024
26 checks passed
@Jondolf Jondolf deleted the better-direction-warnings branch March 4, 2024 00:19
spectria-limina pushed a commit to spectria-limina/bevy that referenced this pull request Mar 9, 2024
# Objective

`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.

Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).

The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.

## Solution

Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.

Here's what the error and warning look like:

```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```

```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```

I gave the same treatment to `new_unchecked`:

```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```

```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```

---

## Discussion

### Threshold values

The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.

### Logging

`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Math Fundamental domain-agnostic mathematical operations C-Usability A targeted quality-of-life change that makes Bevy easier to use S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants