diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs index 00e775e6adc..124410a1c2d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs @@ -175,7 +175,8 @@ namespace Godot } /// - /// Cubic interpolates between two values by a normalized value with pre and post values. + /// Cubic interpolates between two values by the factor defined in + /// with pre and post values. /// /// The start value for interpolation. /// The destination value for interpolation. @@ -192,6 +193,33 @@ namespace Godot (-pre + 3.0f * from - 3.0f * to + post) * (weight * weight * weight)); } + /// + /// Cubic interpolates between two values by the factor defined in + /// with pre and post values. + /// It can perform smoother interpolation than + /// by the time values. + /// + /// The start value for interpolation. + /// The destination value for interpolation. + /// The value which before "from" value for interpolation. + /// The value which after "to" value for interpolation. + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// + /// + /// + /// The resulting value of the interpolation. + public static real_t CubicInterpolateInTime(real_t from, real_t to, real_t pre, real_t post, real_t weight, real_t toT, real_t preT, real_t postT) + { + /* Barry-Goldman method */ + real_t t = Lerp(0.0f, toT, weight); + real_t a1 = Lerp(pre, from, preT == 0 ? 0.0f : (t - preT) / -preT); + real_t a2 = Lerp(from, to, toT == 0 ? 0.5f : t / toT); + real_t a3 = Lerp(to, post, postT - toT == 0 ? 1.0f : (t - toT) / (postT - toT)); + real_t b1 = Lerp(a1, a2, toT - preT == 0 ? 0.0f : (t - preT) / (toT - preT)); + real_t b2 = Lerp(a2, a3, postT == 0 ? 1.0f : t / postT); + return Lerp(b1, b2, toT == 0 ? 0.5f : t / toT); + } + /// /// Returns the point at the given on a one-dimensional Bezier curve defined by /// the given , and points. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index 8568ecf2998..5cc478ca710 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -195,6 +195,75 @@ namespace Godot return q1.Slerp(q2, weight); } + /// + /// Performs a spherical cubic interpolation between quaternions , this quaternion, + /// , and , by the given amount . + /// It can perform smoother interpolation than + /// by the time values. + /// + /// The destination quaternion. + /// A quaternion before this quaternion. + /// A quaternion after . + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// + /// + /// + /// The interpolated quaternion. + public Quaternion SphericalCubicInterpolateInTime(Quaternion b, Quaternion preA, Quaternion postB, real_t weight, real_t bT, real_t preAT, real_t postBT) + { +#if DEBUG + if (!IsNormalized()) + { + throw new InvalidOperationException("Quaternion is not normalized"); + } + if (!b.IsNormalized()) + { + throw new ArgumentException("Argument is not normalized", nameof(b)); + } +#endif + + // Align flip phases. + Quaternion fromQ = new Basis(this).GetRotationQuaternion(); + Quaternion preQ = new Basis(preA).GetRotationQuaternion(); + Quaternion toQ = new Basis(b).GetRotationQuaternion(); + Quaternion postQ = new Basis(postB).GetRotationQuaternion(); + + // Flip quaternions to shortest path if necessary. + bool flip1 = Math.Sign(fromQ.Dot(preQ)) < 0; + preQ = flip1 ? -preQ : preQ; + bool flip2 = Math.Sign(fromQ.Dot(toQ)) < 0; + toQ = flip2 ? -toQ : toQ; + bool flip3 = flip2 ? toQ.Dot(postQ) <= 0 : Math.Sign(toQ.Dot(postQ)) < 0; + postQ = flip3 ? -postQ : postQ; + + // Calc by Expmap in fromQ space. + Quaternion lnFrom = new Quaternion(0, 0, 0, 0); + Quaternion lnTo = (fromQ.Inverse() * toQ).Log(); + Quaternion lnPre = (fromQ.Inverse() * preQ).Log(); + Quaternion lnPost = (fromQ.Inverse() * postQ).Log(); + Quaternion ln = new Quaternion( + Mathf.CubicInterpolateInTime(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight, bT, preAT, postBT), + Mathf.CubicInterpolateInTime(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight, bT, preAT, postBT), + Mathf.CubicInterpolateInTime(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight, bT, preAT, postBT), + 0); + Quaternion q1 = fromQ * ln.Exp(); + + // Calc by Expmap in toQ space. + lnFrom = (toQ.Inverse() * fromQ).Log(); + lnTo = new Quaternion(0, 0, 0, 0); + lnPre = (toQ.Inverse() * preQ).Log(); + lnPost = (toQ.Inverse() * postQ).Log(); + ln = new Quaternion( + Mathf.CubicInterpolateInTime(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight, bT, preAT, postBT), + Mathf.CubicInterpolateInTime(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight, bT, preAT, postBT), + Mathf.CubicInterpolateInTime(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight, bT, preAT, postBT), + 0); + Quaternion q2 = toQ * ln.Exp(); + + // To cancel error made by Expmap ambiguity, do blends. + return q1.Slerp(q2, weight); + } + /// /// Returns the dot product of two quaternions. /// diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 03ee12884b3..b2964db8cd6 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -215,6 +215,29 @@ namespace Godot ); } + /// + /// Performs a cubic interpolation between vectors , this vector, + /// , and , by the given amount . + /// It can perform smoother interpolation than + /// by the time values. + /// + /// The destination vector. + /// A vector before this vector. + /// A vector after . + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// + /// + /// + /// The interpolated vector. + public Vector2 CubicInterpolateInTime(Vector2 b, Vector2 preA, Vector2 postB, real_t weight, real_t t, real_t preAT, real_t postBT) + { + return new Vector2 + ( + Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT), + Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT) + ); + } + /// /// Returns the point at the given on a one-dimensional Bezier curve defined by this vector /// and the given , and points. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index cdba06c0892..b53ca5e45a2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -208,6 +208,30 @@ namespace Godot ); } + /// + /// Performs a cubic interpolation between vectors , this vector, + /// , and , by the given amount . + /// It can perform smoother interpolation than + /// by the time values. + /// + /// The destination vector. + /// A vector before this vector. + /// A vector after . + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// + /// + /// + /// The interpolated vector. + public Vector3 CubicInterpolateInTime(Vector3 b, Vector3 preA, Vector3 postB, real_t weight, real_t t, real_t preAT, real_t postBT) + { + return new Vector3 + ( + Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT), + Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT), + Mathf.CubicInterpolateInTime(z, b.z, preA.z, postB.z, weight, t, preAT, postBT) + ); + } + /// /// Returns the point at the given on a one-dimensional Bezier curve defined by this vector /// and the given , and points. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs index 705da046929..b6f243dfb40 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs @@ -192,6 +192,31 @@ namespace Godot ); } + /// + /// Performs a cubic interpolation between vectors , this vector, + /// , and , by the given amount . + /// It can perform smoother interpolation than + /// by the time values. + /// + /// The destination vector. + /// A vector before this vector. + /// A vector after . + /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. + /// + /// + /// + /// The interpolated vector. + public Vector4 CubicInterpolateInTime(Vector4 b, Vector4 preA, Vector4 postB, real_t weight, real_t t, real_t preAT, real_t postBT) + { + return new Vector4 + ( + Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT), + Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT), + Mathf.CubicInterpolateInTime(y, b.z, preA.z, postB.z, weight, t, preAT, postBT), + Mathf.CubicInterpolateInTime(w, b.w, preA.w, postB.w, weight, t, preAT, postBT) + ); + } + /// /// Returns the normalized vector pointing from this vector to . ///