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

Smooth Damp #2001

Closed
wants to merge 25 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8b8ad09
smooth damp for f32, f64, vec2, vec3
msklywenn Apr 24, 2021
a79e3cc
format
msklywenn Apr 24, 2021
c387dba
Merge branch 'main' of https://github.com/bevyengine/bevy
msklywenn Apr 24, 2021
3b31005
smooth_time comment
msklywenn Apr 26, 2021
565f556
smooth_time comment
msklywenn Apr 26, 2021
16ba211
smooth damp with max speed
msklywenn Apr 26, 2021
2f3b0cb
format
msklywenn Apr 26, 2021
830fef9
use clamp_length_max
msklywenn Apr 26, 2021
1485281
ensure max speed validity to avoid any divide by zero
msklywenn Apr 26, 2021
b74ae4f
removed needless casts
msklywenn Apr 26, 2021
f685e66
removed unnecessary variable
msklywenn Apr 26, 2021
a060a0d
macros to avoid code duplication
msklywenn Apr 26, 2021
e54efb3
export smooth damp max in prelude
msklywenn Apr 26, 2021
5755ffd
format
msklywenn Apr 26, 2021
ece1667
more macros for even less code duplication
msklywenn Apr 26, 2021
19ed7e4
fixed smooth_damp_max and simplified its macro
msklywenn Apr 27, 2021
2b152b2
Merge branch 'main' of https://github.com/bevyengine/bevy
msklywenn Apr 27, 2021
2a7211f
Merge branch 'main' of https://github.com/msklywenn/bevy
msklywenn Apr 27, 2021
745b368
use faster exponential approximation
msklywenn Apr 27, 2021
687e47a
added doc example
msklywenn Apr 27, 2021
24b0b2f
format...
msklywenn Apr 27, 2021
3397f26
properly hide example boilerplate
msklywenn Apr 27, 2021
4331def
make example parameters public
msklywenn Apr 27, 2021
e4d42ad
replaced maxs with asserts on inputs
msklywenn Apr 27, 2021
71ab208
document panics + SmoothDampMax example
msklywenn Apr 27, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
macros to avoid code duplication
msklywenn committed Apr 26, 2021
commit a060a0df5e08fa27ceb561bd97c862043511a965
303 changes: 104 additions & 199 deletions crates/bevy_math/src/smooth.rs
Original file line number Diff line number Diff line change
@@ -18,89 +18,42 @@ pub trait SmoothDamp {
Self: Sized;
}

