Skip to content

GH-854 Add Monotonic Cubic Interpolation#1224

Open
JoltedJon wants to merge 3 commits intoRedot-Engine:masterfrom
JoltedJon:GH-854
Open

GH-854 Add Monotonic Cubic Interpolation#1224
JoltedJon wants to merge 3 commits intoRedot-Engine:masterfrom
JoltedJon:GH-854

Conversation

@JoltedJon
Copy link
Contributor

@JoltedJon JoltedJon commented Mar 13, 2026

Adds a Monotonic version of Cubic Interpolation. resolves #854

Cubic Interpolation is prone to overshooting during animations. This new feature allows for animations to be smooth but also doesn't overshoot the key frames.

The new function keeps the curve monotonic which means that the first derivative of the curve keeps the same sign, which cubic interpolation does not honor.

Here is the difference between Cubic and Monotonic Cubic for a curve going from 0 -> 90 -> 0 -> 0 -> 90.
image

screenrecording-2026-03-13_00-31-00.mp4

Summary by CodeRabbit

  • New Features
    • Added monotonic cubic interpolation (including angle- and time-aware variants) across math primitives, Vector2/3/4, Quaternion, Variant and animation paths; exposed new interpolation enums and API, editor menu options, and GLTF mapping.
  • Tests
    • Added unit tests covering monotonic cubic interpolation variants.

@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: da3fa3d9-eb07-4633-bc40-96050068d877

📥 Commits

Reviewing files that changed from the base of the PR and between 3e8190e and c6c7be0.

📒 Files selected for processing (1)
  • modules/gltf/structures/gltf_animation.cpp

Walkthrough

Adds monotonic cubic interpolation support across core math, vector/quaternion types, variant bindings, animation runtime, and editor menus, introducing INTERPOLATION_CUBIC_MONOTONIC and INTERPOLATION_CUBIC_MONOTONIC_ANGLE and corresponding time/angle-aware APIs and tests.

Changes

Cohort / File(s) Summary
Core Math Functions
core/math/math_funcs.h
Added templated monotonic cubic interpolation functions: monotonic_cubic_interpolate, monotonic_cubic_interpolate_in_time, monotonic_cubic_interpolate_angle, monotonic_cubic_interpolate_angle_in_time. Implement Hermite basis with monotonic tangent computation and time-aware tangent derivation.
Vector & Quaternion Types
core/math/vector2.h, core/math/vector3.h, core/math/vector4.h, core/math/vector4.cpp, core/math/quaternion.h, core/math/quaternion.cpp
Added per-type monotonic cubic interpolation methods for Vector2/3/4 and Quaternion, including time-aware variants. Quaternion uses Expmap/log-space per-component monotonic interpolation and slerp blending.
Variant Layer & Utilities
core/variant/variant_call.cpp, core/variant/variant_utility.h, core/variant/variant_utility.cpp
Registered new built-in methods and VariantUtilityFunctions wrappers for monotonic cubic interpolation (regular, angle, and in_time variants) for numeric, vector, and quaternion types.
Animation Runtime
scene/resources/animation.h, scene/resources/animation.cpp
Added INTERPOLATION_CUBIC_MONOTONIC and INTERPOLATION_CUBIC_MONOTONIC_ANGLE; implemented per-type _monotonic_cubic_interpolate_in_time overloads and Variant dispatch; integrated monotonic cases into _interpolate and optimization paths.
Editor: Animation Track UI
editor/animation/animation_track_editor.h, editor/animation/animation_track_editor.cpp
Added menu constants and UI entries for Monotonic Cubic / Monotonic Cubic Angle; extended interpolation selection, insertion, and angle-detection branches to include monotonic variants.
GLTF Mapping
modules/gltf/structures/gltf_animation.cpp
Mapped new MONOTONIC interpolation enum cases to existing GLTF cubic spline export path.
Tests
tests/core/math/test_math_funcs.h
Added templated tests for monotonic cubic interpolation (including angle and time variants) for float/double.

