فهرست منبع

Merge pull request #72842 from TokageItLab/fix-pathfollow

Fix Pathfollow direction and add Z forward option
Rémi Verschelde 2 سال پیش
والد
کامیت
c39c565307

+ 1 - 0
doc/classes/Basis.xml

@@ -127,6 +127,7 @@
 			<description>
 				Creates a Basis with a rotation such that the forward axis (-Z) points towards the [param target] position.
 				The up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the forward axis. The resulting Basis is orthonormalized. The [param target] and [param up] vectors cannot be zero, and cannot be parallel to each other.
+				If [param use_model_front] is [code]true[/code], the +Z axis (asset front) is treated as forward (implies +X is left) and points toward the [param target] position. By default, the -Z axis (camera forward) is treated as forward (implies +X is right).
 			</description>
 		</method>
 		<method name="orthonormalized" qualifiers="const">

+ 2 - 1
doc/classes/Node3D.xml

@@ -115,10 +115,11 @@
 			<param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
 			<param index="2" name="use_model_front" type="bool" default="false" />
 			<description>
-				Rotates the node so that the local forward axis (-Z, [constant Vector3.FORWARD]) points toward the [param target] position. If the [param use_model_front] options is specified, then the model is oriented in reverse, towards the model front axis (+Z, [constant Vector3.MODEL_FRONT]), which is more useful for orienting 3D models.
+				Rotates the node so that the local forward axis (-Z, [constant Vector3.FORWARD]) points toward the [param target] position.
 				The local up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the local forward axis. The resulting transform is orthogonal, and the scale is preserved. Non-uniform scaling may not work correctly.
 				The [param target] position cannot be the same as the node's position, the [param up] vector cannot be zero, and the direction from the node's position to the [param target] vector cannot be parallel to the [param up] vector.
 				Operations take place in global space, which means that the node must be in the scene tree.
+				If [param use_model_front] is [code]true[/code], the +Z axis (asset front) is treated as forward (implies +X is left) and points toward the [param target] position. By default, the -Z axis (camera forward) is treated as forward (implies +X is right).
 			</description>
 		</method>
 		<method name="look_at_from_position">

+ 0 - 3
doc/classes/PathFollow2D.xml

@@ -18,9 +18,6 @@
 		<member name="h_offset" type="float" setter="set_h_offset" getter="get_h_offset" default="0.0">
 			The node's offset along the curve.
 		</member>
-		<member name="lookahead" type="float" setter="set_lookahead" getter="get_lookahead" default="4.0">
-			How far to look ahead of the curve to calculate the tangent if the node is rotating. E.g. shorter lookaheads will lead to faster rotations.
-		</member>
 		<member name="loop" type="bool" setter="set_loop" getter="has_loop" default="true">
 			If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths.
 		</member>

+ 3 - 0
doc/classes/PathFollow3D.xml

@@ -43,6 +43,9 @@
 		<member name="tilt_enabled" type="bool" setter="set_tilt_enabled" getter="is_tilt_enabled" default="true">
 			If [code]true[/code], the tilt property of [Curve3D] takes effect.
 		</member>
+		<member name="use_model_front" type="bool" setter="set_use_model_front" getter="is_using_model_front" default="false">
+			If [code]true[/code], the node moves on the travel path with orienting the +Z axis as forward. See also [constant Vector3.FORWARD] and [constant Vector3.MODEL_FRONT].
+		</member>
 		<member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0">
 			The node's offset perpendicular to the curve.
 		</member>

+ 1 - 0
doc/classes/Transform3D.xml

@@ -97,6 +97,7 @@
 			<description>
 				Returns a copy of the transform rotated such that the forward axis (-Z) points towards the [param target] position.
 				The up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the forward axis. The resulting transform is orthonormalized. The existing rotation, scale, and skew information from the original transform is discarded. The [param target] and [param up] vectors cannot be zero, cannot be parallel to each other, and are defined in global/parent space.
+				If [param use_model_front] is [code]true[/code], the +Z axis (asset front) is treated as forward (implies +X is left) and points toward the [param target] position. By default, the -Z axis (camera forward) is treated as forward (implies +X is right).
 			</description>
 		</method>
 		<method name="orthonormalized" qualifiers="const">

