ソースを参照

Merge pull request #62458 from Geometror/interpolation-function-cleanup

Refactor Bezier interpolation functions
Rémi Verschelde 3 年 前
コミット
25baa32db0

+ 21 - 0
core/math/math_funcs.h

@@ -253,6 +253,27 @@ public:
 						(-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight));
 	}
 
+	static _ALWAYS_INLINE_ double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
+		/* Formula from Wikipedia article on Bezier curves. */
+		double omt = (1.0 - p_t);
+		double omt2 = omt * omt;
+		double omt3 = omt2 * omt;
+		double t2 = p_t * p_t;
+		double t3 = t2 * p_t;
+
+		return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
+	}
+	static _ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
+		/* Formula from Wikipedia article on Bezier curves. */
+		float omt = (1.0f - p_t);
+		float omt2 = omt * omt;
+		float omt3 = omt2 * omt;
+		float t2 = p_t * p_t;
+		float t3 = t2 * p_t;
+
+		return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0f + p_control_2 * omt * t2 * 3.0f + p_end * t3;
+	}
+
 	static _ALWAYS_INLINE_ double lerp_angle(double p_from, double p_to, double p_weight) {
 		double difference = fmod(p_to - p_from, Math_TAU);
 		double distance = fmod(2.0 * difference, Math_TAU) - difference;

+ 0 - 7
core/math/vector2.cpp

@@ -152,13 +152,6 @@ Vector2 Vector2::limit_length(const real_t p_len) const {
 	return v;
 }
 
-Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const {
-	Vector2 res = *this;
-	res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
-	res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
-	return res;
-}
-
 Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const {
 	Vector2 v = *this;
 	Vector2 vd = p_to - v;

+ 23 - 1
core/math/vector2.h

@@ -113,7 +113,9 @@ struct _NO_DISCARD_ Vector2 {
 
 	_FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const;
 	_FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const;
-	Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
+
 	Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const;
 
 	Vector2 slide(const Vector2 &p_normal) const;
@@ -261,6 +263,26 @@ Vector2 Vector2::slerp(const Vector2 &p_to, const real_t p_weight) const {
 	return rotated(angle * p_weight) * (result_length / start_length);
 }
 
+Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const {
+	Vector2 res = *this;
+	res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
+	res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
+	return res;
+}
+
+Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const {
+	Vector2 res = *this;
+
+	/* Formula from Wikipedia article on Bezier curves. */
+	real_t omt = (1.0 - p_t);
+	real_t omt2 = omt * omt;
+	real_t omt3 = omt2 * omt;
+	real_t t2 = p_t * p_t;
+	real_t t3 = t2 * p_t;
+
+	return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
+}
+
 Vector2 Vector2::direction_to(const Vector2 &p_to) const {
 	Vector2 ret(p_to.x - x, p_to.y - y);
 	ret.normalize();

+ 0 - 8
core/math/vector3.cpp

@@ -85,14 +85,6 @@ Vector3 Vector3::limit_length(const real_t p_len) const {
 	return v;
 }
 
-Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const {
-	Vector3 res = *this;
-	res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
-	res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
-	res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight);
-	return res;
-}
-
 Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const {
 	Vector3 v = *this;
 	Vector3 vd = p_to - v;

+ 24 - 1
core/math/vector3.h

@@ -104,7 +104,9 @@ struct _NO_DISCARD_ Vector3 {
 
 	_FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, const real_t p_weight) const;
 	_FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, const real_t p_weight) const;
-	Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const;
+	_FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;
+
 	Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const;
 
 	Vector2 octahedron_encode() const;
@@ -227,6 +229,27 @@ Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const {
 	return rotated(cross(p_to).normalized(), angle * p_weight) * (result_length / start_length);
 }
 
+Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const {
+	Vector3 res = *this;
+	res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
+	res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
+	res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight);
+	return res;
+}
+
+Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const {
+	Vector3 res = *this;
+
+	/* Formula from Wikipedia article on Bezier curves. */
+	real_t omt = (1.0 - p_t);
+	real_t omt2 = omt * omt;
+	real_t omt3 = omt2 * omt;
+	real_t t2 = p_t * p_t;
+	real_t t3 = t2 * p_t;
+
+	return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
+}
+
 real_t Vector3::distance_to(const Vector3 &p_to) const {
 	return (p_to - *this).length();
 }

+ 2 - 0
core/variant/variant_call.cpp

@@ -1556,6 +1556,7 @@ static void _register_variant_builtin_methods() {
 	bind_method(Vector2, lerp, sarray("to", "weight"), varray());
 	bind_method(Vector2, slerp, sarray("to", "weight"), varray());
 	bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+	bind_method(Vector2, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
 	bind_method(Vector2, max_axis_index, sarray(), varray());
 	bind_method(Vector2, min_axis_index, sarray(), varray());
 	bind_method(Vector2, move_toward, sarray("to", "delta"), varray());
@@ -1643,6 +1644,7 @@ static void _register_variant_builtin_methods() {
 	bind_method(Vector3, lerp, sarray("to", "weight"), varray());
 	bind_method(Vector3, slerp, sarray("to", "weight"), varray());
 	bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+	bind_method(Vector3, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
 	bind_method(Vector3, move_toward, sarray("to", "delta"), varray());
 	bind_method(Vector3, dot, sarray("with"), varray());
 	bind_method(Vector3, cross, sarray("with"), varray());

+ 5 - 0
core/variant/variant_utility.cpp

@@ -231,6 +231,10 @@ struct VariantUtilityFunctions {
 		return Math::cubic_interpolate(from, to, pre, post, weight);
 	}
 
+	static inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
+		return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t);
+	}
+
 	static inline double lerp_angle(double from, double to, double weight) {
 		return Math::lerp_angle(from, to, weight);
 	}
@@ -1204,6 +1208,7 @@ void Variant::_register_variant_utility_functions() {
 
 	FUNCBINDR(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
 	FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+	FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH);
 	FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
 	FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
 	FUNCBINDR(range_lerp, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);

+ 11 - 0
doc/classes/@GlobalScope.xml

@@ -106,6 +106,17 @@
 				[/codeblock]
 			</description>
 		</method>
+		<method name="bezier_interpolate">
+			<return type="float" />
+			<argument index="0" name="start" type="float" />
+			<argument index="1" name="control_1" type="float" />
+			<argument index="2" name="control_2" type="float" />
+			<argument index="3" name="end" type="float" />
+			<argument index="4" name="t" type="float" />
+			<description>
+				Returns the point at the given [code]t[/code] on a one-dimnesional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [code]control_1[/code], [code]control_2[/code], and [code]end[/code] points.
+			</description>
+		</method>
 		<method name="bytes2var">
 			<return type="Variant" />
 			<argument index="0" name="bytes" type="PackedByteArray" />

+ 10 - 0
doc/classes/Vector2.xml

@@ -85,6 +85,16 @@
 				Returns the aspect ratio of this vector, the ratio of [member x] to [member y].
 			</description>
 		</method>
+		<method name="bezier_interpolate" qualifiers="const">
+			<return type="Vector2" />
+			<argument index="0" name="control_1" type="Vector2" />
+			<argument index="1" name="control_2" type="Vector2" />
+			<argument index="2" name="end" type="Vector2" />
+			<argument index="3" name="t" type="float" />
+			<description>
+				Returns the point at the given [code]t[/code] on the [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by this vector and the given [code]control_1[/code], [code]control_2[/code], and [code]end[/code] points.
+			</description>
+		</method>
 		<method name="bounce" qualifiers="const">
 			<return type="Vector2" />
 			<argument index="0" name="n" type="Vector2" />

+ 10 - 0
doc/classes/Vector3.xml

@@ -61,6 +61,16 @@
 				Returns the unsigned minimum angle to the given vector, in radians.
 			</description>
 		</method>
+		<method name="bezier_interpolate" qualifiers="const">
+			<return type="Vector3" />
+			<argument index="0" name="control_1" type="Vector3" />
+			<argument index="1" name="control_2" type="Vector3" />
+			<argument index="2" name="end" type="Vector3" />
+			<argument index="3" name="t" type="float" />
+			<description>
+				Returns the point at the given [code]t[/code] on the [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by this vector and the given [code]control_1[/code], [code]control_2[/code], and [code]end[/code] points.
+			</description>
+		</method>
 		<method name="bounce" qualifiers="const">
 			<return type="Vector3" />
 			<argument index="0" name="n" type="Vector3" />

+ 3 - 14
editor/animation_bezier_editor.cpp

@@ -44,17 +44,6 @@ float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) {
 	return h;
 }
 
-static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, const Vector2 &start, const Vector2 &control_1, const Vector2 &control_2, const Vector2 &end) {
-	/* Formula from Wikipedia article on Bezier curves. */
-	real_t omt = (1.0 - t);
-	real_t omt2 = omt * omt;
-	real_t omt3 = omt2 * omt;
-	real_t t2 = t * t;
-	real_t t3 = t2 * t;
-
-	return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3;
-}
-
 void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
 	float scale = timeline->get_zoom_scale();
 
@@ -151,7 +140,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
 				for (int k = 0; k < iterations; k++) {
 					float middle = (low + high) / 2;
 
-					Vector2 interp = _bezier_interp(middle, start, out_handle, in_handle, end);
+					Vector2 interp = start.bezier_interpolate(out_handle, in_handle, end, middle);
 
 					if (interp.x < t) {
 						low = middle;
@@ -161,8 +150,8 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
 				}
 
 				//interpolate the result:
-				Vector2 low_pos = _bezier_interp(low, start, out_handle, in_handle, end);
-				Vector2 high_pos = _bezier_interp(high, start, out_handle, in_handle, end);
+				Vector2 low_pos = start.bezier_interpolate(out_handle, in_handle, end, low);
+				Vector2 high_pos = start.bezier_interpolate(out_handle, in_handle, end, high);
 
 				float c = (t - low_pos.x) / (high_pos.x - low_pos.x);
 

+ 3 - 14
scene/resources/animation.cpp

@@ -3379,17 +3379,6 @@ Vector2 Animation::bezier_track_get_key_out_handle(int p_track, int p_index) con
 	return bt->values[p_index].value.out_handle;
 }
 
-static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, const Vector2 &start, const Vector2 &control_1, const Vector2 &control_2, const Vector2 &end) {
-	/* Formula from Wikipedia article on Bezier curves. */
-	real_t omt = (1.0 - t);
-	real_t omt2 = omt * omt;
-	real_t omt3 = omt2 * omt;
-	real_t t2 = t * t;
-	real_t t3 = t2 * t;
-
-	return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3;
-}
-
 real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
 	//this uses a different interpolation scheme
 	ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
@@ -3438,7 +3427,7 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
 	for (int i = 0; i < iterations; i++) {
 		real_t middle = (low + high) / 2;
 
-		Vector2 interp = _bezier_interp(middle, start, start_out, end_in, end);
+		Vector2 interp = start.bezier_interpolate(start_out, end_in, end, middle);
 
 		if (interp.x < t) {
 			low = middle;
@@ -3448,8 +3437,8 @@ real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
 	}
 
 	//interpolate the result:
-	Vector2 low_pos = _bezier_interp(low, start, start_out, end_in, end);
-	Vector2 high_pos = _bezier_interp(high, start, start_out, end_in, end);
+	Vector2 low_pos = start.bezier_interpolate(start_out, end_in, end, low);
+	Vector2 high_pos = start.bezier_interpolate(start_out, end_in, end, high);
 	real_t c = (t - low_pos.x) / (high_pos.x - low_pos.x);
 
 	return low_pos.lerp(high_pos, c).y;

+ 13 - 25
scene/resources/curve.cpp

@@ -32,18 +32,6 @@
 
 #include "core/core_string_names.h"
 
-template <class T>
-static _FORCE_INLINE_ T _bezier_interp(real_t p_t, T p_start, T p_control_1, T p_control_2, T p_end) {
-	/* Formula from Wikipedia article on Bezier curves. */
-	real_t omt = (1.0 - p_t);
-	real_t omt2 = omt * omt;
-	real_t omt3 = omt2 * omt;
-	real_t t2 = p_t * p_t;
-	real_t t3 = t2 * p_t;
-
-	return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
-}
-
 const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
 
 Curve::Curve() {
@@ -376,7 +364,7 @@ real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) cons
 	real_t yac = a.position.y + d * a.right_tangent;
 	real_t ybc = b.position.y - d * b.left_tangent;
 
-	real_t y = _bezier_interp(p_local_offset, a.position.y, yac, ybc, b.position.y);
+	real_t y = Math::bezier_interpolate(a.position.y, yac, ybc, b.position.y, p_local_offset);
 
 	return y;
 }
@@ -747,7 +735,7 @@ Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const {
 	Vector2 p3 = points[p_index + 1].position;
 	Vector2 p2 = p3 + points[p_index + 1].in;
 
-	return _bezier_interp(p_offset, p0, p1, p2, p3);
+	return p0.bezier_interpolate(p1, p2, p3, p_offset);
 }
 
 Vector2 Curve2D::interpolatef(real_t p_findex) const {
@@ -767,9 +755,9 @@ void Curve2D::mark_dirty() {
 
 void Curve2D::_bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
 	real_t mp = p_begin + (p_end - p_begin) * 0.5;
-	Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
-	Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
-	Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
+	Vector2 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+	Vector2 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+	Vector2 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
 
 	Vector2 na = (mid - beg).normalized();
 	Vector2 nb = (end - mid).normalized();
@@ -828,7 +816,7 @@ void Curve2D::_bake() const {
 				np = 1.0;
 			}
 
-			Vector2 npp = _bezier_interp(np, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+			Vector2 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
 			real_t d = position.distance_to(npp);
 
 			if (d > bake_interval) {
@@ -841,7 +829,7 @@ void Curve2D::_bake() const {
 				real_t mid = low + (hi - low) * 0.5;
 
 				for (int j = 0; j < iterations; j++) {
-					npp = _bezier_interp(mid, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+					npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
 					d = position.distance_to(npp);
 
 					if (bake_interval < d) {
@@ -1336,7 +1324,7 @@ Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const {
 	Vector3 p3 = points[p_index + 1].position;
 	Vector3 p2 = p3 + points[p_index + 1].in;
 
-	return _bezier_interp(p_offset, p0, p1, p2, p3);
+	return p0.bezier_interpolate(p1, p2, p3, p_offset);
 }
 
 Vector3 Curve3D::interpolatef(real_t p_findex) const {
@@ -1356,9 +1344,9 @@ void Curve3D::mark_dirty() {
 
 void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const {
 	real_t mp = p_begin + (p_end - p_begin) * 0.5;
-	Vector3 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
-	Vector3 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
-	Vector3 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
+	Vector3 beg = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_begin);
+	Vector3 mid = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, mp);
+	Vector3 end = p_a.bezier_interpolate(p_a + p_out, p_b + p_in, p_b, p_end);
 
 	Vector3 na = (mid - beg).normalized();
 	Vector3 nb = (end - mid).normalized();
@@ -1426,7 +1414,7 @@ void Curve3D::_bake() const {
 				np = 1.0;
 			}
 
-			Vector3 npp = _bezier_interp(np, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+			Vector3 npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, np);
 			real_t d = position.distance_to(npp);
 
 			if (d > bake_interval) {
@@ -1439,7 +1427,7 @@ void Curve3D::_bake() const {
 				real_t mid = low + (hi - low) * 0.5;
 
 				for (int j = 0; j < iterations; j++) {
-					npp = _bezier_interp(mid, points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position);
+					npp = points[i].position.bezier_interpolate(points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, mid);
 					d = position.distance_to(npp);
 
 					if (bake_interval < d) {

+ 4 - 8
scene/resources/gradient.h

@@ -92,10 +92,6 @@ public:
 	void set_interpolation_mode(InterpolationMode p_interp_mode);
 	InterpolationMode get_interpolation_mode();
 
-	_FORCE_INLINE_ float cubic_interpolate(float p0, float p1, float p2, float p3, float x) {
-		return p1 + 0.5 * x * (p2 - p0 + x * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3 + x * (3.0 * (p1 - p2) + p3 - p0)));
-	}
-
 	_FORCE_INLINE_ Color get_color_at_offset(float p_offset) {
 		if (points.is_empty()) {
 			return Color(0, 0, 0, 1);
@@ -161,10 +157,10 @@ public:
 				const Point &pointP3 = points[p3];
 
 				float x = (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset);
-				float r = cubic_interpolate(pointP0.color.r, pointFirst.color.r, pointSecond.color.r, pointP3.color.r, x);
-				float g = cubic_interpolate(pointP0.color.g, pointFirst.color.g, pointSecond.color.g, pointP3.color.g, x);
-				float b = cubic_interpolate(pointP0.color.b, pointFirst.color.b, pointSecond.color.b, pointP3.color.b, x);
-				float a = cubic_interpolate(pointP0.color.a, pointFirst.color.a, pointSecond.color.a, pointP3.color.a, x);
+				float r = Math::cubic_interpolate(pointP0.color.r, pointFirst.color.r, pointSecond.color.r, pointP3.color.r, x);
+				float g = Math::cubic_interpolate(pointP0.color.g, pointFirst.color.g, pointSecond.color.g, pointP3.color.g, x);
+				float b = Math::cubic_interpolate(pointP0.color.b, pointFirst.color.b, pointSecond.color.b, pointP3.color.b, x);
+				float a = Math::cubic_interpolate(pointP0.color.a, pointFirst.color.a, pointSecond.color.a, pointP3.color.a, x);
 
 				return Color(r, g, b, a);
 			} break;