impl SmoothDamp for f32 {
fn smooth_damp(
from: f32,
to: f32,
velocity: f32,
smooth_time: f32,
delta_time: f32,
) -> (f32, f32) {
let smooth_time = f32::max(smooth_time, 0.0001); // ensure smooth_time is positive and non-zero

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let change = from - to;
let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
macro_rules! impl_smooth_damp_scalar {
($t:ty, $f:ty) => {
impl SmoothDamp for $t {
fn smooth_damp(
from: $t,
to: $t,
velocity: $t,
smooth_time: f32,
delta_time: f32,
) -> ($t, $t) {
let smooth_time = <$f>::max(smooth_time as $f, 0.0001); // ensure smooth_time is positive and non-zero
let delta_time = delta_time as $f;

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let change = from - to;
let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
}
}
}
}

impl SmoothDamp for f64 {
fn smooth_damp(
from: f64,
to: f64,
velocity: f64,
smooth_time: f32,
delta_time: f32,
) -> (f64, f64) {
let smooth_time = f64::max(smooth_time as f64, 0.0001); // ensure smooth_time is positive and non-zero
let delta_time = delta_time as f64;

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let change = from - to;
let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
}
}

impl SmoothDamp for Vec2 {
fn smooth_damp(
from: Vec2,
to: Vec2,
velocity: Vec2,
smooth_time: f32,
delta_time: f32,
) -> (Vec2, Vec2) {
let (x, vx) = f32::smooth_damp(from.x, to.x, velocity.x, smooth_time, delta_time);
let (y, vy) = f32::smooth_damp(from.y, to.y, velocity.y, smooth_time, delta_time);
(Vec2::new(x, y), Vec2::new(vx, vy))
}
}

impl SmoothDamp for Vec3 {
fn smooth_damp(
from: Vec3,
to: Vec3,
velocity: Vec3,
smooth_time: f32,
delta_time: f32,
) -> (Vec3, Vec3) {
let (x, vx) = f32::smooth_damp(from.x, to.x, velocity.x, smooth_time, delta_time);
let (y, vy) = f32::smooth_damp(from.y, to.y, velocity.y, smooth_time, delta_time);
let (z, vz) = f32::smooth_damp(from.z, to.z, velocity.z, smooth_time, delta_time);
(Vec3::new(x, y, z), Vec3::new(vx, vy, vz))
}
}
impl_smooth_damp_scalar! {f32, f32}
impl_smooth_damp_scalar! {f64, f64}
impl_smooth_damp_scalar! {Vec2, f32}
impl_smooth_damp_scalar! {Vec3, f32}

/// Smooths value to a goal using a damped spring limited by a maximum speed.
pub trait SmoothDampMax {
@@ -121,127 +74,79 @@ pub trait SmoothDampMax {
Self: Sized;
}

impl SmoothDampMax for f32 {
fn smooth_damp_max(
from: f32,
to: f32,
velocity: f32,
max_speed: f32,
smooth_time: f32,
delta_time: f32,
) -> (f32, f32) {
let max_speed = f32::max(max_speed, 0.0001); // ensure max speed is positive and non-zero
let smooth_time = f32::max(smooth_time, 0.0001); // ensure smooth_time is positive and non-zero

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let max = max_speed * delta_time;
let change = f32::clamp(from - to, -max, max);

let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
}
}

impl SmoothDampMax for f64 {
fn smooth_damp_max(
from: f64,
to: f64,
velocity: f64,
max_speed: f32,
smooth_time: f32,
delta_time: f32,
) -> (f64, f64) {
let max_speed = f32::max(max_speed, 0.0001); // ensure max speed is positive and non-zero
let smooth_time = f64::max(smooth_time as f64, 0.0001); // ensure smooth_time is positive and non-zero
let delta_time = delta_time as f64;

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let max = (max_speed as f64) * delta_time;
let change = f64::clamp(from - to, -max, max);

let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
macro_rules! impl_smooth_damp_max_scalar {
($t:ty) => {
impl SmoothDampMax for $t {
fn smooth_damp_max(
from: $t,
to: $t,
velocity: $t,
max_speed: f32,
smooth_time: f32,
delta_time: f32,
) -> ($t, $t) {
let max_speed = <$t>::max(max_speed as $t, 0.0001); // ensure max speed is positive and non-zero
let smooth_time = <$t>::max(smooth_time as $t, 0.0001); // ensure smooth_time is positive and non-zero
let delta_time = delta_time as $t;

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let max = max_speed * delta_time;
let change = <$t>::clamp(from - to, -max, max);

let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
}
}
}
}

impl SmoothDampMax for Vec2 {
fn smooth_damp_max(
from: Vec2,
to: Vec2,
velocity: Vec2,
max_speed: f32,
smooth_time: f32,
delta_time: f32,
) -> (Vec2, Vec2) {
let max_speed = f32::max(max_speed, 0.0001); // ensure max speed is positive and non-zero
let smooth_time = f32::max(smooth_time, 0.0001); // ensure smooth_time is positive and non-zero

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let max = max_speed * delta_time;
let change = (from - to).clamp_length_max(max);

let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
}
impl_smooth_damp_max_scalar!{f32}
impl_smooth_damp_max_scalar!{f64}

macro_rules! impl_smooth_damp_max_vec {
($t:ty) => {
impl SmoothDampMax for $t {
fn smooth_damp_max(
from: $t,
to: $t,
velocity: $t,
max_speed: f32,
smooth_time: f32,
delta_time: f32,
) -> ($t, $t) {
let max_speed = f32::max(max_speed, 0.0001); // ensure max speed is positive and non-zero
let smooth_time = f32::max(smooth_time, 0.0001); // ensure smooth_time is positive and non-zero

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let max = max_speed * delta_time;
let change = (from - to).clamp_length_max(max);

let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
}
}
};
}

impl SmoothDampMax for Vec3 {
fn smooth_damp_max(
from: Vec3,
to: Vec3,
velocity: Vec3,
max_speed: f32,
smooth_time: f32,
delta_time: f32,
) -> (Vec3, Vec3) {
let max_speed = f32::max(max_speed, 0.0001); // ensure max speed is positive and non-zero
let smooth_time = f32::max(smooth_time, 0.0001); // ensure smooth_time is positive and non-zero

// from game programming gems 4, chapter 1.10
let omega = 2.0 / smooth_time;
let x = omega * delta_time;

let exp = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
// let exp = 1.0 / (1.0 + x * (1.0 + x * (0.48 + 0.235 * x))); // TODO: profile me, both in debug & release

let max = max_speed * delta_time;
let change = (from - to).clamp_length_max(max);

let temp = (velocity + omega * change) * delta_time;

(
to + (change + temp) * exp, // position
(velocity - omega * temp) * exp, // velocity
)
}
}
impl_smooth_damp_max_vec! {Vec2}
impl_smooth_damp_max_vec! {Vec3}