+ 2 - 2
editor/plugins/path_3d_editor_plugin.cpp

@@ -274,10 +274,10 @@ void Path3DGizmo::redraw() {
 
 			// Fish Bone.
 			v3p.push_back(p1);
-			v3p.push_back(p1 + (side - forward + up * 0.3) * 0.06);
+			v3p.push_back(p1 + (side + forward + up * 0.3) * 0.06);
 
 			v3p.push_back(p1);
-			v3p.push_back(p1 + (-side - forward + up * 0.3) * 0.06);
+			v3p.push_back(p1 + (-side + forward + up * 0.3) * 0.06);
 		}
 
 		add_lines(v3p, path_material);

+ 10 - 22
scene/2d/path_2d.cpp

@@ -268,11 +268,11 @@ void PathFollow2D::_notification(int p_what) {
 	}
 }
 
-void PathFollow2D::set_cubic_interpolation(bool p_enable) {
-	cubic = p_enable;
+void PathFollow2D::set_cubic_interpolation_enabled(bool p_enabled) {
+	cubic = p_enabled;
 }
 
-bool PathFollow2D::get_cubic_interpolation() const {
+bool PathFollow2D::is_cubic_interpolation_enabled() const {
 	return cubic;
 }
 
@@ -312,18 +312,15 @@ void PathFollow2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_progress_ratio", "ratio"), &PathFollow2D::set_progress_ratio);
 	ClassDB::bind_method(D_METHOD("get_progress_ratio"), &PathFollow2D::get_progress_ratio);
 
-	ClassDB::bind_method(D_METHOD("set_rotates", "enable"), &PathFollow2D::set_rotates);
-	ClassDB::bind_method(D_METHOD("is_rotating"), &PathFollow2D::is_rotating);
+	ClassDB::bind_method(D_METHOD("set_rotates", "enabled"), &PathFollow2D::set_rotation_enabled);
+	ClassDB::bind_method(D_METHOD("is_rotating"), &PathFollow2D::is_rotation_enabled);
 
-	ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &PathFollow2D::set_cubic_interpolation);
-	ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &PathFollow2D::get_cubic_interpolation);
+	ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enabled"), &PathFollow2D::set_cubic_interpolation_enabled);
+	ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &PathFollow2D::is_cubic_interpolation_enabled);
 
 	ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow2D::set_loop);
 	ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow2D::has_loop);
 
-	ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead);
-	ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead);
-
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_less,or_greater,suffix:px"), "set_progress", "get_progress");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
@@ -331,7 +328,6 @@ void PathFollow2D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotates"), "set_rotates", "is_rotating");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
-	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead");
 }
 
 void PathFollow2D::set_progress(real_t p_progress) {
@@ -395,20 +391,12 @@ real_t PathFollow2D::get_progress_ratio() const {
 	}
 }
 
