Skip to content

Commit

Permalink
Merge pull request godotengine#69199 from TokageItLab/fix-and-refacto…
Browse files Browse the repository at this point in the history
…r-root-motion

Fix broken root motion scale & Refactor API & Add sample codes in documentation
  • Loading branch information
akien-mga committed Nov 28, 2022
2 parents df4e80e + 09adf5f commit bb9cd40
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 20 deletions.
64 changes: 60 additions & 4 deletions doc/classes/AnimationTree.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,66 @@
Manually advance the animations by the specified time (in seconds).
</description>
</method>
<method name="get_root_motion_transform" qualifiers="const">
<return type="Transform3D" />
<method name="get_root_motion_position" qualifiers="const">
<return type="Vector3" />
<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>
</method>
<method name="rename_parameter">
Expand All @@ -48,7 +104,7 @@
</member>
<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].
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 name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root">
The root animation node of this [AnimationTree]. See [AnimationNode].
Expand Down
30 changes: 20 additions & 10 deletions scene/animation/animation_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,9 @@ void AnimationTree::_process_graph(double p_delta) {
_update_properties(); //if properties need updating, update them

//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()) {
ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback.");
Expand Down Expand Up @@ -982,7 +984,7 @@ void AnimationTree::_process_graph(double p_delta) {
if (track->root_motion) {
t->loc = Vector3(0, 0, 0);
t->rot = Quaternion(0, 0, 0, 1);
t->scale = Vector3(0, 0, 0);
t->scale = Vector3(1, 1, 1);
} else {
t->loc = t->init_loc;
t->rot = t->init_rot;
Expand Down Expand Up @@ -1627,11 +1629,9 @@ void AnimationTree::_process_graph(double p_delta) {
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);

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) {
if (t->loc_used) {
Expand Down Expand Up @@ -1844,8 +1844,16 @@ NodePath AnimationTree::get_root_motion_track() const {
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() {
Expand Down Expand Up @@ -2003,7 +2011,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("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);

Expand Down
8 changes: 6 additions & 2 deletions scene/animation/animation_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,9 @@ class AnimationTree : public Node {
bool started = true;

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;
bool properties_dirty = true;
Expand Down Expand Up @@ -350,7 +352,9 @@ class AnimationTree : public Node {
void set_root_motion_track(const NodePath &p_track);
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;
void advance(double p_time);
Expand Down
8 changes: 4 additions & 4 deletions scene/animation/root_motion_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ void RootMotionView::_notification(int p_what) {
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.
}
}

Expand All @@ -113,9 +114,8 @@ void RootMotionView::_notification(int p_what) {

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);
if (zero_y) {
accumulated.origin.y = 0;
Expand Down

0 comments on commit bb9cd40

Please sign in to comment.