-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
Stable interpolation and smooth following #13741
Stable interpolation and smooth following #13741
Conversation
I didn't label this for Animation or Color since it technically doesn't touch those things, but feedback from those directions (persuant to my comments in the description or otherwise) is obviously still welcome :) |
examples/math/smooth_follow.rs
Outdated
let abs_delta = (target_pos.0 - target.translation).norm(); | ||
|
||
// Avoid overshooting in case of high values of `delta_time``: | ||
let magnitude = min_by(abs_delta, delta_time * target_speed.0, |f0, f1| { |
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.
nitpick:
could
let magnitude = abs_delta.min(delta_time * target_speed.0);
work here?
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.
I forgot about f32::min
and was just thinking of the Ord
version. Good catch!
/// # let delta_time: f32 = 1.0 / 60.0; | ||
/// let mut object_position: Vec3 = Vec3::ZERO; | ||
/// let target_position: Vec3 = Vec3::new(2.0, 3.0, 5.0); | ||
/// // Decay rate of ln(10) => after 1 second, remaining distance is 1/10th |
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.
praise: I had the exact question of how can I as a user approximate how long it would take a follower to reach a target- love that you added this example
// The two are really close, so let's generate a new target position: | ||
Err(_) => { | ||
let legal_region = Cuboid::from_size(Vec3::splat(4.0)); | ||
*target_pos = TargetPosition(legal_region.sample_interior(&mut rng.0)); |
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.
praise: Elegant 👍
// Conservatively, we presently only apply this for normed vector spaces, where the notion | ||
// of being constant-speed is literally true. The technical axioms are satisfied for any | ||
// VectorSpace type, but the "natural from the semantics" part is less clear in general. | ||
impl<V> StableInterpolate for V |
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.
question: I saw that neither this blanket impl nor the concrete impls below add an impl for any color type.
I see color types can lerp
via this trait: http://dev-docs.bevyengine.org/bevy/math/trait.VectorSpace.html
I'm curious how smooth nudging would look like for colors.
I suppose there is a reason why colors are left out- they probably don't meet the requirements for StableInterpolate
?
EDIT: I read the OP description now and I see it mentions colors being left out intentionally but that it could possibly have an impl later, that sounds promising.
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.
We discussed on another PR, colors are very different from other types and there's a perceptual component to blending them. I general it makes few sense to treat them like other math types, except for trivial cases.
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.
Yeah, precisely as djeedai says. The way I see it is that despite the fact that existing color mixing satisfies the interpolation laws, it's still unclear that it's actually "canonical" enough to warrant being included here. For example, HSV color space does some kind of cylindrical interpolation, but "uniformity" in that space only has to do with the way colors are represented, so a constant-speed path in that space is not necessarily semantically meaningful. Perhaps a stronger case could be made in perceptually uniform color spaces, but that's quite a nuanced matter that I'll leave to the color people. :)
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.
It'd like to see colors and animation revisited once the curves api is out of the oven. The policy that has worked the best for us so far is to design useful things in bevy_math
and then later go back and integrate them.
smooth-follow.mp4This is your example but with 1k spheres, works great. I tried different amount of targets/followers, changing decay rates and speeds etc. and everything works as expected. |
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.
Approving on the basis of:
- It's something I've wanted to see in Bevy
- As a user it feels elegant to use
- I tried the PR and it works well
But the math itself I'll leave to others- not my strength
/// 1. The notion of interpolation should follow naturally from the semantics of the type, so | ||
/// that inferring the interpolation mode from the type alone is sensible. | ||
/// | ||
/// 2. The interpolation recovers something equivalent to the starting value at `t = 0.0` |
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.
The doc on interpolate_stable()
seems to say you recover exactly self and other. Why the vague "something equivalent to" mention here?
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.
I chose this loosey-goosey wording around "equivalence" because what I really mean is that they don't necessarily have to be data-identical, but they do have to be semantically identical. An example of this is that a Quat
as used in glam
/bevy_math
represents a rotation, and it's the case that slerp
doesn't always return a data-identical quaternion at its end; however, it does always return one that represents the same rotation as the one that was input. I'll amend the docs to make this more clear and make the two more consistent.
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.
Good point on Quat
rotations. Maybe it's worth writing down that example to explain the wording.
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.
I like the new clarification you added here.
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.
Wonderful. The properties of interpolate_stable
seem extremely useful and well defined, and the documentation is truly top-notch.
I've very pleased to see your investigation of the curves api yielding related work like this.
Objective
Partially address #13408
Rework of #13613
Unify the very nice forms of interpolation specifically present in
bevy_math
under a shared trait upon which further behavior can be based.The ideas in this PR were prompted by Lerp smoothing is broken by Freya Holmer.
Solution
There is a new trait
StableInterpolate
inbevy_math::common_traits
which enshrines a quite-specific notion of interpolation with a lot of guarantees:This trait has a blanket implementation over
NormedVectorSpace
, wherelerp
is used, along with implementations forRot2
,Quat
, and the direction types using variants ofslerp
. Other areas may choose to implement this trait in order to hook into its functionality, but the stringent requirements must actually be met.This trait bears no direct relationship with
bevy_animation
'sAnimatable
trait, although they may choose to useinterpolate_stable
in their trait implementations if they wish, as both traits involve type-inferred interpolations of the same kind.StableInterpolate
is not a supertrait ofAnimatable
for a couple reasons:bevy_animation
rather than ofbevy_math
. (Consider also that inferring interpolation from types is not universally desirable.)Similarly, this is not implemented on
bevy_color
's color types, although their current mixing behavior does meet the conditions of the trait.As an aside, the subdivision-stability condition is of interest specifically for the Curve RFC, where it also ensures a kind of stability for subsampling.
Importantly, this trait ensures that the "smooth following" behavior defined in this PR behaves predictably:
As the documentation indicates, the intention is for this to be called in game update systems, and
delta
would be something likeTime::delta_seconds
in Bevy, allowing positions, orientations, and so on to smoothly follow a target. A new example,smooth_follow
, demonstrates a basic implementation of this, with a sphere smoothly following a sharply moving target:smooth_follow.mov
Testing
Tested by running the example with various parameters.