-void PathFollow2D::set_lookahead(real_t p_lookahead) {
-	lookahead = p_lookahead;
-}
-
-real_t PathFollow2D::get_lookahead() const {
-	return lookahead;
-}
-
-void PathFollow2D::set_rotates(bool p_rotates) {
-	rotates = p_rotates;
+void PathFollow2D::set_rotation_enabled(bool p_enabled) {
+	rotates = p_enabled;
 	_update_transform();
 }
 
-bool PathFollow2D::is_rotating() const {
+bool PathFollow2D::is_rotation_enabled() const {
 	return rotates;
 }
 

+ 4 - 8
scene/2d/path_2d.h

@@ -70,7 +70,6 @@ private:
 	Timer *update_timer = nullptr;
 	real_t h_offset = 0.0;
 	real_t v_offset = 0.0;
-	real_t lookahead = 4.0;
 	bool cubic = true;
 	bool loop = true;
 	bool rotates = true;
@@ -98,17 +97,14 @@ public:
 	void set_progress_ratio(real_t p_ratio);
 	real_t get_progress_ratio() const;
 
-	void set_lookahead(real_t p_lookahead);
-	real_t get_lookahead() const;
-
 	void set_loop(bool p_loop);
 	bool has_loop() const;
 
-	void set_rotates(bool p_rotates);
-	bool is_rotating() const;
+	void set_rotation_enabled(bool p_enabled);
+	bool is_rotation_enabled() const;
 
-	void set_cubic_interpolation(bool p_enable);
-	bool get_cubic_interpolation() const;
+	void set_cubic_interpolation_enabled(bool p_enabled);
+	bool is_cubic_interpolation_enabled() const;
 
 	PackedStringArray get_configuration_warnings() const override;
 

+ 22 - 7
scene/3d/path_3d.cpp

@@ -192,6 +192,9 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
 		t.origin = pos;
 	} else {
 		t = c->sample_baked_with_rotation(progress, cubic, false);
+		if (use_model_front) {
+			t.basis *= Basis::from_scale(Vector3(-1.0, 1.0, -1.0));
+		}
 		Vector3 forward = t.basis.get_column(2); // Retain tangent for applying tilt
 		t = PathFollow3D::correct_posture(t, rotation_mode);
 
@@ -230,11 +233,11 @@ void PathFollow3D::_notification(int p_what) {
 	}
 }
 
-void PathFollow3D::set_cubic_interpolation(bool p_enable) {
-	cubic = p_enable;
+void PathFollow3D::set_cubic_interpolation_enabled(bool p_enabled) {
+	cubic = p_enabled;
 }
 
-bool PathFollow3D::get_cubic_interpolation() const {
+bool PathFollow3D::is_cubic_interpolation_enabled() const {
 	return cubic;
 }
 
@@ -314,8 +317,11 @@ void PathFollow3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_rotation_mode", "rotation_mode"), &PathFollow3D::set_rotation_mode);
 	ClassDB::bind_method(D_METHOD("get_rotation_mode"), &PathFollow3D::get_rotation_mode);
 
-	ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &PathFollow3D::set_cubic_interpolation);
-	ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &PathFollow3D::get_cubic_interpolation);
+	ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enabled"), &PathFollow3D::set_cubic_interpolation_enabled);
+	ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &PathFollow3D::is_cubic_interpolation_enabled);
+
+	ClassDB::bind_method(D_METHOD("set_use_model_front", "enabled"), &PathFollow3D::set_use_model_front);
+	ClassDB::bind_method(D_METHOD("is_using_model_front"), &PathFollow3D::is_using_model_front);
 
 	ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow3D::set_loop);
 	ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow3D::has_loop);
@@ -330,6 +336,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, "use_model_front"), "set_use_model_front", "is_using_model_front");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tilt_enabled"), "set_tilt_enabled", "is_tilt_enabled");
@@ -412,6 +419,14 @@ PathFollow3D::RotationMode PathFollow3D::get_rotation_mode() const {
 	return rotation_mode;
 }
 
+void PathFollow3D::set_use_model_front(bool p_use_model_front) {
+	use_model_front = p_use_model_front;
+}
+
+bool PathFollow3D::is_using_model_front() const {
+	return use_model_front;
+}
+
 void PathFollow3D::set_loop(bool p_loop) {
 	loop = p_loop;
 }
@@ -420,8 +435,8 @@ bool PathFollow3D::has_loop() const {
 	return loop;
 }
 
