From 23fc704cbc79c77fb3e8bda8c58a8bbb4815951e Mon Sep 17 00:00:00 2001 From: Malcolm Nixon Date: Fri, 14 Jun 2024 03:08:16 -0400 Subject: [PATCH] This PR handles the smoothstep degenerate case where the range is empty. It also updates the documentation to describe positive and negative ranges. Co-Authored-By: Hugo Locurcio Co-Authored-By: kleonc <9283098+kleonc@users.noreply.github.com> --- core/math/math_funcs.h | 12 ++++++++++-- doc/classes/@GlobalScope.xml | 6 ++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 3060f31970c..fd53ed28fd3 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -447,14 +447,22 @@ public: static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) { if (is_equal_approx(p_from, p_to)) { - return p_from; + if (likely(p_from <= p_to)) { + return p_s <= p_from ? 0.0 : 1.0; + } else { + return p_s <= p_to ? 1.0 : 0.0; + } } double s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0, 1.0); return s * s * (3.0 - 2.0 * s); } static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) { if (is_equal_approx(p_from, p_to)) { - return p_from; + if (likely(p_from <= p_to)) { + return p_s <= p_from ? 0.0f : 1.0f; + } else { + return p_s <= p_to ? 1.0f : 0.0f; + } } float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); return s * s * (3.0f - 2.0f * s); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 2cd3a517224..339bbb71dd7 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1248,8 +1248,9 @@ - Returns the result of smoothly interpolating the value of [param x] between [code]0[/code] and [code]1[/code], based on the where [param x] lies with respect to the edges [param from] and [param to]. - The return value is [code]0[/code] if [code]x <= from[/code], and [code]1[/code] if [code]x >= to[/code]. If [param x] lies between [param from] and [param to], the returned value follows an S-shaped curve that maps [param x] between [code]0[/code] and [code]1[/code]. + Returns a smooth cubic Hermite interpolation between [code]0[/code] and [code]1[/code]. + For positive ranges (when [code]from <= to[/code]) the return value is [code]0[/code] when [code]x <= from[/code], and [code]1[/code] when [code]x >= to[/code]. If [param x] lies between [param from] and [param to], the return value follows an S-shaped curve that smoothly transitions from [code]0[/code] to [code]1[/code]. + For negative ranges (when [code]from > to[/code]) the function is mirrored and returns [code]1[/code] when [code]x <= to[/code] and [code]0[/code] when [code]x >= from[/code]. This S-shaped curve is the cubic Hermite interpolator, given by [code]f(y) = 3*y^2 - 2*y^3[/code] where [code]y = (x-from) / (to-from)[/code]. [codeblock] smoothstep(0, 2, -5.0) # Returns 0.0 @@ -1259,6 +1260,7 @@ [/codeblock] Compared to [method ease] with a curve value of [code]-1.6521[/code], [method smoothstep] returns the smoothest possible curve with no sudden changes in the derivative. If you need to perform more advanced transitions, use [Tween] or [AnimationPlayer]. [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/smoothstep_ease_comparison.png]Comparison between smoothstep() and ease(x, -1.6521) return values[/url] + [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/smoothstep_range.webp]Smoothstep() return values with positive, zero, and negative ranges[/url]