Sequence Diagram(s)

sequenceDiagram
    participant Editor as Editor (Track UI)
    participant Animation as Animation Runtime
    participant Math as Math::monotonic_cubic*
    participant Type as Vector/Quaternion Implementation
    participant Variant as Variant Bindings / Scripts

    Editor->>Animation: User selects/interpolates key (MONOTONIC)
    Animation->>Type: _interpolate dispatch (INTERPOLATION_CUBIC_MONOTONIC)
    Type->>Math: call monotonic_cubic_interpolate(_in_time / _angle variants)
    Math-->>Type: interpolated numeric components
    Type-->>Animation: composed Vector/Quaternion result
    Animation-->>Variant: expose result to scripting / export
    Variant-->>Editor: script-accessible interpolation methods
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'GH-854 Add Monotonic Cubic Interpolation' clearly and concisely describes the main change—adding monotonic cubic interpolation functionality—and directly relates to the PR objectives.
Linked Issues check ✅ Passed The PR comprehensively addresses issue #854 by implementing monotonic cubic interpolation across Math utilities, Vector2/3/4, Quaternion, Animation system, and editor UI to prevent cubic interpolation overshoot in animation playback.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing monotonic cubic interpolation functionality; no unrelated modifications or refactoring found outside the stated objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can enable review details to help with troubleshooting, context usage and more.

Enable the reviews.review_details setting to include review details such as the model used, the time taken for each step and more in the review comments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
editor/animation/animation_track_editor.cpp (1)

3092-3117: ⚠️ Potential issue | 🔴 Critical

Add icon handling for the new interpolation enums.

These modes are now selectable, but the draw path at Lines 2315-2321 and Line 2395 still uses a 5-entry interp_icon lookup. That no longer matches the interpolation enum, so monotonic tracks will show the wrong icon or read past the array during redraw.

Suggested fix
-				Ref<Texture2D> interp_icon[5] = {
-					get_editor_theme_icon(SNAME("InterpRaw")),
-					get_editor_theme_icon(SNAME("InterpLinear")),
-					get_editor_theme_icon(SNAME("InterpCubic")),
-					get_editor_theme_icon(SNAME("InterpLinearAngle")),
-					get_editor_theme_icon(SNAME("InterpCubicAngle")),
-				};
@@
-					Ref<Texture2D> icon = interp_icon[interp_mode];
+					Ref<Texture2D> icon;
+					switch (interp_mode) {
+						case Animation::INTERPOLATION_NEAREST:
+							icon = get_editor_theme_icon(SNAME("InterpRaw"));
+							break;
+						case Animation::INTERPOLATION_LINEAR:
+							icon = get_editor_theme_icon(SNAME("InterpLinear"));
+							break;
+						case Animation::INTERPOLATION_CUBIC:
+						case Animation::INTERPOLATION_CUBIC_MONOTONIC:
+							icon = get_editor_theme_icon(SNAME("InterpCubic"));
+							break;
+						case Animation::INTERPOLATION_LINEAR_ANGLE:
+							icon = get_editor_theme_icon(SNAME("InterpLinearAngle"));
+							break;
+						case Animation::INTERPOLATION_CUBIC_ANGLE:
+						case Animation::INTERPOLATION_CUBIC_MONOTONIC_ANGLE:
+							icon = get_editor_theme_icon(SNAME("InterpCubicAngle"));
+							break;
+						default:
+							icon = get_editor_theme_icon(SNAME("InterpRaw"));
+							break;
+					}