-void PathFollow3D::set_tilt_enabled(bool p_enable) {
-	tilt_enabled = p_enable;
+void PathFollow3D::set_tilt_enabled(bool p_enabled) {
+	tilt_enabled = p_enabled;
 }
 
 bool PathFollow3D::is_tilt_enabled() const {

+ 8 - 3
scene/3d/path_3d.h

@@ -72,6 +72,8 @@ public:
 		ROTATION_ORIENTED
 	};
 
+	bool use_model_front = false;
+
 	static Transform3D correct_posture(Transform3D p_transform, PathFollow3D::RotationMode p_rotation_mode);
 
 private:
@@ -108,14 +110,17 @@ public:
 	void set_loop(bool p_loop);
 	bool has_loop() const;
 
-	void set_tilt_enabled(bool p_enable);
+	void set_tilt_enabled(bool p_enabled);
 	bool is_tilt_enabled() const;
 
 	void set_rotation_mode(RotationMode p_rotation_mode);
 	RotationMode get_rotation_mode() const;
 
-	void set_cubic_interpolation(bool p_enable);
-	bool get_cubic_interpolation() const;
+	void set_use_model_front(bool p_use_model_front);
+	bool is_using_model_front() const;
+
+	void set_cubic_interpolation_enabled(bool p_enabled);
+	bool is_cubic_interpolation_enabled() const;
 
 	PackedStringArray get_configuration_warnings() const override;
 

+ 4 - 4
scene/resources/curve.cpp

@@ -1648,9 +1648,9 @@ void Curve3D::_bake() const {
 			Vector3 forward = forward_ptr[0];
 
 			if (abs(forward.dot(Vector3(0, 1, 0))) > 1.0 - UNIT_EPSILON) {
-				frame_prev = Basis::looking_at(-forward, Vector3(1, 0, 0));
+				frame_prev = Basis::looking_at(forward, Vector3(1, 0, 0));
 			} else {
-				frame_prev = Basis::looking_at(-forward, Vector3(0, 1, 0));
+				frame_prev = Basis::looking_at(forward, Vector3(0, 1, 0));
 			}
 
 			up_write[0] = frame_prev.get_column(1);
@@ -1809,8 +1809,8 @@ Basis Curve3D::_sample_posture(Interval p_interval, bool p_apply_tilt) const {
 	}
 
 	// Build frames at both ends of the interval, then interpolate.
-	const Basis frame_begin = Basis::looking_at(-forward_begin, up_begin);
-	const Basis frame_end = Basis::looking_at(-forward_end, up_end);
+	const Basis frame_begin = Basis::looking_at(forward_begin, up_begin);
+	const Basis frame_end = Basis::looking_at(forward_end, up_end);
 	const Basis frame = frame_begin.slerp(frame_end, frac).orthonormalized();
 
 	if (!p_apply_tilt) {

+ 3 - 3
tests/scene/test_curve_3d.h

@@ -178,9 +178,9 @@ TEST_CASE("[Curve3D] Sampling") {
 	}
 
 	SUBCASE("sample_baked_with_rotation") {
-		CHECK(curve->sample_baked_with_rotation(curve->get_closest_offset(Vector3(0, 0, 0))) == Transform3D(Basis(Vector3(0, 0, 1), Vector3(1, 0, 0), Vector3(0, 1, 0)), Vector3(0, 0, 0)));
-		CHECK(curve->sample_baked_with_rotation(curve->get_closest_offset(Vector3(0, 25, 0))) == Transform3D(Basis(Vector3(0, 0, 1), Vector3(1, 0, 0), Vector3(0, 1, 0)), Vector3(0, 25, 0)));
-		CHECK(curve->sample_baked_with_rotation(curve->get_closest_offset(Vector3(0, 50, 0))) == Transform3D(Basis(Vector3(0, 0, 1), Vector3(1, 0, 0), Vector3(0, 1, 0)), Vector3(0, 50, 0)));
+		CHECK(curve->sample_baked_with_rotation(curve->get_closest_offset(Vector3(0, 0, 0))) == Transform3D(Basis(Vector3(0, 0, -1), Vector3(1, 0, 0), Vector3(0, -1, 0)), Vector3(0, 0, 0)));
+		CHECK(curve->sample_baked_with_rotation(curve->get_closest_offset(Vector3(0, 25, 0))) == Transform3D(Basis(Vector3(0, 0, -1), Vector3(1, 0, 0), Vector3(0, -1, 0)), Vector3(0, 25, 0)));
+		CHECK(curve->sample_baked_with_rotation(curve->get_closest_offset(Vector3(0, 50, 0))) == Transform3D(Basis(Vector3(0, 0, -1), Vector3(1, 0, 0), Vector3(0, -1, 0)), Vector3(0, 50, 0)));
 	}
 
 	SUBCASE("sample_baked_tilt") {