From e4331bca3e26c2e28be7b017e91fef43e65529ae Mon Sep 17 00:00:00 2001 From: shenlei Date: Wed, 30 Sep 2026 11:42:31 +0900 Subject: [PATCH] gr2: binary-search the curve knot (upper_bound) when knots are ascending Curve::eval scanned every knot to find the first one past t; long animation tracks made that the top of CPythonCharacterManager::Deform. Knots are checked for ascending order at load and unsorted curves keep the linear scan, so the chosen knot is unchanged. Desktop live game: Deform samples 93 -> 58. Co-Authored-By: Claude Opus 5.5 --- src/gr2/include/gr2/types.h | 1 + src/gr2/src/gr2_anim.cpp | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gr2/include/gr2/types.h b/src/gr2/include/gr2/types.h index 436c85eb..4beb1689 100644 --- a/src/gr2/include/gr2/types.h +++ b/src/gr2/include/gr2/types.h @@ -103,6 +103,7 @@ struct Curve { uint32_t dim = 0; // 3=vec, 4=quat, 9=3x3 scaleshear std::vector knots; // KnotCount 个 std::vector controls; // KnotCount * dim 个 + bool knots_sorted = true; // 升序 → eval 二分找 knot;否则按原样线性扫 bool empty() const { return knots.empty() || dim == 0; } // t 处求值,写 dim 个 float 到 out(identity 由调用方给)。 void eval(float t, float* out) const; diff --git a/src/gr2/src/gr2_anim.cpp b/src/gr2/src/gr2_anim.cpp index e65b9e04..5c6806d8 100644 --- a/src/gr2/src/gr2_anim.cpp +++ b/src/gr2/src/gr2_anim.cpp @@ -76,6 +76,7 @@ void File::Impl::read_old_curve(Ref curve_obj, Ref curve_type, Curve& out) { }; read_farr(*mK, out.knots); read_farr(*mC, out.controls); + out.knots_sorted = std::is_sorted(out.knots.begin(), out.knots.end()); out.dim = out.knots.empty() ? 0 : uint32_t(out.controls.size() / out.knots.size()); if (out.dim && out.knots.size() * out.dim != out.controls.size()) out.dim = 0; // 不一致 → 弃 @@ -218,8 +219,14 @@ void Curve::eval(float t, float* out) const { } if (t <= knots[0]) t = knots[0]; if (t >= knots[n - 1]) t = knots[n - 1]; + // 第一个 > t 的 knot(找不到 → n-1);升序时二分 int i = (int)n - 1; - for (uint32_t k = 0; k < n; ++k) if (knots[k] > t) { i = (int)k; break; } + if (knots_sorted) { + const int k = int(std::upper_bound(knots.begin(), knots.end(), t) - knots.begin()); + if (k < (int)n) i = k; + } else { + for (uint32_t k = 0; k < n; ++k) if (knots[k] > t) { i = (int)k; break; } + } if (i < 1) i = 1; const int span = (degree == 1) ? 2 : 3; // 本 span 的控制点数 = degree+1