diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index d2cd76b796c5..03b45e8e0d12 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -1313,6 +1313,33 @@ void Curve3D::_bake() const { idx++; } + + //Tilt smoothing, paralell rotation frame does not guarantee that the rotation at the beginning of the curve is equal to that at the end of the curve. + //Check out: Wang, W., Juttler, B., Zheng, D., and Liu, Y. 2008. Computation of rotation minimizing frame. + + if (auto_tilts) { + + //Calculate tilt angle difference between first and last baked up vector + Vector3 first_up = up_write[0]; + Vector3 last_up = up_write[pointlist.size() - 1]; + Vector3 tangent = Vector3(0, 0, 0); + + for (int i = 0; i < idx; i++) { + tangent = (w[0] - w[i]); + if (tangent.length_squared() > CMP_EPSILON2) { + break; + } + } + tangent = tangent.normalized(); + float phi = first_up.signed_angle_to(last_up, tangent); + + for (int i = 0; i < idx; i++) { + wt[i] += phi * float(i) / float(idx - 1); + } + } + + + } real_t Curve3D::get_baked_length() const { @@ -1584,6 +1611,16 @@ bool Curve3D::is_up_vector_enabled() const { return up_vector_enabled; } +void Curve3D::set_auto_tilts(bool p_auto_tilts) { + auto_tilts = p_auto_tilts; + baked_cache_dirty = true; + emit_signal(CoreStringNames::get_singleton()->changed); +} + +bool Curve3D::is_auto_tilts() const { + return auto_tilts; +} + Dictionary Curve3D::_get_data() const { Dictionary dc; @@ -1684,6 +1721,8 @@ void Curve3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval); ClassDB::bind_method(D_METHOD("set_up_vector_enabled", "enable"), &Curve3D::set_up_vector_enabled); ClassDB::bind_method(D_METHOD("is_up_vector_enabled"), &Curve3D::is_up_vector_enabled); + ClassDB::bind_method(D_METHOD("set_auto_tilts", "enable"), &Curve3D::set_auto_tilts); + ClassDB::bind_method(D_METHOD("is_auto_tilts"), &Curve3D::is_auto_tilts); ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve3D::get_baked_length); ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve3D::interpolate_baked, DEFVAL(false)); @@ -1701,6 +1740,8 @@ void Curve3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval"); ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_tilts"), "set_auto_tilts", "is_auto_tilts"); + ADD_GROUP("Up Vector", "up_vector_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "up_vector_enabled"), "set_up_vector_enabled", "is_up_vector_enabled"); } diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 767900b84310..b8559d461396 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -232,6 +232,7 @@ class Curve3D : public Resource { real_t bake_interval = 0.2; bool up_vector_enabled = true; + bool auto_tilts= true; void _bake_segment3d(Map &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; Dictionary _get_data() const; @@ -261,6 +262,8 @@ class Curve3D : public Resource { real_t get_bake_interval() const; void set_up_vector_enabled(bool p_enable); bool is_up_vector_enabled() const; + void set_auto_tilts(bool p_auto_tilts); + bool is_auto_tilts() const; real_t get_baked_length() const; Vector3 interpolate_baked(real_t p_offset, bool p_cubic = false) const;