Also applies to: 3568-3571

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@editor/animation/animation_track_editor.cpp` around lines 3092 - 3117, The
draw code still uses a 5-entry interp_icon lookup which no longer matches the
expanded interpolation enum (new monotonic entries), causing wrong icons/UB;
update the interp_icon array and any switch/lookup in the drawing code to
include icons for MENU_INTERPOLATION_CUBIC_MONOTONIC and
MENU_INTERPOLATION_CUBIC_MONOTONIC_ANGLE (and their angle/non-angle
counterparts), and adjust any index mapping logic so each interpolation enum
value maps to the correct icon (update references to interp_icon and the drawing
functions that read interpolation enum values). Ensure you add the corresponding
get_editor_theme_icon calls for the new monotonic variants and verify the lookup
size matches the enum range so no out-of-bounds access occurs.
scene/resources/animation.h (1)

62-70: ⚠️ Potential issue | 🔴 Critical

Do not renumber existing InterpolationType enum values.

Adding INTERPOLATION_CUBIC_MONOTONIC before existing entries changes legacy numeric IDs (notably INTERPOLATION_LINEAR_ANGLE and INTERPOLATION_CUBIC_ANGLE). That can break backward compatibility for serialized animation tracks and runtime interpolation selection.

🔧 Proposed fix
 	enum InterpolationType : uint8_t {
 		INTERPOLATION_NEAREST,
 		INTERPOLATION_LINEAR,
 		INTERPOLATION_CUBIC,
-		INTERPOLATION_CUBIC_MONOTONIC,
 		INTERPOLATION_LINEAR_ANGLE,
 		INTERPOLATION_CUBIC_ANGLE,
+		INTERPOLATION_CUBIC_MONOTONIC,
 		INTERPOLATION_CUBIC_MONOTONIC_ANGLE,
 	};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scene/resources/animation.h` around lines 62 - 70, The enum InterpolationType
was modified in a way that shifts numeric IDs (specifically
INTERPOLATION_LINEAR_ANGLE and INTERPOLATION_CUBIC_ANGLE); restore backward
compatibility by ensuring existing values retain their original numeric
IDs—either move INTERPOLATION_CUBIC_MONOTONIC to the end of the enum list or add
explicit integer assignments for each enum entry so INTERPOLATION_NEAREST,
INTERPOLATION_LINEAR, INTERPOLATION_CUBIC, INTERPOLATION_LINEAR_ANGLE, and
INTERPOLATION_CUBIC_ANGLE keep their previous numeric values; update the
InterpolationType definition accordingly to avoid changing legacy serialized
IDs.
🧹 Nitpick comments (2)
core/math/quaternion.cpp (1)

269-368: Extract the shared spherical-cubic core.

