-
-
Notifications
You must be signed in to change notification settings - Fork 21.5k
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
Make acos and asin safe #76906
Make acos and asin safe #76906
Conversation
Very rough poll for those interested? Either is good as long as we decide! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Given ::asin
/::acos
can always be called directly when desired I prefer this over #76876, seems simpler / potentially less confusing.
This also creates problems in CharacterBody2D because angles are determined by going through acos () and when it returns NAN, often, the internal set_collision_direction () function returns the result of hitting a "wall" because that is the default fall-through case. In this sort of situation, the code should be amended because it doesn't really make sense that the user has to create their own get_floor_angle (), etc. functions to bypass the unsafe version of acos (). |
Yes, this is a snag, anything that relies on Nan will have to use the raw version ( EDIT: get_angle is:
For this to return Nan, If |
A common bug with using acos and asin is that input outside -1 to 1 range will result in Nan output. This can occur due to floating point error in the input. The standard solution is to provide safe_acos function with clamped input. For Godot it may make more sense to make the standard functions safe.
I can't remember the exact details, as it was a while ago, but both normals involved were normalized and I was noticing that the number was slightly outside of the -1.0..1.0 range and therefore acos () was returning NAN. I added the clamp () when I noticed this, and I haven't noticed the problem since. collision_normal was never 0 in the circumstances I encountered. The normals were valid and I was surprised because the documentation states that if the normals are normalized, then you are guaranteed a value that is between -1.0..1.0 inclusive only and that was not the case. |
Ah yes, I was misunderstanding you. You were pointing out that this was previously a bug, and it is now fixed by this PR. 👍 It was indeed quite a nasty bug, because you got easily get Nans there.
After normalizing a vector, the vector will usually be slightly below or slightly above unit length. This tiny float error is enough to get outside the -1 to 1 range, and thus cause the Nan. |
It was the first of a few bugs I've found in the CharacterBody2D code but I can confirm it is easily solved with clamping. |
Thanks! |
Cherry-picked for 4.0.3. |
Also reminder there is a 3.x version #76902 which is mostly similar except there are no unit tests for this in 3.x. If we could review / merge that too while it is fresh in mind it would be great. 👍 |
I'm happy to hear that this is getting patched! That said, if we ever go this route, I would prefer that acos and sin be safe by default, and for niche cases where its range check is a problem, we could have Moreover, having a function called "unsafe" highlights that there's a risk, more than having a slower alternative called "safe" which they should probably be using by default. |
A common bug with using acos and asin is that input outside -1 to 1 range will result in Nan output. This can occur due to floating point error in the input.
The standard solution is to provide safe_acos function with clamped input. For Godot it may make more sense to make the standard functions safe.
Simpler alternative to #76876
Fixes #76857
Notes
::acos
could be called directly on such a rare occasion.