diff --git a/doc/classes/PathFollow3D.xml b/doc/classes/PathFollow3D.xml
index 42094b42beb7..442d93ef8570 100644
--- a/doc/classes/PathFollow3D.xml
+++ b/doc/classes/PathFollow3D.xml
@@ -46,6 +46,9 @@
The node's offset perpendicular to the curve.
+
+ If [code]true[/code], the node moves with the glTF forward axis (+Z) in the front.
+
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index fbbca2b2ead1..26bd19c50dce 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -191,6 +191,9 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
t.origin = pos;
} else {
t = c->sample_baked_with_rotation(progress, cubic, false);
+ if (z_forward) {
+ t.basis = Basis(t.basis.get_column(1).normalized(), Math_PI) * t.basis;
+ }
Vector3 forward = t.basis.get_column(2); // Retain tangent for applying tilt
t = PathFollow3D::correct_posture(t, rotation_mode);
@@ -334,6 +337,9 @@ void PathFollow3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cubic_interpolation_enabled", "enabled"), &PathFollow3D::set_cubic_interpolation_enabled);
ClassDB::bind_method(D_METHOD("is_cubic_interpolation_enabled"), &PathFollow3D::is_cubic_interpolation_enabled);
+ ClassDB::bind_method(D_METHOD("set_z_forward", "enabled"), &PathFollow3D::set_z_forward);
+ ClassDB::bind_method(D_METHOD("is_z_forward"), &PathFollow3D::is_z_forward);
+
ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow3D::set_loop);
ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow3D::has_loop);
@@ -347,6 +353,7 @@ void PathFollow3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_v_offset", "get_v_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "z_forward"), "set_z_forward", "is_z_forward");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interpolation_enabled"), "set_cubic_interpolation_enabled", "is_cubic_interpolation_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tilt_enabled"), "set_tilt_enabled", "is_tilt_enabled");
@@ -429,6 +436,14 @@ PathFollow3D::RotationMode PathFollow3D::get_rotation_mode() const {
return rotation_mode;
}
+void PathFollow3D::set_z_forward(bool p_enabled) {
+ z_forward = p_enabled;
+}
+
+bool PathFollow3D::is_z_forward() const {
+ return z_forward;
+}
+
void PathFollow3D::set_loop(bool p_loop) {
loop = p_loop;
}
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index 43e8423927f0..d4a313612ba5 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -72,6 +72,8 @@ class PathFollow3D : public Node3D {
ROTATION_ORIENTED
};
+ bool z_forward = false;
+
static Transform3D correct_posture(Transform3D p_transform, PathFollow3D::RotationMode p_rotation_mode);
private:
@@ -118,6 +120,9 @@ class PathFollow3D : public Node3D {
void set_rotation_mode(RotationMode p_rotation_mode);
RotationMode get_rotation_mode() const;
+ void set_z_forward(bool p_enabled);
+ bool is_z_forward() const;
+
void set_cubic_interpolation_enabled(bool p_enabled);
bool is_cubic_interpolation_enabled() const;