Browse Source

Fix broken root motion scale and refactor API

Silc Renew 2 years ago
parent
commit
09adf5f20e

+ 60 - 4
doc/classes/AnimationTree.xml

@@ -19,10 +19,66 @@
 				Manually advance the animations by the specified time (in seconds).
 				Manually advance the animations by the specified time (in seconds).
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="get_root_motion_transform" qualifiers="const">
-			<return type="Transform3D" />
+		<method name="get_root_motion_position" qualifiers="const">
+			<return type="Vector3" />
 			<description>
 			<description>
-				Retrieve the motion of the [member root_motion_track] as a [Transform3D] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_SCALE_3D] or [constant Animation.TYPE_ROTATION_3D], returns an identity transformation. See also [member root_motion_track] and [RootMotionView].
+				Retrieve the motion of position with the [member root_motion_track] as a [Vector3] that can be used elsewhere.
+				If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_POSITION_3D], returns [code]Vector3(0, 0, 0)[/code].
+				See also [member root_motion_track] and [RootMotionView].
+				The most basic example is applying position to [CharacterBody3D]:
+				[codeblocks]
+				[gdscript]
+				var current_rotation: Quaternion
+
+				func _process(delta):
+				    if Input.is_action_just_pressed("animate"):
+				        current_rotation = get_quaternion()
+				        state_machine.travel("Animate")
+				    var velocity: Vector3 = current_rotation * animation_tree.get_root_motion_position() / delta
+				    set_velocity(velocity)
+				    move_and_slide()
+				[/gdscript]
+				[/codeblocks]
+			</description>
+		</method>
+		<method name="get_root_motion_rotation" qualifiers="const">
+			<return type="Quaternion" />
+			<description>
+				Retrieve the motion of rotation with the [member root_motion_track] as a [Quaternion] that can be used elsewhere.
+				If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_ROTATION_3D], returns [code]Quaternion(0, 0, 0, 1)[/code].
+				See also [member root_motion_track] and [RootMotionView].
+				The most basic example is applying rotation to [CharacterBody3D]:
+				[codeblocks]
+				[gdscript]
+				func _process(delta):
+				    if Input.is_action_just_pressed("animate"):
+				        state_machine.travel("Animate")
+				    set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
+				[/gdscript]
+				[/codeblocks]
+			</description>
+		</method>
+		<method name="get_root_motion_scale" qualifiers="const">
+			<return type="Vector3" />
+			<description>
+				Retrieve the motion of scale with the [member root_motion_track] as a [Vector3] that can be used elsewhere.
+				If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_SCALE_3D], returns [code]Vector3(0, 0, 0)[/code].
+				See also [member root_motion_track] and [RootMotionView].
+				The most basic example is applying scale to [CharacterBody3D]:
+				[codeblocks]
+				[gdscript]
+				var current_scale: Vector3 = Vector3(1, 1, 1)
+				var scale_accum: Vector3 = Vector3(1, 1, 1)
+
+				func _process(delta):
+				    if Input.is_action_just_pressed("animate"):
+				        current_scale = get_scale()
+				        scale_accum = Vector3(1, 1, 1)
+				        state_machine.travel("Animate")
+				    scale_accum += animation_tree.get_root_motion_scale()
+				    set_scale(current_scale * scale_accum)
+				[/gdscript]
+				[/codeblocks]
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="rename_parameter">
 		<method name="rename_parameter">
@@ -48,7 +104,7 @@
 		</member>
 		</member>
 		<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
 		<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
 			The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code].
 			The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code].
-			If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be cancelled visually, and the animation will appear to stay in place. See also [method get_root_motion_transform] and [RootMotionView].
+			If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D] or [constant Animation.TYPE_SCALE_3D] the transformation will be cancelled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale] and [RootMotionView].
 		</member>
 		</member>
 		<member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root">
 		<member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root">
 			The root animation node of this [AnimationTree]. See [AnimationNode].
 			The root animation node of this [AnimationTree]. See [AnimationNode].

+ 20 - 10
scene/animation/animation_tree.cpp