These two overloads duplicate the full phase-alignment and dual-expmap flow from spherical_cubic_interpolate{_in_time}. A small helper that takes the scalar interpolation op would keep future fixes to the quaternion math in one place.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/math/quaternion.cpp` around lines 269 - 368, Both
spherical_monotonic_cubic_interpolate and
spherical_monotonic_cubic_interpolate_in_time duplicate the phase-alignment,
flip handling, dual ExpMap and slerp blending logic; extract that shared flow
into a single helper (e.g., spherical_monotonic_cubic_interpolate_core) that
accepts a scalar interpolation callable (std::function or template parameter)
and any optional time arguments, so the two public methods call the core with
either Math::monotonic_cubic_interpolate or
Math::monotonic_cubic_interpolate_in_time; update the core to perform Basis
conversions, flip adjustments (from_q, pre_q, to_q, post_q), compute ln vectors
in both from_q and to_q spaces, call the provided scalar interpolator for x/y/z,
build q1/q2 and return q1.slerp(q2, p_weight), keeping the public function names
spherical_monotonic_cubic_interpolate and
spherical_monotonic_cubic_interpolate_in_time as thin wrappers.
scene/resources/animation.cpp (1)

6566-6754: Extract the shared Variant cubic dispatcher before these two implementations drift.

Animation::monotonic_cubic_interpolate_in_time_variant is effectively a second copy of Animation::cubic_interpolate_in_time_variant. Any future type fix now has to be mirrored across another very large switch and array-walking block. I'd pull the shared traversal into a helper and inject the cubic vs monotonic primitives.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scene/resources/animation.cpp` around lines 6566 - 6754, The two large
switch+array traversal blocks in
Animation::monotonic_cubic_interpolate_in_time_variant and
Animation::cubic_interpolate_in_time_variant should be refactored into a single
helper (e.g., Animation::variant_cubic_dispatcher) that accepts a strategy flag
or function pointers for the primitive scalar/vector interpolation routines
(e.g., Math::cubic_interpolate_in_time vs
Math::monotonic_cubic_interpolate_in_time and the instance methods like
Vector2::monotonic_cubic_interpolate_in_time / cubic_interpolate_in_time,
Quaternion::spherical_monotonic_cubic_interpolate_in_time /
spherical_cubic_interpolate_in_time). Move the shared array handling and
type-switch logic into that helper and have the two public methods call it with
the appropriate primitive functions; ensure you preserve the special-casing
(numeric cast_to_blendwise/cast_from_blendwise, string fallback,
PACKED_BYTE_ARRAY skip, p_snap_array_element behavior) by passing any needed
flags through the helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/math/math_funcs.h`:
- Around line 947-960: The function monotonic_cubic_interpolate_angle_in_time
has the timestamp parameters in the wrong order (p_pre_t, p_to_t, p_post_t)
which mismatches the established _in_time API; change the signature to accept (T
p_to_t, T p_pre_t, T p_post_t) and update the call to
monotonic_cubic_interpolate_in_time(...) to pass the timestamps in the same
order expected by that function (p_weight, p_to_t, p_pre_t, p_post_t) so pre/to
timestamps are not swapped; ensure the parameter names in the function
declaration/definition and any callers use the corrected order to preserve API
consistency with cubic_interpolate_angle_in_time and VariantUtilityFunctions.

In `@core/variant/variant_utility.cpp`:
- Around line 548-550: The wrapper
VariantUtilityFunctions::monotonic_cubic_interpolate_angle_in_time forwards time
arguments to Math::monotonic_cubic_interpolate_angle_in_time in the wrong order,
swapping to_t and pre_t; fix it by calling
Math::monotonic_cubic_interpolate_angle_in_time(from, to, pre, post, weight,
pre_t, to_t, post_t) so that the forwarded times match Math's expected (p_pre_t,
p_to_t, p_post_t) parameter order.

In `@tests/core/math/test_math_funcs.h`:
- Around line 694-700: The test block is calling
Math::cubic_interpolate_angle_in_time instead of the intended
Math::monotonic_cubic_interpolate_angle_in_time; update all five CHECK lines to
call Math::monotonic_cubic_interpolate_angle_in_time (keeping the same argument
order) so the monotonic helper is exercised, then re-run tests and update the
expected doctest::Approx values to the correct baselines produced by the
monotonic implementation.

---

Outside diff comments:
In `@editor/animation/animation_track_editor.cpp`:
- Around line 3092-3117: The draw code still uses a 5-entry interp_icon lookup
which no longer matches the expanded interpolation enum (new monotonic entries),
causing wrong icons/UB; update the interp_icon array and any switch/lookup in
the drawing code to include icons for MENU_INTERPOLATION_CUBIC_MONOTONIC and
MENU_INTERPOLATION_CUBIC_MONOTONIC_ANGLE (and their angle/non-angle
counterparts), and adjust any index mapping logic so each interpolation enum
value maps to the correct icon (update references to interp_icon and the drawing
functions that read interpolation enum values). Ensure you add the corresponding
get_editor_theme_icon calls for the new monotonic variants and verify the lookup
size matches the enum range so no out-of-bounds access occurs.

In `@scene/resources/animation.h`:
- Around line 62-70: The enum InterpolationType was modified in a way that
shifts numeric IDs (specifically INTERPOLATION_LINEAR_ANGLE and
INTERPOLATION_CUBIC_ANGLE); restore backward compatibility by ensuring existing
values retain their original numeric IDs—either move
INTERPOLATION_CUBIC_MONOTONIC to the end of the enum list or add explicit
integer assignments for each enum entry so INTERPOLATION_NEAREST,
INTERPOLATION_LINEAR, INTERPOLATION_CUBIC, INTERPOLATION_LINEAR_ANGLE, and
INTERPOLATION_CUBIC_ANGLE keep their previous numeric values; update the
InterpolationType definition accordingly to avoid changing legacy serialized
IDs.

---

Nitpick comments:
In `@core/math/quaternion.cpp`:
- Around line 269-368: Both spherical_monotonic_cubic_interpolate and
spherical_monotonic_cubic_interpolate_in_time duplicate the phase-alignment,
flip handling, dual ExpMap and slerp blending logic; extract that shared flow
into a single helper (e.g., spherical_monotonic_cubic_interpolate_core) that
accepts a scalar interpolation callable (std::function or template parameter)
and any optional time arguments, so the two public methods call the core with
either Math::monotonic_cubic_interpolate or
Math::monotonic_cubic_interpolate_in_time; update the core to perform Basis
conversions, flip adjustments (from_q, pre_q, to_q, post_q), compute ln vectors
in both from_q and to_q spaces, call the provided scalar interpolator for x/y/z,
build q1/q2 and return q1.slerp(q2, p_weight), keeping the public function names
spherical_monotonic_cubic_interpolate and
spherical_monotonic_cubic_interpolate_in_time as thin wrappers.

In `@scene/resources/animation.cpp`:
- Around line 6566-6754: The two large switch+array traversal blocks in
Animation::monotonic_cubic_interpolate_in_time_variant and
Animation::cubic_interpolate_in_time_variant should be refactored into a single
helper (e.g., Animation::variant_cubic_dispatcher) that accepts a strategy flag
or function pointers for the primitive scalar/vector interpolation routines
(e.g., Math::cubic_interpolate_in_time vs
Math::monotonic_cubic_interpolate_in_time and the instance methods like
Vector2::monotonic_cubic_interpolate_in_time / cubic_interpolate_in_time,
Quaternion::spherical_monotonic_cubic_interpolate_in_time /
spherical_cubic_interpolate_in_time). Move the shared array handling and
type-switch logic into that helper and have the two public methods call it with
the appropriate primitive functions; ensure you preserve the special-casing
(numeric cast_to_blendwise/cast_from_blendwise, string fallback,
PACKED_BYTE_ARRAY skip, p_snap_array_element behavior) by passing any needed
flags through the helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a60ef8ef-5981-48e7-9a61-c26f77ab2797

📥 Commits

Reviewing files that changed from the base of the PR and between 7ff8093 and 3e8190e.

📒 Files selected for processing (15)
  • core/math/math_funcs.h
  • core/math/quaternion.cpp
  • core/math/quaternion.h
  • core/math/vector2.h
  • core/math/vector3.h
  • core/math/vector4.cpp
  • core/math/vector4.h
  • core/variant/variant_call.cpp
  • core/variant/variant_utility.cpp
  • core/variant/variant_utility.h
  • editor/animation/animation_track_editor.cpp
  • editor/animation/animation_track_editor.h
  • scene/resources/animation.cpp
  • scene/resources/animation.h
  • tests/core/math/test_math_funcs.h

Comment on lines +947 to +960
template <typename T>
constexpr T monotonic_cubic_interpolate_angle_in_time(T p_from, T p_to, T p_pre, T p_post, T p_weight, T p_pre_t, T p_to_t, T p_post_t) {
T from_rot = fmod(p_from, (T)TAU);

T pre_diff = fmod(p_pre - from_rot, (T)TAU);
T pre_rot = from_rot + fmod((T)2 * pre_diff, (T)TAU) - pre_diff;

T to_diff = fmod(p_to - from_rot, (T)TAU);
T to_rot = from_rot + fmod((T)2 * to_diff, (T)TAU) - to_diff;

T post_diff = fmod(p_post - to_rot, (T)TAU);
T post_rot = to_rot + fmod((T)2 * post_diff, (T)TAU) - post_diff;

return monotonic_cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Compare the positional argument order used by the existing and new angle-in-time helpers.
rg -n -C2 '\b(cubic_interpolate_angle_in_time|monotonic_cubic_interpolate_angle_in_time)\s*\(' --glob='*.{h,hpp,hh,c,cc,cpp,cxx}'

Repository: Redot-Engine/redot-engine

Length of output: 7269


Fix parameter order for monotonic_cubic_interpolate_angle_in_time to match existing _in_time APIs.

The new function signature takes (p_pre_t, p_to_t, p_post_t) while the existing cubic_interpolate_angle_in_time() takes (p_to_t, p_pre_t, p_post_t). This breaks the API contract—any caller copied from the existing helper or using the pattern established by VariantUtilityFunctions will silently swap the pre and to timestamps, computing incorrect tangent magnitudes.

Suggested fix
 template <typename T>
-constexpr T monotonic_cubic_interpolate_angle_in_time(T p_from, T p_to, T p_pre, T p_post, T p_weight, T p_pre_t, T p_to_t, T p_post_t) {
+constexpr T monotonic_cubic_interpolate_angle_in_time(T p_from, T p_to, T p_pre, T p_post, T p_weight, T p_to_t, T p_pre_t, T p_post_t) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template <typename T>
constexpr T monotonic_cubic_interpolate_angle_in_time(T p_from, T p_to, T p_pre, T p_post, T p_weight, T p_pre_t, T p_to_t, T p_post_t) {
T from_rot = fmod(p_from, (T)TAU);
T pre_diff = fmod(p_pre - from_rot, (T)TAU);
T pre_rot = from_rot + fmod((T)2 * pre_diff, (T)TAU) - pre_diff;
T to_diff = fmod(p_to - from_rot, (T)TAU);
T to_rot = from_rot + fmod((T)2 * to_diff, (T)TAU) - to_diff;
T post_diff = fmod(p_post - to_rot, (T)TAU);
T post_rot = to_rot + fmod((T)2 * post_diff, (T)TAU) - post_diff;
return monotonic_cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
template <typename T>
constexpr T monotonic_cubic_interpolate_angle_in_time(T p_from, T p_to, T p_pre, T p_post, T p_weight, T p_to_t, T p_pre_t, T p_post_t) {
T from_rot = fmod(p_from, (T)TAU);
T pre_diff = fmod(p_pre - from_rot, (T)TAU);
T pre_rot = from_rot + fmod((T)2 * pre_diff, (T)TAU) - pre_diff;
T to_diff = fmod(p_to - from_rot, (T)TAU);
T to_rot = from_rot + fmod((T)2 * to_diff, (T)TAU) - to_diff;
T post_diff = fmod(p_post - to_rot, (T)TAU);
T post_rot = to_rot + fmod((T)2 * post_diff, (T)TAU) - post_diff;
return monotonic_cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/math/math_funcs.h` around lines 947 - 960, The function
monotonic_cubic_interpolate_angle_in_time has the timestamp parameters in the
wrong order (p_pre_t, p_to_t, p_post_t) which mismatches the established
_in_time API; change the signature to accept (T p_to_t, T p_pre_t, T p_post_t)
and update the call to monotonic_cubic_interpolate_in_time(...) to pass the
timestamps in the same order expected by that function (p_weight, p_to_t,
p_pre_t, p_post_t) so pre/to timestamps are not swapped; ensure the parameter
names in the function declaration/definition and any callers use the corrected
order to preserve API consistency with cubic_interpolate_angle_in_time and
VariantUtilityFunctions.

