From 0b89b90b360f1a42f2159111fe39dafd862cd553 Mon Sep 17 00:00:00 2001 From: Ferenc Arn Date: Sat, 21 Oct 2017 11:26:55 -0400 Subject: [PATCH] Fix PathFollow rotations. Replaced the lookahead (which is problematic) with exact delta in offset. Also made some other minor fixes and improvements. Fixes #12258. --- scene/3d/path.cpp | 52 ++++++++++++++++++++++------------------------- scene/3d/path.h | 5 +---- 2 files changed, 25 insertions(+), 32 deletions(-) diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index 60245fe6ceb..65f20210e18 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -85,9 +85,15 @@ void PathFollow::_update_transform() { if (!c.is_valid()) return; + if (delta_offset == 0) { + return; + } + float o = offset; - if (loop) + + if (loop) { o = Math::fposmod(o, c->get_baked_length()); + } Vector3 pos = c->interpolate_baked(o, cubic); Transform t = get_transform(); @@ -101,14 +107,14 @@ void PathFollow::_update_transform() { // see C. Dougan, The Parallel Transport Frame, Game Programming Gems 2 for example // for a discussion about why not Frenet frame. - Vector3 t_prev = pos - c->interpolate_baked(o - lookahead, cubic); - Vector3 t_cur = c->interpolate_baked(o + lookahead, cubic) - pos; + Vector3 t_prev = (pos - c->interpolate_baked(o - delta_offset, cubic)).normalized(); + Vector3 t_cur = (c->interpolate_baked(o + delta_offset, cubic) - pos).normalized(); Vector3 axis = t_prev.cross(t_cur); - float dot = t_prev.normalized().dot(t_cur.normalized()); + float dot = t_prev.dot(t_cur); float angle = Math::acos(CLAMP(dot, -1, 1)); - if (axis.length() > CMP_EPSILON && angle > CMP_EPSILON) { + if (likely(Math::abs(angle) > CMP_EPSILON)) { if (rotation_mode == ROTATION_Y) { // assuming we're referring to global Y-axis. is this correct? axis.x = 0; @@ -116,27 +122,31 @@ void PathFollow::_update_transform() { } else if (rotation_mode == ROTATION_XY) { axis.z = 0; } else if (rotation_mode == ROTATION_XYZ) { - // all components are OK + // all components are allowed } - t.rotate_basis(axis.normalized(), angle); + if (likely(axis.length() > CMP_EPSILON)) { + t.rotate_basis(axis.normalized(), angle); + } } // do the additional tilting float tilt_angle = c->interpolate_baked_tilt(o); - Vector3 tilt_axis = t_cur; // is this correct?? + Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct?? - if (tilt_axis.length() > CMP_EPSILON && tilt_angle > CMP_EPSILON) { + if (likely(Math::abs(tilt_angle) > CMP_EPSILON)) { if (rotation_mode == ROTATION_Y) { tilt_axis.x = 0; tilt_axis.z = 0; } else if (rotation_mode == ROTATION_XY) { tilt_axis.z = 0; } else if (rotation_mode == ROTATION_XYZ) { - // all components are OK + // all components are allowed } - t.rotate_basis(tilt_axis.normalized(), tilt_angle); + if (likely(tilt_axis.length() > CMP_EPSILON)) { + t.rotate_basis(tilt_axis.normalized(), tilt_angle); + } } t.translate(pos_offset); @@ -195,8 +205,6 @@ bool PathFollow::_set(const StringName &p_name, const Variant &p_value) { set_cubic_interpolation(p_value); } else if (String(p_name) == "loop") { set_loop(p_value); - } else if (String(p_name) == "lookahead") { - set_lookahead(p_value); } else return false; @@ -219,8 +227,6 @@ bool PathFollow::_get(const StringName &p_name, Variant &r_ret) const { r_ret = cubic; } else if (String(p_name) == "loop") { r_ret = loop; - } else if (String(p_name) == "lookahead") { - r_ret = lookahead; } else return false; @@ -238,7 +244,6 @@ void PathFollow::_get_property_list(List *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ")); p_list->push_back(PropertyInfo(Variant::BOOL, "cubic_interp")); p_list->push_back(PropertyInfo(Variant::BOOL, "loop")); - p_list->push_back(PropertyInfo(Variant::REAL, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001")); } void PathFollow::_bind_methods() { @@ -271,8 +276,9 @@ void PathFollow::_bind_methods() { } void PathFollow::set_offset(float p_offset) { - + delta_offset = p_offset - offset; offset = p_offset; + if (path) _update_transform(); _change_notify("offset"); @@ -322,16 +328,6 @@ float PathFollow::get_unit_offset() const { return 0; } -void PathFollow::set_lookahead(float p_lookahead) { - - lookahead = p_lookahead; -} - -float PathFollow::get_lookahead() const { - - return lookahead; -} - void PathFollow::set_rotation_mode(RotationMode p_rotation_mode) { rotation_mode = p_rotation_mode; @@ -356,11 +352,11 @@ bool PathFollow::has_loop() const { PathFollow::PathFollow() { offset = 0; + delta_offset = 0; h_offset = 0; v_offset = 0; path = NULL; rotation_mode = ROTATION_XYZ; cubic = true; loop = true; - lookahead = 0.1; } diff --git a/scene/3d/path.h b/scene/3d/path.h index 0f9a169f727..52760e0c754 100644 --- a/scene/3d/path.h +++ b/scene/3d/path.h @@ -67,10 +67,10 @@ public: private: Path *path; + real_t delta_offset; // change in offset since last _update_transform real_t offset; real_t h_offset; real_t v_offset; - real_t lookahead; bool cubic; bool loop; RotationMode rotation_mode; @@ -98,9 +98,6 @@ public: void set_unit_offset(float p_unit_offset); float get_unit_offset() const; - void set_lookahead(float p_lookahead); - float get_lookahead() const; - void set_loop(bool p_loop); bool has_loop() const;