@@ -874,7 +874,9 @@ void AnimationTree::_process_graph(double p_delta) {
 	_update_properties(); //if properties need updating, update them
 	_update_properties(); //if properties need updating, update them
 
 
 	//check all tracks, see if they need modification
 	//check all tracks, see if they need modification
-	root_motion_transform = Transform3D();
+	root_motion_position = Vector3(0, 0, 0);
+	root_motion_rotation = Quaternion(0, 0, 0, 1);
+	root_motion_scale = Vector3(0, 0, 0);
 
 
 	if (!root.is_valid()) {
 	if (!root.is_valid()) {
 		ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback.");
 		ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback.");
@@ -973,7 +975,7 @@ void AnimationTree::_process_graph(double p_delta) {
 					if (track->root_motion) {
 					if (track->root_motion) {
 						t->loc = Vector3(0, 0, 0);
 						t->loc = Vector3(0, 0, 0);
 						t->rot = Quaternion(0, 0, 0, 1);
 						t->rot = Quaternion(0, 0, 0, 1);
-						t->scale = Vector3(0, 0, 0);
+						t->scale = Vector3(1, 1, 1);
 					} else {
 					} else {
 						t->loc = t->init_loc;
 						t->loc = t->init_loc;
 						t->rot = t->init_rot;
 						t->rot = t->init_rot;
@@ -1618,11 +1620,9 @@ void AnimationTree::_process_graph(double p_delta) {
 					TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
 					TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
 
 
 					if (t->root_motion) {
 					if (t->root_motion) {
-						Transform3D xform;
-						xform.origin = t->loc;
-						xform.basis.set_quaternion_scale(t->rot, Vector3(1, 1, 1) + t->scale);
-
-						root_motion_transform = xform;
+						root_motion_position = root_motion_rotation.xform_inv(t->loc);
+						root_motion_rotation = t->rot;
+						root_motion_scale = t->scale - Vector3(1, 1, 1);
 
 
 					} else if (t->skeleton && t->bone_idx >= 0) {
 					} else if (t->skeleton && t->bone_idx >= 0) {
 						if (t->loc_used) {
 						if (t->loc_used) {
@@ -1835,8 +1835,16 @@ NodePath AnimationTree::get_root_motion_track() const {
 	return root_motion_track;
 	return root_motion_track;
 }
 }
 
 
-Transform3D AnimationTree::get_root_motion_transform() const {
-	return root_motion_transform;
+Vector3 AnimationTree::get_root_motion_position() const {
+	return root_motion_position;
+}
+
+Quaternion AnimationTree::get_root_motion_rotation() const {
+	return root_motion_rotation;
+}
+
+Vector3 AnimationTree::get_root_motion_scale() const {
+	return root_motion_scale;
 }
 }
 
 
 void AnimationTree::_tree_changed() {
 void AnimationTree::_tree_changed() {
@@ -1994,7 +2002,9 @@ void AnimationTree::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationTree::set_root_motion_track);
 	ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationTree::set_root_motion_track);
 	ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationTree::get_root_motion_track);
 	ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationTree::get_root_motion_track);
 
 
-	ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform);
+	ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationTree::get_root_motion_position);
+	ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationTree::get_root_motion_rotation);
+	ClassDB::bind_method(D_METHOD("get_root_motion_scale"), &AnimationTree::get_root_motion_scale);
 
 
 	ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
 	ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
 
 

+ 6 - 2
scene/animation/animation_tree.h

@@ -294,7 +294,9 @@ private:
 	bool started = true;
 	bool started = true;
 
 
 	NodePath root_motion_track;
 	NodePath root_motion_track;
-	Transform3D root_motion_transform;
+	Vector3 root_motion_position = Vector3(0, 0, 0);
+	Quaternion root_motion_rotation = Quaternion(0, 0, 0, 1);
+	Vector3 root_motion_scale = Vector3(0, 0, 0);
 
 
 	friend class AnimationNode;
 	friend class AnimationNode;
 	bool properties_dirty = true;
 	bool properties_dirty = true;
@@ -350,7 +352,9 @@ public:
 	void set_root_motion_track(const NodePath &p_track);
 	void set_root_motion_track(const NodePath &p_track);
 	NodePath get_root_motion_track() const;
 	NodePath get_root_motion_track() const;
 
 
-	Transform3D get_root_motion_transform() const;
+	Vector3 get_root_motion_position() const;
+	Quaternion get_root_motion_rotation() const;
+	Vector3 get_root_motion_scale() const;
 
 
 	real_t get_connection_activity(const StringName &p_path, int p_connection) const;
 	real_t get_connection_activity(const StringName &p_path, int p_connection) const;
 	void advance(double p_time);
 	void advance(double p_time);

+ 4 - 4
scene/animation/root_motion_view.cpp

@@ -103,7 +103,8 @@ void RootMotionView::_notification(int p_what) {
 						set_physics_process_internal(false);
 						set_physics_process_internal(false);
 					}
 					}
 
 
-					transform = tree->get_root_motion_transform();
+					transform.origin = tree->get_root_motion_position();
+					transform.basis = tree->get_root_motion_rotation(); // Scale is meaningless.
 				}
 				}
 			}
 			}
 
 
@@ -113,9 +114,8 @@ void RootMotionView::_notification(int p_what) {
 
 
 			first = false;
 			first = false;
 
 
-			transform.orthonormalize(); //don't want scale, too imprecise
-
-			accumulated = accumulated * transform;
+			accumulated.origin += transform.origin;
+			accumulated.basis *= transform.basis;
 			accumulated.origin.x = Math::fposmod(accumulated.origin.x, cell_size);
 			accumulated.origin.x = Math::fposmod(accumulated.origin.x, cell_size);
 			if (zero_y) {
 			if (zero_y) {
 				accumulated.origin.y = 0;
 				accumulated.origin.y = 0;