diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 84c4bbcd73..76c25d4cd0 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -759,6 +759,20 @@ class Math {
}
return p_target;
}
+
+ static _ALWAYS_INLINE_ double sigmoid_affine(double p_x, double p_amplitude, double p_y_translation) {
+ return p_amplitude / (1.0 + ::exp(-p_x)) + p_y_translation;
+ }
+ static _ALWAYS_INLINE_ float sigmoid_affine(float p_x, float p_amplitude, float p_y_translation) {
+ return p_amplitude / (1.0f + expf(-p_x)) + p_y_translation;
+ }
+
+ static _ALWAYS_INLINE_ double sigmoid_affine_approx(double p_x, double p_amplitude, double p_y_translation) {
+ return p_amplitude * (0.5 + p_x / (4.0 + fabs(p_x))) + p_y_translation;
+ }
+ static _ALWAYS_INLINE_ float sigmoid_affine_approx(float p_x, float p_amplitude, float p_y_translation) {
+ return p_amplitude * (0.5f + p_x / (4.0f + fabsf(p_x))) + p_y_translation;
+ }
};
#endif // MATH_FUNCS_H
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 8e4231c90e..03edd6cc52 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -641,6 +641,22 @@ double VariantUtilityFunctions::pingpong(double value, double length) {
return Math::pingpong(value, length);
}
+double VariantUtilityFunctions::sigmoid(double x) {
+ return Math::sigmoid_affine(x, 1.0, 0.0);
+}
+
+double VariantUtilityFunctions::sigmoid_approx(double x) {
+ return Math::sigmoid_affine_approx(x, 1.0, 0.0);
+}
+
+double VariantUtilityFunctions::sigmoid_affine(double x, double amplitude, double y_translation) {
+ return Math::sigmoid_affine(x, amplitude, y_translation);
+}
+
+double VariantUtilityFunctions::sigmoid_affine_approx(double x, double amplitude, double y_translation) {
+ return Math::sigmoid_affine_approx(x, amplitude, y_translation);
+}
+
Variant VariantUtilityFunctions::max(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
if (p_argcount < 2) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -1789,6 +1805,11 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(nearest_po2, sarray("value"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(pingpong, sarray("value", "length"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(sigmoid, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(sigmoid_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(sigmoid_affine, sarray("x", "amplitude", "y_translation"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(sigmoid_affine_approx, sarray("x", "amplitude", "y_translation"), Variant::UTILITY_FUNC_TYPE_MATH);
+
// Random
FUNCBIND(randomize, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM);
diff --git a/core/variant/variant_utility.h b/core/variant/variant_utility.h
index 067988e246..a3eb386263 100644
--- a/core/variant/variant_utility.h
+++ b/core/variant/variant_utility.h
@@ -117,6 +117,10 @@ struct VariantUtilityFunctions {
static double clampf(double x, double min, double max);
static int64_t clampi(int64_t x, int64_t min, int64_t max);
static int64_t nearest_po2(int64_t x);
+ static double sigmoid(double x);
+ static double sigmoid_approx(double x);
+ static double sigmoid_affine(double x, double amplitude, double y_translation);
+ static double sigmoid_affine_approx(double x, double amplitude, double y_translation);
// Random
static void randomize();
static int64_t randi();
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 660783a84a..25316bb7bd 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1175,6 +1175,84 @@
[/codeblocks]
+
+
+
+
+ Computes the sigmoid for [param x], which maps the input value into the range (0, 1).
+ The sigmoid function is defined as:
+ [codeblock]
+ sigmoid(x) = 1 / (1 + exp(-x))
+ [/codeblock]
+ This is the most accurate implementation of the sigmoid.
+ [codeblock]
+ var result = sigmoid(0.0) # result is 0.5
+ var result = sigmoid(1.0) # result is approximately 0.7310
+ var result = sigmoid(-1.0) # result is approximately 0.2689
+ var result = sigmoid(5.0) # result is approximately 0.9933
+ [/codeblock]
+ [b]Note:[/b] For faster but less accurate approximation, see [method sigmoid_approx].
+
+
+
+
+
+
+
+
+ Computes an affine-transformed sigmoid for [param x], which allows scaling by [param amplitude] and translation by [param y_translation].
+ The affine sigmoid function is defined as:
+ [codeblock]
+ sigmoid_affine(x, amplitude, y_translation) = (amplitude / (1 + exp(-x))) + y_translation
+ [/codeblock]
+ This function modifies the standard sigmoid by introducing scaling and vertical translation.
+ [codeblock]
+ var result = sigmoid_affine(0.0, 1.0, 0.0) # result is 0.5
+ var result = sigmoid_affine(1.0, 2.0, -1.0) # result is approximately 0.4621
+ var result = sigmoid_affine(-1.0, 3.0, 2.0) # result is approximately 2.8068
+ var result = sigmoid_affine(1.0, 2.0, 2.5) # result is approximately 3.9621
+ [/codeblock]
+ [b]Note:[/b] This is a more accurate but computationally heavier version of the affine sigmoid. For faster approximations, see [method sigmoid_affine_approx].
+
+
+
+
+
+
+
+
+ Computes an approximation of the affine-transformed sigmoid function for [param x], allowing scaling by [param amplitude] and translation by [param y_translation].
+ The approximation function is defined as:
+ [codeblock]
+ affine_sigmoid_approx(x, amplitude, y_translation) = amplitude * (0.5 + (x / (4 + abs(x)))) + y_translation
+ [/codeblock]
+ This function approximates the affine sigmoid, offering faster computation at the cost of some precision. It is useful in performance-sensitive environments where both transformation and speed are needed.
+ [codeblock]
+ var result = sigmoid_affine_approx(0.0, 1.0, 0.0) # result is 0.5
+ var result = sigmoid_affine_approx(2.0, 2.0, 1.0) # result is approximately 2.6667
+ var result = sigmoid_affine_approx(-1.0, 3.0, 0.5) # result is 1.4
+ var result = sigmoid_affine_approx(1.0, 2.0, 2.5) # result is 3.9
+ [/codeblock]
+
+
+
+
+
+
+ Computes an approximation of the sigmoid function for [param x], which maps the input value into the range (0, 1).
+ The approximation function is defined as:
+ [codeblock]
+ sigmoid_approx(x) = 0.5 + (x / (4 + abs(x)))
+ [/codeblock]
+ This function is faster than the standard [method sigmoid], especially useful in performance-sensitive environments where a balance between accuracy and speed is desired.
+ [codeblock]
+ var result = sigmoid_approx(0.0) # result is 0.5
+ var result = sigmoid_approx(2.0) # result is approximately 0.8333
+ var result = sigmoid_approx(-1.0) # result is 0.3
+ var result = sigmoid_approx(5.0) # result is approximately 1.0555
+ [/codeblock]
+
+
diff --git a/tests/core/math/test_math_funcs.h b/tests/core/math/test_math_funcs.h
index 1a692e7eff..ef437b9c5c 100644
--- a/tests/core/math/test_math_funcs.h
+++ b/tests/core/math/test_math_funcs.h
@@ -641,6 +641,20 @@ TEST_CASE_TEMPLATE("[Math] bezier_interpolate", T, float, double) {
CHECK(Math::bezier_interpolate((T)0.0, (T)0.2, (T)0.8, (T)1.0, (T)1.0) == doctest::Approx((T)1.0));
}
+TEST_CASE_TEMPLATE("[Math] sigmoid_affine", T, float, double) {
+ CHECK(Math::sigmoid_affine((T)0.0, (T)1.0, (T)0.0) == doctest::Approx((T)0.5));
+ CHECK(Math::sigmoid_affine((T)1.0, (T)2.0, (T)-1.0) == doctest::Approx((T)0.4621));
+ CHECK(Math::sigmoid_affine((T)-1.0, (T)3.0, (T)2.0) == doctest::Approx((T)2.8068));
+ CHECK(Math::sigmoid_affine((T)1.0, (T)2.0, (T)2.5) == doctest::Approx((T)3.9621));
+}
+
+TEST_CASE_TEMPLATE("[Math] sigmoid_affine_approx", T, float, double) {
+ CHECK(Math::sigmoid_affine_approx((T)0.0, (T)1.0, (T)0.0) == doctest::Approx((T)0.5));
+ CHECK(Math::sigmoid_affine_approx((T)2.0, (T)2.0, (T)1.0) == doctest::Approx((T)2.6667));
+ CHECK(Math::sigmoid_affine_approx((T)-1.0, (T)3.0, (T)0.5) == doctest::Approx((T)1.4));
+ CHECK(Math::sigmoid_affine_approx((T)1.0, (T)2.0, (T)2.5) == doctest::Approx((T)3.9));
+}
+
} // namespace TestMath
#endif // TEST_MATH_FUNCS_H