Comment on lines +548 to +550
double VariantUtilityFunctions::monotonic_cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
double to_t, double pre_t, double post_t) {
return Math::monotonic_cubic_interpolate_angle_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix swapped time arguments in angle monotonic wrapper (wrong interpolation behavior).

At Line 550, to_t and pre_t are forwarded in the wrong order for Math::monotonic_cubic_interpolate_angle_in_time.
core/math/math_funcs.h expects (..., p_pre_t, p_to_t, p_post_t). Current forwarding can distort angle interpolation timing.

🔧 Proposed fix
 double VariantUtilityFunctions::monotonic_cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
 		double to_t, double pre_t, double post_t) {
-	return Math::monotonic_cubic_interpolate_angle_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
+	return Math::monotonic_cubic_interpolate_angle_in_time(from, to, pre, post, weight, pre_t, to_t, post_t);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
double VariantUtilityFunctions::monotonic_cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
double to_t, double pre_t, double post_t) {
return Math::monotonic_cubic_interpolate_angle_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
double VariantUtilityFunctions::monotonic_cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
double to_t, double pre_t, double post_t) {
return Math::monotonic_cubic_interpolate_angle_in_time(from, to, pre, post, weight, pre_t, to_t, post_t);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/variant/variant_utility.cpp` around lines 548 - 550, The wrapper
VariantUtilityFunctions::monotonic_cubic_interpolate_angle_in_time forwards time
arguments to Math::monotonic_cubic_interpolate_angle_in_time in the wrong order,
swapping to_t and pre_t; fix it by calling
Math::monotonic_cubic_interpolate_angle_in_time(from, to, pre, post, weight,
pre_t, to_t, post_t) so that the forwarded times match Math's expected (p_pre_t,
p_to_t, p_post_t) parameter order.

Comment on lines +694 to +700
TEST_CASE_TEMPLATE("[Math] monotonic_cubic_interpolate_angle_in_time", T, float, double) {
CHECK(Math::cubic_interpolate_angle_in_time((T)(Math::PI * (1.0 / 6.0)), (T)(Math::PI * (5.0 / 6.0)), (T)0.0, (T)Math::PI, (T)0.0, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.0));
CHECK(Math::cubic_interpolate_angle_in_time((T)(Math::PI * (1.0 / 6.0)), (T)(Math::PI * (5.0 / 6.0)), (T)0.0, (T)Math::PI, (T)0.25, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)0.494964));
CHECK(Math::cubic_interpolate_angle_in_time((T)(Math::PI * (1.0 / 6.0)), (T)(Math::PI * (5.0 / 6.0)), (T)0.0, (T)Math::PI, (T)0.5, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)1.27627));
CHECK(Math::cubic_interpolate_angle_in_time((T)(Math::PI * (1.0 / 6.0)), (T)(Math::PI * (5.0 / 6.0)), (T)0.0, (T)Math::PI, (T)0.75, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)2.07394));
CHECK(Math::cubic_interpolate_angle_in_time((T)(Math::PI * (1.0 / 6.0)), (T)(Math::PI * (5.0 / 6.0)), (T)0.0, (T)Math::PI, (T)1.0, (T)0.5, (T)0.0, (T)1.0) == doctest::Approx((T)Math::PI * (5.0 / 6.0)));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

This block never hits the monotonic angle-in-time helper.

All five assertions still call Math::cubic_interpolate_angle_in_time(), so this duplicates the cubic coverage and leaves Math::monotonic_cubic_interpolate_angle_in_time() untested. The copied expectations will also need re-baselining once the monotonic call is wired in.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/core/math/test_math_funcs.h` around lines 694 - 700, The test block is
calling Math::cubic_interpolate_angle_in_time instead of the intended
Math::monotonic_cubic_interpolate_angle_in_time; update all five CHECK lines to
call Math::monotonic_cubic_interpolate_angle_in_time (keeping the same argument
order) so the monotonic helper is exercised, then re-run tests and update the
expected doctest::Approx values to the correct baselines produced by the
monotonic implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3D Animation play back is wrong when interpolation is cubic

1 participant