Backported: "Remove animation 3D transform track, replace by loc/rot/scale tracks" from Godot4.

ec19ed3723
Its a bit broken right now, more patches need to be ported. Also I kept the Transform track for now, and I did not touch the gltf module yet.
This commit is contained in:
Relintai 2022-08-08 23:49:18 +02:00
parent d89dc61436
commit 8fd473f685
23 changed files with 2140 additions and 531 deletions

View File

@ -240,6 +240,14 @@
Returns the arguments values to be called on a method track for a given key in a given track. Returns the arguments values to be called on a method track for a given key in a given track.
</description> </description>
</method> </method>
<method name="position_track_insert_key">
<return type="int" />
<argument index="0" name="track_idx" type="int" />
<argument index="1" name="time" type="float" />
<argument index="2" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="remove_track"> <method name="remove_track">
<return type="void" /> <return type="void" />
<argument index="0" name="track_idx" type="int" /> <argument index="0" name="track_idx" type="int" />
@ -247,6 +255,22 @@
Removes a track by specifying the track index. Removes a track by specifying the track index.
</description> </description>
</method> </method>
<method name="rotation_track_insert_key">
<return type="int" />
<argument index="0" name="track_idx" type="int" />
<argument index="1" name="time" type="float" />
<argument index="2" name="rotation" type="Quaternion" />
<description>
</description>
</method>
<method name="scale_track_insert_key">
<return type="int" />
<argument index="0" name="track_idx" type="int" />
<argument index="1" name="time" type="float" />
<argument index="2" name="scale" type="Vector3" />
<description>
</description>
</method>
<method name="track_find_key" qualifiers="const"> <method name="track_find_key" qualifiers="const">
<return type="int" /> <return type="int" />
<argument index="0" name="track_idx" type="int" /> <argument index="0" name="track_idx" type="int" />
@ -531,16 +555,22 @@
<constant name="TYPE_TRANSFORM" value="1" enum="TrackType"> <constant name="TYPE_TRANSFORM" value="1" enum="TrackType">
Transform tracks are used to change node local transforms or skeleton pose bones. Transitions are interpolated. Transform tracks are used to change node local transforms or skeleton pose bones. Transitions are interpolated.
</constant> </constant>
<constant name="TYPE_METHOD" value="2" enum="TrackType"> <constant name="TYPE_POSITION_3D" value="2" enum="TrackType">
</constant>
<constant name="TYPE_ROTATION_3D" value="3" enum="TrackType">
</constant>
<constant name="TYPE_SCALE_3D" value="4" enum="TrackType">
</constant>
<constant name="TYPE_METHOD" value="5" enum="TrackType">
Method tracks call functions with given arguments per key. Method tracks call functions with given arguments per key.
</constant> </constant>
<constant name="TYPE_BEZIER" value="3" enum="TrackType"> <constant name="TYPE_BEZIER" value="6" enum="TrackType">
Bezier tracks are used to interpolate a value using custom curves. They can also be used to animate sub-properties of vectors and colors (e.g. alpha value of a [Color]). Bezier tracks are used to interpolate a value using custom curves. They can also be used to animate sub-properties of vectors and colors (e.g. alpha value of a [Color]).
</constant> </constant>
<constant name="TYPE_AUDIO" value="4" enum="TrackType"> <constant name="TYPE_AUDIO" value="7" enum="TrackType">
Audio tracks are used to play an audio stream with either type of [AudioStreamPlayer]. The stream can be trimmed and previewed in the animation. Audio tracks are used to play an audio stream with either type of [AudioStreamPlayer]. The stream can be trimmed and previewed in the animation.
</constant> </constant>
<constant name="TYPE_ANIMATION" value="5" enum="TrackType"> <constant name="TYPE_ANIMATION" value="8" enum="TrackType">
Animation tracks play animations in other [AnimationPlayer] nodes. Animation tracks play animations in other [AnimationPlayer] nodes.
</constant> </constant>
<constant name="INTERPOLATION_NEAREST" value="0" enum="InterpolationType"> <constant name="INTERPOLATION_NEAREST" value="0" enum="InterpolationType">

View File

@ -22,7 +22,7 @@
<method name="get_root_motion_transform" qualifiers="const"> <method name="get_root_motion_transform" qualifiers="const">
<return type="Transform" /> <return type="Transform" />
<description> <description>
Retrieve the motion of the [member root_motion_track] as a [Transform] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_TRANSFORM], returns an identity transformation. See also [member root_motion_track] and [RootMotionView]. Retrieve the motion of the [member root_motion_track] as a [Transform] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_TRANSFORM], [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].
</description> </description>
</method> </method>
<method name="rename_parameter"> <method name="rename_parameter">
@ -45,7 +45,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_TRANSFORM], 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_TRANSFORM], [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].
</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].

View File

@ -95,6 +95,24 @@
Returns the pose transform of the specified bone. Pose is applied on top of the custom pose, which is applied on top the rest pose. Returns the pose transform of the specified bone. Pose is applied on top of the custom pose, which is applied on top the rest pose.
</description> </description>
</method> </method>
<method name="get_bone_pose_position" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="bone_idx" type="int" />
<description>
</description>
</method>
<method name="get_bone_pose_rotation" qualifiers="const">
<return type="Quaternion" />
<argument index="0" name="bone_idx" type="int" />
<description>
</description>
</method>
<method name="get_bone_pose_scale" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="bone_idx" type="int" />
<description>
</description>
</method>
<method name="get_bone_rest" qualifiers="const"> <method name="get_bone_rest" qualifiers="const">
<return type="Transform" /> <return type="Transform" />
<argument index="0" name="bone_idx" type="int" /> <argument index="0" name="bone_idx" type="int" />
@ -198,8 +216,31 @@
<return type="void" /> <return type="void" />
<argument index="0" name="bone_idx" type="int" /> <argument index="0" name="bone_idx" type="int" />
<argument index="1" name="pose" type="Transform" /> <argument index="1" name="pose" type="Transform" />
<description>
Sets the pose transform for bone [code]bone_idx[/code]. Prefer set_bone_pose_position, set_bone_pose_rotation, or set_bone_pose_scale instead.
</description>
</method>
<method name="set_bone_pose_position">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
<argument index="1" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="set_bone_pose_rotation">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
<argument index="1" name="rotation" type="Quaternion" />
<description>
</description>
</method>
<method name="set_bone_pose_scale">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
<argument index="1" name="scale" type="Vector3" />
<description> <description>
Sets the pose transform for bone [code]bone_idx[/code]. Sets the pose transform for bone [code]bone_idx[/code].
[b]Note:[/b] The pose transform needs to be in bone space. Use [method world_transform_to_global_pose] to convert a world transform, like one you can get from a [Node3D], to bone space.
</description> </description>
</method> </method>
<method name="set_bone_rest"> <method name="set_bone_rest">

View File

@ -31,16 +31,6 @@
#include "animation_track_editor.h" #include "animation_track_editor.h"
#include "animation_track_editor_plugins.h" #include "animation_track_editor_plugins.h"
#include "core/os/input.h"
#include "core/os/keyboard.h"
#include "editor/animation_bezier_editor.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor_node.h"
#include "editor_scale.h"
#include "scene/3d/spatial.h"
#include "scene/main/node.h"
#include "scene/main/viewport.h"
#include "servers/audio/audio_stream.h"
#include "core/array.h" #include "core/array.h"
#include "core/class_db.h" #include "core/class_db.h"
#include "core/color.h" #include "core/color.h"
@ -52,7 +42,9 @@
#include "core/math/transform.h" #include "core/math/transform.h"
#include "core/math/transform_2d.h" #include "core/math/transform_2d.h"
#include "core/math/vector3.h" #include "core/math/vector3.h"
#include "core/os/input.h"
#include "core/os/input_event.h" #include "core/os/input_event.h"
#include "core/os/keyboard.h"
#include "core/os/memory.h" #include "core/os/memory.h"
#include "core/pair.h" #include "core/pair.h"
#include "core/resource.h" #include "core/resource.h"
@ -61,13 +53,18 @@
#include "core/string_name.h" #include "core/string_name.h"
#include "core/typedefs.h" #include "core/typedefs.h"
#include "core/undo_redo.h" #include "core/undo_redo.h"
#include "editor/animation_bezier_editor.h"
#include "editor/editor_data.h" #include "editor/editor_data.h"
#include "editor/editor_inspector.h" #include "editor/editor_inspector.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "editor/editor_spin_slider.h" #include "editor/editor_spin_slider.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/property_selector.h" #include "editor/property_selector.h"
#include "editor/scene_tree_editor.h" #include "editor/scene_tree_editor.h"
#include "editor_node.h"
#include "editor_scale.h"
#include "scene/2d/canvas_item.h" #include "scene/2d/canvas_item.h"
#include "scene/3d/spatial.h"
#include "scene/animation/animation_player.h" #include "scene/animation/animation_player.h"
#include "scene/gui/button.h" #include "scene/gui/button.h"
#include "scene/gui/check_box.h" #include "scene/gui/check_box.h"
@ -87,9 +84,12 @@
#include "scene/gui/texture_rect.h" #include "scene/gui/texture_rect.h"
#include "scene/gui/tool_button.h" #include "scene/gui/tool_button.h"
#include "scene/gui/tree.h" #include "scene/gui/tree.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h" #include "scene/main/scene_tree.h"
#include "scene/main/viewport.h"
#include "scene/resources/font.h" #include "scene/resources/font.h"
#include "scene/resources/style_box.h" #include "scene/resources/style_box.h"
#include "servers/audio/audio_stream.h"
class AnimationTrackKeyEdit : public Object { class AnimationTrackKeyEdit : public Object {
GDCLASS(AnimationTrackKeyEdit, Object); GDCLASS(AnimationTrackKeyEdit, Object);
@ -230,6 +230,40 @@ public:
setting = false; setting = false;
return true; return true;
} break; } break;
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D: {
if (name == "position" || name == "rotation" || name == "scale") {
Variant old = animation->track_get_key_value(track, key);
setting = true;
String chan;
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D:
chan = "Position3D";
break;
case Animation::TYPE_ROTATION_3D:
chan = "Rotation3D";
break;
case Animation::TYPE_SCALE_3D:
chan = "Scale3D";
break;
default: {
}
}
undo_redo->create_action(vformat(TTR("Anim Change %s"), chan));
undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
undo_redo->add_do_method(this, "_update_obj", animation);
undo_redo->add_undo_method(this, "_update_obj", animation);
undo_redo->commit_action();
setting = false;
return true;
}
} break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
if (name == "value") { if (name == "value") {
Variant value = p_value; Variant value = p_value;
@ -469,6 +503,14 @@ public:
return true; return true;
} break; } break;
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D: {
if (name == "position" || name == "rotation" || name == "scale") {
r_ret = animation->track_get_key_value(track, key);
return true;
}
} break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
if (name == "value") { if (name == "value") {
r_ret = animation->track_get_key_value(track, key); r_ret = animation->track_get_key_value(track, key);
@ -578,6 +620,18 @@ public:
p_list->push_back(PropertyInfo(Variant::QUAT, "rotation")); p_list->push_back(PropertyInfo(Variant::QUAT, "rotation"));
p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale")); p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
} break;
case Animation::TYPE_POSITION_3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "position"));
} break;
case Animation::TYPE_ROTATION_3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "rotation"));
} break;
case Animation::TYPE_SCALE_3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
} break; } break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
Variant v = animation->track_get_key_value(track, key); Variant v = animation->track_get_key_value(track, key);
@ -853,6 +907,33 @@ public:
undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old); undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
update_obj = true; update_obj = true;
} break; } break;
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D: {
Variant old = animation->track_get_key_value(track, key);
if (!setting) {
String chan;
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D:
chan = "Position3D";
break;
case Animation::TYPE_ROTATION_3D:
chan = "Rotation3D";
break;
case Animation::TYPE_SCALE_3D:
chan = "Scale3D";
break;
default: {
}
}
setting = true;
undo_redo->create_action(vformat(TTR("Anim Multi Change %s"), chan));
}
undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
update_obj = true;
} break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
if (name == "value") { if (name == "value") {
Variant value = p_value; Variant value = p_value;
@ -1077,6 +1158,15 @@ public:
r_ret = d[p_name]; r_ret = d[p_name];
return true; return true;
} break;
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D: {
if (name == "position" || name == "rotation" || name == "scale") {
r_ret = animation->track_get_key_value(track, key);
return true;
}
} break; } break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
if (name == "value") { if (name == "value") {
@ -1226,6 +1316,15 @@ public:
p_list->push_back(PropertyInfo(Variant::QUAT, "rotation")); p_list->push_back(PropertyInfo(Variant::QUAT, "rotation"));
p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale")); p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
} break; } break;
case Animation::TYPE_POSITION_3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "position"));
} break;
case Animation::TYPE_ROTATION_3D: {
p_list->push_back(PropertyInfo(Variant::QUAT, "scale"));
} break;
case Animation::TYPE_SCALE_3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
} break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
if (same_key_type) { if (same_key_type) {
Variant v = animation->track_get_key_value(first_track, first_key); Variant v = animation->track_get_key_value(first_track, first_key);
@ -1429,6 +1528,9 @@ void AnimationTimelineEdit::_notification(int p_what) {
add_track->get_popup()->clear(); add_track->get_popup()->clear();
add_track->get_popup()->add_icon_item(get_icon("KeyValue", "EditorIcons"), TTR("Property Track")); add_track->get_popup()->add_icon_item(get_icon("KeyValue", "EditorIcons"), TTR("Property Track"));
add_track->get_popup()->add_icon_item(get_icon("KeyXform", "EditorIcons"), TTR("3D Transform Track")); add_track->get_popup()->add_icon_item(get_icon("KeyXform", "EditorIcons"), TTR("3D Transform Track"));
add_track->get_popup()->add_icon_item(get_icon("KeyXPosition", "EditorIcons"), TTR("3D Position Track"));
add_track->get_popup()->add_icon_item(get_icon("KeyXRotation", "EditorIcons"), TTR("3D Rotation Track"));
add_track->get_popup()->add_icon_item(get_icon("KeyXScale", "EditorIcons"), TTR("3D Scale Track"));
add_track->get_popup()->add_icon_item(get_icon("KeyCall", "EditorIcons"), TTR("Call Method Track")); add_track->get_popup()->add_icon_item(get_icon("KeyCall", "EditorIcons"), TTR("Call Method Track"));
add_track->get_popup()->add_icon_item(get_icon("KeyBezier", "EditorIcons"), TTR("Bezier Curve Track")); add_track->get_popup()->add_icon_item(get_icon("KeyBezier", "EditorIcons"), TTR("Bezier Curve Track"));
add_track->get_popup()->add_icon_item(get_icon("KeyAudio", "EditorIcons"), TTR("Audio Playback Track")); add_track->get_popup()->add_icon_item(get_icon("KeyAudio", "EditorIcons"), TTR("Audio Playback Track"));
@ -2106,9 +2208,12 @@ void AnimationTrackEdit::_notification(int p_what) {
interp_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2; interp_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
interp_mode_rect.size = icon->get_size(); interp_mode_rect.size = icon->get_size();
if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) { Animation::TrackType track_type = animation->track_get_type(track);
if (track_type == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM || track_type == Animation::TYPE_POSITION_3D || track_type == Animation::TYPE_SCALE_3D || track_type == Animation::TYPE_ROTATION_3D) {
draw_texture(icon, interp_mode_rect.position); draw_texture(icon, interp_mode_rect.position);
} }
//make it easier to click //make it easier to click
interp_mode_rect.position.y = 0; interp_mode_rect.position.y = 0;
interp_mode_rect.size.y = get_size().height; interp_mode_rect.size.y = get_size().height;
@ -2116,7 +2221,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep; ofs += icon->get_width() + hsep;
interp_mode_rect.size.x += hsep; interp_mode_rect.size.x += hsep;
if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) { if (track_type == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM || track_type == Animation::TYPE_POSITION_3D || track_type == Animation::TYPE_SCALE_3D || track_type == Animation::TYPE_ROTATION_3D) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
interp_mode_rect.size.x += down_icon->get_width(); interp_mode_rect.size.x += down_icon->get_width();
} else { } else {
@ -2139,7 +2244,9 @@ void AnimationTrackEdit::_notification(int p_what) {
loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2; loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
loop_mode_rect.size = icon->get_size(); loop_mode_rect.size = icon->get_size();
if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) { Animation::TrackType track_type = animation->track_get_type(track);
if (track_type == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM || track_type == Animation::TYPE_POSITION_3D || track_type == Animation::TYPE_SCALE_3D || track_type == Animation::TYPE_ROTATION_3D) {
draw_texture(icon, loop_mode_rect.position); draw_texture(icon, loop_mode_rect.position);
} }
@ -2149,7 +2256,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep; ofs += icon->get_width() + hsep;
loop_mode_rect.size.x += hsep; loop_mode_rect.size.x += hsep;
if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) { if (track_type == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM || track_type == Animation::TYPE_POSITION_3D || track_type == Animation::TYPE_SCALE_3D || track_type == Animation::TYPE_ROTATION_3D) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
loop_mode_rect.size.x += down_icon->get_width(); loop_mode_rect.size.x += down_icon->get_width();
} else { } else {
@ -2478,9 +2585,12 @@ bool AnimationTrackEdit::_is_value_key_valid(const Variant &p_key_value, Variant
} }
Ref<Texture> AnimationTrackEdit::_get_key_type_icon() const { Ref<Texture> AnimationTrackEdit::_get_key_type_icon() const {
Ref<Texture> type_icons[6] = { Ref<Texture> type_icons[9] = {
get_icon("KeyValue", "EditorIcons"), get_icon("KeyValue", "EditorIcons"),
get_icon("KeyXform", "EditorIcons"), get_icon("KeyXform", "EditorIcons"),
get_icon("KeyXPosition", "EditorIcons"),
get_icon("KeyXRotation", "EditorIcons"),
get_icon("KeyXScale", "EditorIcons"),
get_icon("KeyCall", "EditorIcons"), get_icon("KeyCall", "EditorIcons"),
get_icon("KeyBezier", "EditorIcons"), get_icon("KeyBezier", "EditorIcons"),
get_icon("KeyAudio", "EditorIcons"), get_icon("KeyAudio", "EditorIcons"),
@ -2560,6 +2670,18 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
text += "Scale: " + String(d["scale"]) + "\n"; text += "Scale: " + String(d["scale"]) + "\n";
} }
} break; } break;
case Animation::TYPE_POSITION_3D: {
Vector3 t = animation->track_get_key_value(track, key_idx);
text += TTR("Position:") + " " + String(t) + "\n";
} break;
case Animation::TYPE_ROTATION_3D: {
Quat t = animation->track_get_key_value(track, key_idx);
text += TTR("Rotation:") + " " + String(t) + "\n";
} break;
case Animation::TYPE_SCALE_3D: {
Vector3 t = animation->track_get_key_value(track, key_idx);
text += TTR("Scale:") + " " + String(t) + "\n";
} break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
const Variant &v = animation->track_get_key_value(track, key_idx); const Variant &v = animation->track_get_key_value(track, key_idx);
text += "Type: " + Variant::get_type_name(v.get_type()) + "\n"; text += "Type: " + Variant::get_type_name(v.get_type()) + "\n";
@ -3419,6 +3541,9 @@ static bool track_type_is_resettable(Animation::TrackType p_type) {
case Animation::TYPE_VALUE: case Animation::TYPE_VALUE:
case Animation::TYPE_BEZIER: case Animation::TYPE_BEZIER:
case Animation::TYPE_TRANSFORM: case Animation::TYPE_TRANSFORM:
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D:
return true; return true;
default: default:
return false; return false;
@ -3584,34 +3709,53 @@ void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p
NodePath np = path; NodePath np = path;
int track_idx = -1; int position_idx = -1;
int rotation_idx = -1;
int scale_idx = -1;
for (int i = 0; i < animation->get_track_count(); i++) { for (int i = 0; i < animation->get_track_count(); i++) {
if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM) {
continue;
}
if (animation->track_get_path(i) != np) { if (animation->track_get_path(i) != np) {
continue; continue;
} }
track_idx = i; if (animation->track_get_type(i) == Animation::TYPE_POSITION_3D) {
break; position_idx = i;
}
if (animation->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
rotation_idx = i;
}
if (animation->track_get_type(i) == Animation::TYPE_SCALE_3D) {
scale_idx = i;
}
} }
InsertData id; InsertData id;
Dictionary val;
id.path = np; id.path = np;
id.track_idx = track_idx;
id.value = p_xform;
id.type = Animation::TYPE_TRANSFORM;
// TRANSLATORS: This describes the target of new animation track, will be inserted into another string. // TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
id.query = vformat(TTR("node '%s'"), p_node->get_name()); id.query = vformat(TTR("node '%s'"), p_node->get_name());
id.advance = false; id.advance = false;
//dialog insert //dialog insert
_query_insert(id); {
id.track_idx = position_idx;
id.value = p_xform.origin;
id.type = Animation::TYPE_POSITION_3D;
_query_insert(id);
}
{
id.track_idx = rotation_idx;
id.value = p_xform.basis.get_rotation_quat();
id.type = Animation::TYPE_ROTATION_3D;
_query_insert(id);
}
{
id.track_idx = scale_idx;
id.value = p_xform.basis.get_scale();
id.type = Animation::TYPE_SCALE_3D;
_query_insert(id);
}
} }
void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant &p_value) { void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant &p_value) {
@ -4063,6 +4207,12 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
d["rotation"] = Quat(tr.basis); d["rotation"] = Quat(tr.basis);
value = d; value = d;
} break; } break;
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D: {
value = p_id.value;
} break;
case Animation::TYPE_BEZIER: { case Animation::TYPE_BEZIER: {
Array array; Array array;
array.resize(5); array.resize(5);
@ -4479,8 +4629,8 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
ERR_FAIL_COND(!node); ERR_FAIL_COND(!node);
NodePath path_to = root->get_path_to(node); NodePath path_to = root->get_path_to(node);
if (adding_track_type == Animation::TYPE_TRANSFORM && !node->is_class("Spatial")) { if ((adding_track_type == Animation::TYPE_TRANSFORM || adding_track_type == Animation::TYPE_POSITION_3D || adding_track_type == Animation::TYPE_ROTATION_3D || adding_track_type == Animation::TYPE_SCALE_3D) && !node->is_class("Spatial")) {
EditorNode::get_singleton()->show_warning(TTR("Transform tracks only apply to Spatial-based nodes.")); EditorNode::get_singleton()->show_warning(TTR("Transform/Position/Rotation/Scale 3D tracks only apply to Spatial-based nodes."));
return; return;
} }
@ -4491,6 +4641,9 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
prop_selector->select_property_from_instance(node); prop_selector->select_property_from_instance(node);
} break; } break;
case Animation::TYPE_TRANSFORM: case Animation::TYPE_TRANSFORM:
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D:
case Animation::TYPE_METHOD: { case Animation::TYPE_METHOD: {
undo_redo->create_action(TTR("Add Track")); undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
@ -4683,6 +4836,66 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
undo_redo->commit_action(); undo_redo->commit_action();
} break;
case Animation::TYPE_POSITION_3D: {
if (!root->has_node(animation->track_get_path(p_track))) {
EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key."));
return;
}
Spatial *base = Object::cast_to<Spatial>(root->get_node(animation->track_get_path(p_track)));
if (!base) {
EditorNode::get_singleton()->show_warning(TTR("Track is not of type Spatial, can't insert key"));
return;
}
Vector3 pos = base->get_translation();
undo_redo->create_action(TTR("Add Position Key"));
undo_redo->add_do_method(animation.ptr(), "position_track_insert_key", p_track, p_ofs, pos);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
case Animation::TYPE_ROTATION_3D: {
if (!root->has_node(animation->track_get_path(p_track))) {
EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key."));
return;
}
Spatial *base = Object::cast_to<Spatial>(root->get_node(animation->track_get_path(p_track)));
if (!base) {
EditorNode::get_singleton()->show_warning(TTR("Track is not of type Spatial, can't insert key"));
return;
}
Quat rot = base->get_transform().basis.operator Quat();
undo_redo->create_action(TTR("Add Rotation Key"));
undo_redo->add_do_method(animation.ptr(), "rotation_track_insert_key", p_track, p_ofs, rot);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
case Animation::TYPE_SCALE_3D: {
if (!root->has_node(animation->track_get_path(p_track))) {
EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key."));
return;
}
Spatial *base = Object::cast_to<Spatial>(root->get_node(animation->track_get_path(p_track)));
if (!base) {
EditorNode::get_singleton()->show_warning(TTR("Track is not of type Spatial, can't insert key"));
return;
}
Vector3 scale = base->get_scale();
undo_redo->create_action(TTR("Add Scale Key"));
undo_redo->add_do_method(animation.ptr(), "scale_track_insert_key", p_track, p_ofs, scale);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break; } break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
NodePath bp; NodePath bp;
@ -5365,6 +5578,15 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
case Animation::TYPE_TRANSFORM: case Animation::TYPE_TRANSFORM:
track_type = TTR("Transform"); track_type = TTR("Transform");
break; break;
case Animation::TYPE_POSITION_3D:
track_type += TTR("Position");
break;
case Animation::TYPE_ROTATION_3D:
track_type += TTR("Rotation");
break;
case Animation::TYPE_SCALE_3D:
track_type += TTR("Scale");
break;
case Animation::TYPE_METHOD: case Animation::TYPE_METHOD:
track_type = TTR("Methods"); track_type = TTR("Methods");
break; break;

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><ellipse cx="-.88987" cy="6.095995" fill="none" rx="1.249577" ry="1.086747"/><path d="m4.949661.60426977a.6444116.6444116 0 0 0 -.445508.1875179l-1.288694 1.28869423.911171.9111713.83314-.8331408.833141.8331408.911172-.9111713-1.288695-1.28869423a.6444116.6444116 0 0 0 -.465644-.1875179zm-3.02289 2.76489363-1.288694 1.2886943a.6444116.6444116 0 0 0 0 .9111713l1.288694 1.2886943.911171-.9111713-.833141-.8331409.833141-.8331409-.911171-.9111713zm6.065948 0-.911171.9111713.83314.8331409-.83314.8331408.911171.9111714 1.288694-1.2886944a.6444116.6444116 0 0 0 0-.9111713l-1.288694-1.2886943zm-3.032942.4555727a1.2886943 1.2886943 0 0 0 -1.288694 1.2886944 1.2886943 1.2886943 0 0 0 1.288694 1.2886943 1.2886943 1.2886943 0 0 0 1.288694-1.2886943 1.2886943 1.2886943 0 0 0 -1.288694-1.2886944zm-.83314 3.4105296-.911172.9111715 1.288694 1.288694a.6444116.6444116 0 0 0 .911171 0l1.288695-1.288694-.911172-.9111715-.833141.8331405-.83314-.8331405z" fill="#ea7940" stroke-width=".644347"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><ellipse cx="-.88987" cy="6.095995" fill="none" rx="1.249577" ry="1.086747"/><path d="m5.0711986.88214062a4.1086779 4.1086779 0 0 0 -.178839.00115 4.1086779 4.1086779 0 0 0 -.409265.033245 4.1086779 4.1086779 0 0 0 -3.49308098 3.27179898 4.1086779 4.1086779 0 0 0 1.15670998 3.7360798h-.648877v1.1739077h2.347816a.58701268.58701268 0 0 0 .569756-.729119l-.586953-2.3478164-1.139514.2854534.165082.6580347a2.9347699 2.9347699 0 0 1 -.769204-1.9752178 2.9347699 2.9347699 0 0 1 2.93477-2.93477 2.9347699 2.9347699 0 0 1 2.93477 2.93477 2.9347699 2.9347699 0 0 1 -.860944 2.0738257l.831127.8311266a4.1086779 4.1086779 0 0 0 .779534-4.7219857 4.1086779 4.1086779 0 0 0 -3.632953-2.29047068zm-.05159 2.93359608a1.173908 1.173908 0 0 0 -1.173907 1.173908 1.173908 1.173908 0 0 0 1.173907 1.173908 1.173908 1.173908 0 0 0 1.173909-1.173908 1.173908 1.173908 0 0 0 -1.173909-1.173908z" fill="#ff2b88" stroke-width=".586954"/></svg>

After

Width:  |  Height:  |  Size: 1007 B

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><ellipse cx="-.88987" cy="6.095995" fill="none" rx="1.249577" ry="1.086747"/><path d="m5.5742494.94786723a.58774585.58774585 0 0 0 -.5877458.58774577.58774585.58774585 0 0 0 .5877458.5877459h1.519852l-.7599554.7599553.8311314.8311314.7599554-.7599553v1.5198519a.58774585.58774585 0 0 0 .5877459.5877459.58774585.58774585 0 0 0 .5877458-.5877459v-2.9387292a.58780462.58780462 0 0 0 -.5877458-.58774577zm-.5877458 2.93872917a1.1754917 1.1754917 0 0 0 -1.1754917 1.1754917 1.1754917 1.1754917 0 0 0 1.1754917 1.1754917 1.1754917 1.1754917 0 0 0 1.1754917-1.1754917 1.1754917 1.1754917 0 0 0 -1.1754917-1.1754917zm-3.5264751 1.1754917a.58774585.58774585 0 0 0 -.5877459.5877458v2.9387299a.58780462.58780462 0 0 0 .5877459.5877454h2.9387292a.58774585.58774585 0 0 0 .5877459-.5877454.58774585.58774585 0 0 0 -.5877459-.5877465h-1.519852l.7599554-.7599554-.8311314-.8311314-.7599554.7599554v-1.519852a.58774585.58774585 0 0 0 -.5877458-.5877458z" fill="#eac840" stroke-width=".587745"/></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#ea7940" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 0 -1042.4)" width="6.1027" x="-740.13947" y="741.10779"/></svg>

After

Width:  |  Height:  |  Size: 255 B

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#ff2b88" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 .000003 -1042.399994)" width="6.103" x="-740.13947" y="741.10779"/></svg>

After

Width:  |  Height:  |  Size: 265 B

View File

@ -0,0 +1 @@
<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><rect fill="#eac840" height="6.1027" ry=".76286" transform="matrix(.70710678 -.70710678 .70710678 .70710678 .000003 -1042.399994)" width="6.103" x="-740.13947" y="741.10779"/></svg>

After

Width:  |  Height:  |  Size: 265 B

View File

@ -31,6 +31,7 @@
#include "resource_importer_scene.h" #include "resource_importer_scene.h"
#include "core/io/resource_saver.h" #include "core/io/resource_saver.h"
#include "core/os/dir_access.h"
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "scene/3d/collision_shape.h" #include "scene/3d/collision_shape.h"
#include "scene/3d/mesh_instance.h" #include "scene/3d/mesh_instance.h"
@ -41,16 +42,14 @@
#include "scene/animation/animation_player.h" #include "scene/animation/animation_player.h"
#include "scene/resources/animation.h" #include "scene/resources/animation.h"
#include "scene/resources/box_shape.h" #include "scene/resources/box_shape.h"
#include "scene/resources/mesh.h"
#include "scene/resources/navigation_mesh.h" #include "scene/resources/navigation_mesh.h"
#include "scene/resources/packed_scene.h" #include "scene/resources/packed_scene.h"
#include "scene/resources/plane_shape.h" #include "scene/resources/plane_shape.h"
#include "scene/resources/ray_shape.h" #include "scene/resources/ray_shape.h"
#include "scene/resources/resource_format_text.h" #include "scene/resources/resource_format_text.h"
#include "scene/resources/sphere_shape.h"
#include "scene/resources/animation.h"
#include "scene/resources/mesh.h"
#include "scene/resources/shape.h" #include "scene/resources/shape.h"
#include "core/os/dir_access.h" #include "scene/resources/sphere_shape.h"
uint32_t EditorSceneImporter::get_import_flags() const { uint32_t EditorSceneImporter::get_import_flags() const {
if (get_script_instance()) { if (get_script_instance()) {
@ -681,8 +680,19 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
Vector3 s; Vector3 s;
default_anim->transform_track_interpolate(j, from, &p, &q, &s); default_anim->transform_track_interpolate(j, from, &p, &q, &s);
new_anim->transform_track_insert_key(dtrack, 0, p, q, s); new_anim->transform_track_insert_key(dtrack, 0, p, q, s);
} } else if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) { Vector3 p;
default_anim->position_track_interpolate(j, from, &p);
new_anim->position_track_insert_key(dtrack, 0, p);
} else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
Quat r;
default_anim->rotation_track_interpolate(j, from, &r);
new_anim->rotation_track_insert_key(dtrack, 0, r);
} else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
default_anim->scale_track_interpolate(j, from, &s);
new_anim->scale_track_insert_key(dtrack, 0, s);
} else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
Variant var = default_anim->value_track_interpolate(j, from); Variant var = default_anim->value_track_interpolate(j, from);
new_anim->track_insert_key(dtrack, 0, var); new_anim->track_insert_key(dtrack, 0, var);
} }
@ -695,8 +705,19 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
Vector3 s; Vector3 s;
default_anim->transform_track_get_key(j, k, &p, &q, &s); default_anim->transform_track_get_key(j, k, &p, &q, &s);
new_anim->transform_track_insert_key(dtrack, kt - from, p, q, s); new_anim->transform_track_insert_key(dtrack, kt - from, p, q, s);
} } else if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) { Vector3 p;
default_anim->position_track_get_key(j, k, &p);
new_anim->position_track_insert_key(dtrack, kt - from, p);
} else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
Quat r;
default_anim->rotation_track_get_key(j, k, &r);
new_anim->rotation_track_insert_key(dtrack, kt - from, r);
} else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
default_anim->scale_track_get_key(j, k, &s);
new_anim->scale_track_insert_key(dtrack, kt - from, s);
} else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
Variant var = default_anim->track_get_key_value(j, k); Variant var = default_anim->track_get_key_value(j, k);
new_anim->track_insert_key(dtrack, kt - from, var); new_anim->track_insert_key(dtrack, kt - from, var);
} }
@ -709,8 +730,19 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
Vector3 s; Vector3 s;
default_anim->transform_track_interpolate(j, to, &p, &q, &s); default_anim->transform_track_interpolate(j, to, &p, &q, &s);
new_anim->transform_track_insert_key(dtrack, to - from, p, q, s); new_anim->transform_track_insert_key(dtrack, to - from, p, q, s);
} } else if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) { Vector3 p;
default_anim->position_track_interpolate(j, to, &p);
new_anim->position_track_insert_key(dtrack, to - from, p);
} else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
Quat r;
default_anim->rotation_track_interpolate(j, to, &r);
new_anim->rotation_track_insert_key(dtrack, to - from, r);
} else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
default_anim->scale_track_interpolate(j, to, &s);
new_anim->scale_track_insert_key(dtrack, to - from, s);
} else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
Variant var = default_anim->value_track_interpolate(j, to); Variant var = default_anim->value_track_interpolate(j, to);
new_anim->track_insert_key(dtrack, to - from, var); new_anim->track_insert_key(dtrack, to - from, var);
} }
@ -729,8 +761,25 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
new_anim->transform_track_insert_key(dtrack, 0, p, q, s); new_anim->transform_track_insert_key(dtrack, 0, p, q, s);
default_anim->transform_track_interpolate(j, to, &p, &q, &s); default_anim->transform_track_interpolate(j, to, &p, &q, &s);
new_anim->transform_track_insert_key(dtrack, to - from, p, q, s); new_anim->transform_track_insert_key(dtrack, to - from, p, q, s);
} } else if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) { Vector3 p;
default_anim->position_track_interpolate(j, from, &p);
new_anim->position_track_insert_key(dtrack, 0, p);
default_anim->position_track_interpolate(j, to, &p);
new_anim->position_track_insert_key(dtrack, to - from, p);
} else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
Quat r;
default_anim->rotation_track_interpolate(j, from, &r);
new_anim->rotation_track_insert_key(dtrack, 0, r);
default_anim->rotation_track_interpolate(j, to, &r);
new_anim->rotation_track_insert_key(dtrack, to - from, r);
} else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
default_anim->scale_track_interpolate(j, from, &s);
new_anim->scale_track_insert_key(dtrack, 0, s);
default_anim->scale_track_interpolate(j, to, &s);
new_anim->scale_track_insert_key(dtrack, to - from, s);
} else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
Variant var = default_anim->value_track_interpolate(j, from); Variant var = default_anim->value_track_interpolate(j, from);
new_anim->track_insert_key(dtrack, 0, var); new_anim->track_insert_key(dtrack, 0, var);
Variant to_var = default_anim->value_track_interpolate(j, to); Variant to_var = default_anim->value_track_interpolate(j, to);
@ -1130,6 +1179,11 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_angular_error"), 0.01)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_angular_error"), 0.01));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_angle"), 22)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_angle"), 22));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/remove_unused_tracks"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/remove_unused_tracks"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/position", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Always,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/rotation", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Always,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/scale", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Always,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clips/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/clips/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/clip_" + itos(i + 1) + "/name"), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/clip_" + itos(i + 1) + "/name"), ""));

View File

@ -67,6 +67,13 @@ public:
}; };
enum AnimationImportBoneTracks {
ANIMATION_IMPORT_BONE_TRACKS_IF_PRESENT,
ANIMATION_IMPORT_BONE_TRACKS_IF_PRESENT_FOR_ALL,
ANIMATION_IMPORT_BONE_TRACKS_ALWAYS,
ANIMATION_IMPORT_BONE_TRACKS_NEVER,
};
virtual uint32_t get_import_flags() const; virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const; virtual void get_extensions(List<String> *r_extensions) const;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, uint32_t p_compress_flags, List<String> *r_missing_deps, Error *r_err = nullptr); virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, uint32_t p_compress_flags, List<String> *r_missing_deps, Error *r_err = nullptr);

View File

@ -1395,6 +1395,9 @@ bool ModuleSkeletonEditor::forward_spatial_gui_input(int p_index, Camera *p_came
skeleton->set_bone_rest(skeleton->get_selected_bone(), t); skeleton->set_bone_rest(skeleton->get_selected_bone(), t);
} else { } else {
skeleton->set_bone_pose(skeleton->get_selected_bone(), t); skeleton->set_bone_pose(skeleton->get_selected_bone(), t);
//skeleton->set_bone_pose_position(p_id, t.origin);
//skeleton->set_bone_pose_rotation(p_id, t.basis.operator Quaternion());
//skeleton->set_bone_pose_scale(p_id, t.basis.get_scale());
} }
sev->update_surface(); sev->update_surface();

View File

@ -95,6 +95,12 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
set_bone_enabled(which, p_value); set_bone_enabled(which, p_value);
} else if (what == "pose") { } else if (what == "pose") {
set_bone_pose(which, p_value); set_bone_pose(which, p_value);
} else if (what == "position") {
set_bone_pose_position(which, p_value);
} else if (what == "rotation") {
set_bone_pose_rotation(which, p_value);
} else if (what == "scale") {
set_bone_pose_scale(which, p_value);
} else if (what == "bound_children") { } else if (what == "bound_children") {
Array children = p_value; Array children = p_value;
@ -138,6 +144,12 @@ bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const {
r_ret = is_bone_enabled(which); r_ret = is_bone_enabled(which);
} else if (what == "pose") { } else if (what == "pose") {
r_ret = get_bone_pose(which); r_ret = get_bone_pose(which);
} else if (what == "position") {
r_ret = get_bone_pose_position(which);
} else if (what == "rotation") {
r_ret = get_bone_pose_rotation(which);
} else if (what == "scale") {
r_ret = get_bone_pose_scale(which);
} else if (what == "bound_children") { } else if (what == "bound_children") {
Array children; Array children;
@ -165,6 +177,9 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest")); p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled")); p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::QUAT, prep + "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children")); p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children"));
} }
} }
@ -239,7 +254,8 @@ void Skeleton::_notification(int p_what) {
if (b.disable_rest) { if (b.disable_rest) {
if (b.enabled) { if (b.enabled) {
Transform pose = b.pose; b.update_pose_cache();
Transform pose = b.pose_cache;
if (b.custom_pose_enable) { if (b.custom_pose_enable) {
pose = b.custom_pose * pose; pose = b.custom_pose * pose;
} }
@ -261,7 +277,8 @@ void Skeleton::_notification(int p_what) {
} }
} else { } else {
if (b.enabled) { if (b.enabled) {
Transform pose = b.pose; b.update_pose_cache();
Transform pose = b.pose_cache;
if (b.custom_pose_enable) { if (b.custom_pose_enable) {
pose = b.custom_pose * pose; pose = b.custom_pose * pose;
} }
@ -561,16 +578,75 @@ void Skeleton::clear_bones() {
// posing api // posing api
void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) { void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) {
ERR_FAIL_INDEX(p_bone, bones.size()); const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].pose_position = p_pose.origin;
bones.write[p_bone].pose_rotation = p_pose.basis.operator Quat();
bones.write[p_bone].pose_scale = p_pose.basis.get_scale();
bones.write[p_bone].pose_cache_dirty = true;
bones.write[p_bone].pose = p_pose;
if (is_inside_tree()) { if (is_inside_tree()) {
_make_dirty(); _make_dirty();
} }
} }
void Skeleton::set_bone_pose_position(int p_bone, const Vector3 &p_position) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].pose_position = p_position;
bones.write[p_bone].pose_cache_dirty = true;
if (is_inside_tree()) {
_make_dirty();
}
}
void Skeleton::set_bone_pose_rotation(int p_bone, const Quat &p_rotation) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].pose_rotation = p_rotation;
bones.write[p_bone].pose_cache_dirty = true;
if (is_inside_tree()) {
_make_dirty();
}
}
void Skeleton::set_bone_pose_scale(int p_bone, const Vector3 &p_scale) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].pose_scale = p_scale;
bones.write[p_bone].pose_cache_dirty = true;
if (is_inside_tree()) {
_make_dirty();
}
}
Transform Skeleton::get_bone_pose(int p_bone) const { Transform Skeleton::get_bone_pose(int p_bone) const {
ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); const int bone_size = bones.size();
return bones[p_bone].pose; ERR_FAIL_INDEX_V(p_bone, bone_size, Transform());
((Skeleton *)this)->bones.write[p_bone].update_pose_cache();
return bones[p_bone].pose_cache;
}
Vector3 Skeleton::get_bone_pose_position(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3());
return bones[p_bone].pose_position;
}
Quat Skeleton::get_bone_pose_rotation(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Quat());
return bones[p_bone].pose_rotation;
}
Vector3 Skeleton::get_bone_pose_scale(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3());
return bones[p_bone].pose_scale;
} }
void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) { void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) {
@ -925,8 +1001,15 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton::clear_bones); ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton::clear_bones);
ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton::get_bone_pose);
ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton::set_bone_pose); ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton::set_bone_pose);
ClassDB::bind_method(D_METHOD("set_bone_pose_position", "bone_idx", "position"), &Skeleton::set_bone_pose_position);
ClassDB::bind_method(D_METHOD("set_bone_pose_rotation", "bone_idx", "rotation"), &Skeleton::set_bone_pose_rotation);
ClassDB::bind_method(D_METHOD("set_bone_pose_scale", "bone_idx", "scale"), &Skeleton::set_bone_pose_scale);
ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton::get_bone_pose);
ClassDB::bind_method(D_METHOD("get_bone_pose_position", "bone_idx"), &Skeleton::get_bone_pose_position);
ClassDB::bind_method(D_METHOD("get_bone_pose_rotation", "bone_idx"), &Skeleton::get_bone_pose_rotation);
ClassDB::bind_method(D_METHOD("get_bone_pose_scale", "bone_idx"), &Skeleton::get_bone_pose_scale);
ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton::clear_bones_global_pose_override); ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton::clear_bones_global_pose_override);
ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false));

View File

@ -86,7 +86,21 @@ private:
bool disable_rest; bool disable_rest;
Transform rest; Transform rest;
Transform pose; //Transform pose;
_FORCE_INLINE_ void update_pose_cache() {
if (pose_cache_dirty) {
pose_cache.basis.set_quat_scale(pose_rotation, pose_scale);
pose_cache.origin = pose_position;
pose_cache_dirty = false;
}
}
bool pose_cache_dirty = true;
Transform pose_cache;
Vector3 pose_position;
Quat pose_rotation;
Vector3 pose_scale = Vector3(1, 1, 1);
Transform pose_global; Transform pose_global;
Transform pose_global_no_override; Transform pose_global_no_override;
@ -192,7 +206,14 @@ public:
// posing api // posing api
void set_bone_pose(int p_bone, const Transform &p_pose); void set_bone_pose(int p_bone, const Transform &p_pose);
void set_bone_pose_position(int p_bone, const Vector3 &p_position);
void set_bone_pose_rotation(int p_bone, const Quat &p_rotation);
void set_bone_pose_scale(int p_bone, const Vector3 &p_scale);
Transform get_bone_pose(int p_bone) const; Transform get_bone_pose(int p_bone) const;
Vector3 get_bone_pose_position(int p_bone) const;
Quat get_bone_pose_rotation(int p_bone) const;
Vector3 get_bone_pose_scale(int p_bone) const;
void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose); void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose);
Transform get_bone_custom_pose(int p_bone) const; Transform get_bone_custom_pose(int p_bone) const;

View File

@ -1,319 +0,0 @@
/*************************************************************************/
/* animation_cache.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "animation_cache.h"
#include "scene/3d/skeleton.h"
#include "scene/resources/animation.h"
void AnimationCache::_node_exit_tree(Node *p_node) {
//it is one shot, so it disconnects upon arrival
ERR_FAIL_COND(!connected_nodes.has(p_node));
connected_nodes.erase(p_node);
for (int i = 0; i < path_cache.size(); i++) {
if (path_cache[i].node != p_node) {
continue;
}
path_cache.write[i].valid = false; //invalidate path cache
}
}
void AnimationCache::_animation_changed() {
_clear_cache();
}
void AnimationCache::_clear_cache() {
while (connected_nodes.size()) {
connected_nodes.front()->get()->disconnect("tree_exiting", this, "_node_exit_tree");
connected_nodes.erase(connected_nodes.front());
}
path_cache.clear();
cache_valid = false;
cache_dirty = true;
}
void AnimationCache::_update_cache() {
cache_valid = false;
ERR_FAIL_COND(!root);
ERR_FAIL_COND(!root->is_inside_tree());
ERR_FAIL_COND(animation.is_null());
for (int i = 0; i < animation->get_track_count(); i++) {
NodePath np = animation->track_get_path(i);
Node *node = root->get_node(np);
if (!node) {
path_cache.push_back(Path());
ERR_CONTINUE_MSG(!node, "Invalid track path in animation '" + np + "'.");
}
Path path;
Ref<Resource> res;
if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM) {
if (np.get_subname_count() > 1) {
path_cache.push_back(Path());
ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM, "Transform tracks can't have a subpath '" + np + "'.");
}
Spatial *sp = Object::cast_to<Spatial>(node);
if (!sp) {
path_cache.push_back(Path());
ERR_CONTINUE_MSG(!sp, "Transform track not of type Spatial '" + np + "'.");
}
if (np.get_subname_count() == 1) {
StringName property = np.get_subname(0);
String ps = property;
Skeleton *sk = Object::cast_to<Skeleton>(node);
if (!sk) {
path_cache.push_back(Path());
ERR_CONTINUE_MSG(!sk, "Property defined in Transform track, but not a Skeleton! '" + np + "'.");
}
int idx = sk->find_bone(ps);
if (idx == -1) {
path_cache.push_back(Path());
ERR_CONTINUE_MSG(idx == -1, "Property defined in Transform track, but not a Skeleton Bone! '" + np + "'.");
}
path.bone_idx = idx;
path.skeleton = sk;
}
path.spatial = sp;
} else {
if (np.get_subname_count() > 0) {
RES res2;
Vector<StringName> leftover_subpath;
// We don't want to cache the last resource unless it is a method call
bool is_method = animation->track_get_type(i) == Animation::TYPE_METHOD;
root->get_node_and_resource(np, res2, leftover_subpath, is_method);
if (res2.is_valid()) {
path.resource = res2;
} else {
path.node = node;
}
path.object = res2.is_valid() ? res2.ptr() : (Object *)node;
path.subpath = leftover_subpath;
} else {
path.node = node;
path.object = node;
path.subpath = np.get_subnames();
}
}
if (animation->track_get_type(i) == Animation::TYPE_VALUE) {
if (np.get_subname_count() == 0) {
path_cache.push_back(Path());
ERR_CONTINUE_MSG(np.get_subname_count() == 0, "Value Track lacks property: " + np + ".");
}
} else if (animation->track_get_type(i) == Animation::TYPE_METHOD) {
if (path.subpath.size() != 0) { // Trying to call a method of a non-resource
path_cache.push_back(Path());
ERR_CONTINUE_MSG(path.subpath.size() != 0, "Method Track has property: " + np + ".");
}
}
path.valid = true;
path_cache.push_back(path);
if (!connected_nodes.has(path.node)) {
connected_nodes.insert(path.node);
path.node->connect("tree_exiting", this, "_node_exit_tree", Node::make_binds(path.node), CONNECT_ONESHOT);
}
}
cache_dirty = false;
cache_valid = true;
}
void AnimationCache::set_track_transform(int p_idx, const Transform &p_transform) {
if (cache_dirty) {
_update_cache();
}
ERR_FAIL_COND(!cache_valid);
ERR_FAIL_INDEX(p_idx, path_cache.size());
Path &p = path_cache.write[p_idx];
if (!p.valid) {
return;
}
ERR_FAIL_COND(!p.node);
ERR_FAIL_COND(!p.spatial);
if (p.skeleton) {
p.skeleton->set_bone_pose(p.bone_idx, p_transform);
} else {
p.spatial->set_transform(p_transform);
}
}
void AnimationCache::set_track_value(int p_idx, const Variant &p_value) {
if (cache_dirty) {
_update_cache();
}
ERR_FAIL_COND(!cache_valid);
ERR_FAIL_INDEX(p_idx, path_cache.size());
Path &p = path_cache.write[p_idx];
if (!p.valid) {
return;
}
ERR_FAIL_COND(!p.object);
p.object->set_indexed(p.subpath, p_value);
}
void AnimationCache::call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
if (cache_dirty) {
_update_cache();
}
ERR_FAIL_COND(!cache_valid);
ERR_FAIL_INDEX(p_idx, path_cache.size());
Path &p = path_cache.write[p_idx];
if (!p.valid) {
return;
}
ERR_FAIL_COND(!p.object);
p.object->call(p_method, p_args, p_argcount, r_error);
}
void AnimationCache::set_all(float p_time, float p_delta) {
if (cache_dirty) {
_update_cache();
}
ERR_FAIL_COND(!cache_valid);
int tc = animation->get_track_count();
for (int i = 0; i < tc; i++) {
switch (animation->track_get_type(i)) {
case Animation::TYPE_TRANSFORM: {
Vector3 loc, scale;
Quat rot;
animation->transform_track_interpolate(i, p_time, &loc, &rot, &scale);
Transform tr(Basis(rot), loc);
tr.basis.scale(scale);
set_track_transform(i, tr);
} break;
case Animation::TYPE_VALUE: {
if (animation->value_track_get_update_mode(i) == Animation::UPDATE_CONTINUOUS || (animation->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE && p_delta == 0)) {
Variant v = animation->value_track_interpolate(i, p_time);
set_track_value(i, v);
} else {
List<int> indices;
animation->value_track_get_key_indices(i, p_time, p_delta, &indices);
for (List<int>::Element *E = indices.front(); E; E = E->next()) {
Variant v = animation->track_get_key_value(i, E->get());
set_track_value(i, v);
}
}
} break;
case Animation::TYPE_METHOD: {
List<int> indices;
animation->method_track_get_key_indices(i, p_time, p_delta, &indices);
for (List<int>::Element *E = indices.front(); E; E = E->next()) {
Vector<Variant> args = animation->method_track_get_params(i, E->get());
StringName name = animation->method_track_get_name(i, E->get());
Variant::CallError err;
if (!args.size()) {
call_track(i, name, nullptr, 0, err);
} else {
Vector<const Variant *> argptrs;
argptrs.resize(args.size());
for (int j = 0; j < args.size(); j++) {
argptrs.write[j] = &args.write[j];
}
call_track(i, name, (const Variant **)&argptrs[0], args.size(), err);
}
}
} break;
default: {
}
}
}
}
void AnimationCache::set_animation(const Ref<Animation> &p_animation) {
_clear_cache();
if (animation.is_valid()) {
animation->disconnect("changed", this, "_animation_changed");
}
animation = p_animation;
if (animation.is_valid()) {
animation->connect("changed", this, "_animation_changed");
}
}
void AnimationCache::_bind_methods() {
ClassDB::bind_method(D_METHOD("_node_exit_tree"), &AnimationCache::_node_exit_tree);
ClassDB::bind_method(D_METHOD("_animation_changed"), &AnimationCache::_animation_changed);
}
void AnimationCache::set_root(Node *p_root) {
_clear_cache();
root = p_root;
}
AnimationCache::AnimationCache() {
root = nullptr;
cache_dirty = true;
cache_valid = false;
}

View File

@ -1,95 +0,0 @@
#ifndef ANIMATION_CACHE_H
#define ANIMATION_CACHE_H
/*************************************************************************/
/* animation_cache.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/object.h"
#include "core/reference.h"
class Node;
class Spatial;
class Resource;
class Skeleton;
class Animation;
class AnimationCache : public Object {
GDCLASS(AnimationCache, Object);
struct Path {
Ref<Resource> resource;
Object *object;
Skeleton *skeleton; // haxor
Node *node;
Spatial *spatial;
int bone_idx;
Vector<StringName> subpath;
bool valid;
Path() {
object = nullptr;
skeleton = nullptr;
node = nullptr;
bone_idx = -1;
valid = false;
spatial = nullptr;
}
};
Set<Node *> connected_nodes;
Vector<Path> path_cache;
Node *root;
Ref<Animation> animation;
bool cache_dirty;
bool cache_valid;
void _node_exit_tree(Node *p_node);
void _clear_cache();
void _update_cache();
void _animation_changed();
protected:
static void _bind_methods();
public:
void set_track_transform(int p_idx, const Transform &p_transform);
void set_track_value(int p_idx, const Variant &p_value);
void call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
void set_all(float p_time, float p_delta = 0);
void set_animation(const Ref<Animation> &p_animation);
void set_root(Node *p_root);
AnimationCache();
};
#endif // ANIMATION_CACHE_H

View File

@ -65,7 +65,16 @@ void AnimatedValuesBackup::restore() const {
if (entry->bone_idx == -1) { if (entry->bone_idx == -1) {
entry->object->set_indexed(entry->subpath, entry->value); entry->object->set_indexed(entry->subpath, entry->value);
} else { } else {
Object::cast_to<Skeleton>(entry->object)->set_bone_pose(entry->bone_idx, entry->value); if (entry->value.get_type() == Variant::TRANSFORM) {
Object::cast_to<Skeleton>(entry->object)->set_bone_pose(entry->bone_idx, entry->value);
} else {
Array arr = entry->value;
if (arr.size() == 3) {
Object::cast_to<Skeleton>(entry->object)->set_bone_pose_position(entry->bone_idx, arr[0]);
Object::cast_to<Skeleton>(entry->object)->set_bone_pose_rotation(entry->bone_idx, arr[1]);
Object::cast_to<Skeleton>(entry->object)->set_bone_pose_scale(entry->bone_idx, arr[2]);
}
}
} }
} }
} }
@ -247,6 +256,8 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
p_anim->node_cache.resize(a->get_track_count()); p_anim->node_cache.resize(a->get_track_count());
setup_pass++;
for (int i = 0; i < a->get_track_count(); i++) { for (int i = 0; i < a->get_track_count(); i++) {
p_anim->node_cache.write[i] = NULL; p_anim->node_cache.write[i] = NULL;
RES resource; RES resource;
@ -278,44 +289,100 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
node_cache_map[key] = TrackNodeCache(); node_cache_map[key] = TrackNodeCache();
} }
p_anim->node_cache.write[i] = &node_cache_map[key]; TrackNodeCache *node_cache = &node_cache_map[key];
p_anim->node_cache[i]->path = a->track_get_path(i); p_anim->node_cache.write[i] = node_cache;
p_anim->node_cache[i]->node = child;
p_anim->node_cache[i]->resource = resource; node_cache->path = a->track_get_path(i);
p_anim->node_cache[i]->node_2d = Object::cast_to<Node2D>(child); node_cache->node = child;
node_cache->resource = resource;
node_cache->node_2d = Object::cast_to<Node2D>(child);
#ifndef _3D_DISABLED
if (a->track_get_type(i) == Animation::TYPE_TRANSFORM) { if (a->track_get_type(i) == Animation::TYPE_TRANSFORM) {
// special cases and caches for transform tracks // special cases and caches for transform tracks
// cache spatial // cache spatial
p_anim->node_cache[i]->spatial = Object::cast_to<Spatial>(child); node_cache->spatial = Object::cast_to<Spatial>(child);
// cache skeleton // cache skeleton
p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton>(child); node_cache->skeleton = Object::cast_to<Skeleton>(child);
if (p_anim->node_cache[i]->skeleton) { if (node_cache->skeleton) {
if (a->track_get_path(i).get_subname_count() == 1) { if (a->track_get_path(i).get_subname_count() == 1) {
StringName bone_name = a->track_get_path(i).get_subname(0); StringName bone_name = a->track_get_path(i).get_subname(0);
p_anim->node_cache[i]->bone_idx = p_anim->node_cache[i]->skeleton->find_bone(bone_name); node_cache->bone_idx = node_cache->skeleton->find_bone(bone_name);
if (p_anim->node_cache[i]->bone_idx < 0) { if (node_cache->bone_idx < 0) {
// broken track (nonexistent bone) // broken track (nonexistent bone)
p_anim->node_cache[i]->skeleton = nullptr; node_cache->skeleton = nullptr;
p_anim->node_cache[i]->spatial = nullptr; node_cache->spatial = nullptr;
ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0); ERR_CONTINUE(node_cache->bone_idx < 0);
} }
} else { } else {
// no property, just use spatialnode // no property, just use spatialnode
p_anim->node_cache[i]->skeleton = nullptr; node_cache->skeleton = nullptr;
}
}
node_cache->transform_used = true;
} else if (a->track_get_type(i) == Animation::TYPE_POSITION_3D || a->track_get_type(i) == Animation::TYPE_ROTATION_3D || a->track_get_type(i) == Animation::TYPE_SCALE_3D) {
// special cases and caches for transform tracks
if (node_cache->last_setup_pass != setup_pass) {
node_cache->loc_used = false;
node_cache->rot_used = false;
node_cache->scale_used = false;
}
// cache spatial
node_cache->spatial = Object::cast_to<Spatial>(child);
// cache skeleton
node_cache->skeleton = Object::cast_to<Skeleton>(child);
if (node_cache->skeleton) {
if (a->track_get_path(i).get_subname_count() == 1) {
StringName bone_name = a->track_get_path(i).get_subname(0);
node_cache->bone_idx = node_cache->skeleton->find_bone(bone_name);
if (node_cache->bone_idx < 0) {
// broken track (nonexistent bone)
node_cache->skeleton = nullptr;
node_cache->spatial = nullptr;
ERR_CONTINUE(node_cache->bone_idx < 0);
}
Transform rest = node_cache->skeleton->get_bone_rest(bone_idx);
node_cache->init_loc = rest.origin;
node_cache->init_rot = rest.basis.get_rotation_quat();
node_cache->init_scale = rest.basis.get_scale();
} else {
// no property, just use spatialnode
node_cache->skeleton = nullptr;
}
}
switch (a->track_get_type(i)) {
case Animation::TYPE_POSITION_3D: {
node_cache->loc_used = true;
} break;
case Animation::TYPE_ROTATION_3D: {
node_cache->rot_used = true;
} break;
case Animation::TYPE_SCALE_3D: {
node_cache->scale_used = true;
} break;
default: {
} }
} }
} }
#endif // _3D_DISABLED
if (a->track_get_type(i) == Animation::TYPE_VALUE) { if (a->track_get_type(i) == Animation::TYPE_VALUE) {
if (!p_anim->node_cache[i]->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) { if (!node_cache->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
TrackNodeCache::PropertyAnim pa; TrackNodeCache::PropertyAnim pa;
pa.subpath = leftover_path; pa.subpath = leftover_path;
pa.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child; pa.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
pa.special = SP_NONE; pa.special = SP_NONE;
pa.owner = p_anim->node_cache[i]; pa.owner = node_cache;
if (false && p_anim->node_cache[i]->node_2d) { if (false && node_cache->node_2d) {
if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_pos) { if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_pos) {
pa.special = SP_NODE2D_POS; pa.special = SP_NODE2D_POS;
} else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_rot) { } else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_rot) {
@ -324,20 +391,22 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
pa.special = SP_NODE2D_SCALE; pa.special = SP_NODE2D_SCALE;
} }
} }
p_anim->node_cache[i]->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa; node_cache->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa;
} }
} }
if (a->track_get_type(i) == Animation::TYPE_BEZIER && leftover_path.size()) { if (a->track_get_type(i) == Animation::TYPE_BEZIER && leftover_path.size()) {
if (!p_anim->node_cache[i]->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) { if (!node_cache->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) {
TrackNodeCache::BezierAnim ba; TrackNodeCache::BezierAnim ba;
ba.bezier_property = leftover_path; ba.bezier_property = leftover_path;
ba.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child; ba.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
ba.owner = p_anim->node_cache[i]; ba.owner = node_cache;
p_anim->node_cache[i]->bezier_anim[a->track_get_path(i).get_concatenated_subnames()] = ba; node_cache->bezier_anim[a->track_get_path(i).get_concatenated_subnames()] = ba;
} }
} }
node_cache->last_setup_pass = setup_pass;
} }
} }
@ -371,6 +440,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
switch (a->track_get_type(i)) { switch (a->track_get_type(i)) {
case Animation::TYPE_TRANSFORM: { case Animation::TYPE_TRANSFORM: {
#ifndef _3D_DISABLED
if (!nc->spatial) { if (!nc->spatial) {
continue; continue;
} }
@ -399,7 +469,88 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
nc->rot_accum = nc->rot_accum.slerp(rot, p_interp); nc->rot_accum = nc->rot_accum.slerp(rot, p_interp);
nc->scale_accum = nc->scale_accum.linear_interpolate(scale, p_interp); nc->scale_accum = nc->scale_accum.linear_interpolate(scale, p_interp);
} }
#endif // _3D_DISABLED
} break;
case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
if (!nc->spatial) {
continue;
}
Vector3 loc;
Error err = a->position_track_interpolate(i, p_time, &loc);
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
if (err != OK) {
continue;
}
if (nc->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
cache_update[cache_update_size++] = nc;
nc->accum_pass = accum_pass;
nc->loc_accum = loc;
nc->rot_accum = nc->init_rot;
nc->scale_accum = nc->init_scale;
} else {
nc->loc_accum = nc->loc_accum.linear_interpolate(loc, p_interp);
}
#endif // _3D_DISABLED
} break;
case Animation::TYPE_ROTATION_3D: {
#ifndef _3D_DISABLED
if (!nc->spatial) {
continue;
}
Quat rot;
Error err = a->rotation_track_interpolate(i, p_time, &rot);
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
if (err != OK) {
continue;
}
if (nc->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
cache_update[cache_update_size++] = nc;
nc->accum_pass = accum_pass;
nc->loc_accum = nc->init_loc;
nc->rot_accum = rot;
nc->scale_accum = nc->init_scale;
} else {
nc->rot_accum = nc->rot_accum.slerp(rot, p_interp);
}
#endif // _3D_DISABLED
} break;
case Animation::TYPE_SCALE_3D: {
#ifndef _3D_DISABLED
if (!nc->spatial) {
continue;
}
Vector3 scale;
Error err = a->scale_track_interpolate(i, p_time, &scale);
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
if (err != OK) {
continue;
}
if (nc->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
cache_update[cache_update_size++] = nc;
nc->accum_pass = accum_pass;
nc->loc_accum = nc->init_loc;
nc->rot_accum = nc->init_rot;
nc->scale_accum = scale;
} else {
nc->scale_accum = nc->scale_accum.linear_interpolate(scale, p_interp);
}
#endif // _3D_DISABLED
} break; } break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
if (!nc->node) { if (!nc->node) {
@ -855,14 +1006,43 @@ void AnimationPlayer::_animation_update_transforms() {
ERR_CONTINUE(nc->accum_pass != accum_pass); ERR_CONTINUE(nc->accum_pass != accum_pass);
t.origin = nc->loc_accum; #ifndef _3D_DISABLED
t.basis.set_quat_scale(nc->rot_accum, nc->scale_accum);
if (nc->skeleton && nc->bone_idx >= 0) { if (nc->skeleton && nc->bone_idx >= 0) {
nc->skeleton->set_bone_pose(nc->bone_idx, t); if (nc->transform_used) {
t.origin = nc->loc_accum;
t.basis.set_quat_scale(nc->rot_accum, nc->scale_accum);
nc->skeleton->set_bone_pose(nc->bone_idx, t);
} else {
if (nc->loc_used) {
nc->skeleton->set_bone_pose_position(nc->bone_idx, nc->loc_accum);
}
if (nc->rot_used) {
nc->skeleton->set_bone_pose_rotation(nc->bone_idx, nc->rot_accum);
}
if (nc->scale_used) {
nc->skeleton->set_bone_pose_scale(nc->bone_idx, nc->scale_accum);
}
}
} else if (nc->spatial) { } else if (nc->spatial) {
nc->spatial->set_transform(t); if (nc->transform_used) {
t.origin = nc->loc_accum;
t.basis.set_quat_scale(nc->rot_accum, nc->scale_accum);
nc->spatial->set_transform(t);
} else {
if (nc->loc_used) {
nc->spatial->set_translation(nc->loc_accum);
}
if (nc->rot_used) {
nc->spatial->set_rotation(nc->rot_accum.get_euler());
}
if (nc->scale_used) {
nc->spatial->set_scale(nc->scale_accum);
}
}
} }
#endif // _3D_DISABLED
} }
} }
@ -1537,9 +1717,20 @@ Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_o
} }
AnimatedValuesBackup::Entry entry; AnimatedValuesBackup::Entry entry;
entry.object = nc->skeleton;
entry.bone_idx = nc->bone_idx; if (nc->transform_used) {
entry.value = nc->skeleton->get_bone_pose(nc->bone_idx); entry.object = nc->skeleton;
entry.bone_idx = nc->bone_idx;
entry.value = nc->skeleton->get_bone_pose(nc->bone_idx);
} else {
Array arr;
arr.resize(3);
arr[0] = nc->skeleton->get_bone_pose_position(nc->bone_idx);
arr[1] = nc->skeleton->get_bone_pose_rotation(nc->bone_idx);
arr[2] = nc->skeleton->get_bone_pose_scale(nc->bone_idx);
entry.value = nc;
}
backup->entries.push_back(entry); backup->entries.push_back(entry);
} else { } else {
if (nc->spatial) { if (nc->spatial) {

View File

@ -93,6 +93,8 @@ private:
SP_NODE2D_SCALE, SP_NODE2D_SCALE,
}; };
uint32_t setup_pass = 1;
struct TrackNodeCache { struct TrackNodeCache {
NodePath path; NodePath path;
uint32_t id; uint32_t id;
@ -104,6 +106,14 @@ private:
int bone_idx; int bone_idx;
// accumulated transforms // accumulated transforms
bool transform_used;
bool loc_used;
bool rot_used;
bool scale_used;
Vector3 init_loc;
Quat init_rot;
Vector3 init_scale;
Vector3 loc_accum; Vector3 loc_accum;
Quat rot_accum; Quat rot_accum;
Vector3 scale_accum; Vector3 scale_accum;
@ -128,7 +138,8 @@ private:
owner(nullptr), owner(nullptr),
special(SP_NONE), special(SP_NONE),
object(nullptr), object(nullptr),
accum_pass(0) {} accum_pass(0) {
}
}; };
Map<StringName, PropertyAnim> property_anim; Map<StringName, PropertyAnim> property_anim;
@ -149,6 +160,8 @@ private:
Map<StringName, BezierAnim> bezier_anim; Map<StringName, BezierAnim> bezier_anim;
uint32_t last_setup_pass;
TrackNodeCache() : TrackNodeCache() :
id(0), id(0),
node(nullptr), node(nullptr),
@ -160,7 +173,16 @@ private:
audio_playing(false), audio_playing(false),
audio_start(0.0), audio_start(0.0),
audio_len(0.0), audio_len(0.0),
animation_playing(false) {} animation_playing(false) {
transform_used = false;
loc_used = false;
rot_used = false;
scale_used = false;
last_setup_pass = 0;
init_loc = Vector3(0, 0, 0);
init_rot = Quat(0, 0, 0, 1);
init_scale = Vector3(1, 1, 1);
}
}; };
struct TrackNodeCacheKey { struct TrackNodeCacheKey {

View File

@ -543,13 +543,18 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
NodePath path = anim->track_get_path(i); NodePath path = anim->track_get_path(i);
Animation::TrackType track_type = anim->track_get_type(i); Animation::TrackType track_type = anim->track_get_type(i);
Animation::TrackType track_cache_type = track_type;
if (track_cache_type == Animation::TYPE_ROTATION_3D || track_cache_type == Animation::TYPE_SCALE_3D) {
track_cache_type = Animation::TYPE_POSITION_3D; //reference them as position3D tracks, even if they modify rotation or scale
}
TrackCache *track = nullptr; TrackCache *track = nullptr;
if (track_cache.has(path)) { if (track_cache.has(path)) {
track = track_cache.get(path); track = track_cache.get(path);
} }
//if not valid, delete track //if not valid, delete track
if (track && (track->type != track_type || ObjectDB::get_instance(track->object_id) == nullptr)) { if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) {
playing_caches.erase(track); playing_caches.erase(track);
memdelete(track); memdelete(track);
track_cache.erase(path); track_cache.erase(path);
@ -587,6 +592,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
} break; } break;
case Animation::TYPE_TRANSFORM: { case Animation::TYPE_TRANSFORM: {
#ifndef _3D_DISABLED
Spatial *spatial = Object::cast_to<Spatial>(child); Spatial *spatial = Object::cast_to<Spatial>(child);
if (!spatial) { if (!spatial) {
@ -595,10 +601,46 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
} }
TrackCacheTransform *track_xform = memnew(TrackCacheTransform); TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
track_xform->type = Animation::TYPE_TRANSFORM;
track_xform->spatial = spatial; track_xform->spatial = spatial;
track_xform->skeleton = nullptr; track_xform->skeleton = nullptr;
track_xform->bone_idx = -1; track_xform->bone_idx = -1;
track_xform->transform_used = true;
if (path.get_subname_count() == 1 && Object::cast_to<Skeleton>(spatial)) {
Skeleton *sk = Object::cast_to<Skeleton>(spatial);
track_xform->skeleton = sk;
int bone_idx = sk->find_bone(path.get_subname(0));
if (bone_idx != -1) {
track_xform->bone_idx = bone_idx;
}
}
track_xform->object = spatial;
track_xform->object_id = track_xform->object->get_instance_id();
track = track_xform;
#endif
} break;
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D: {
#ifndef _3D_DISABLED
Spatial *spatial = Object::cast_to<Spatial>(child);
if (!spatial) {
ERR_PRINT("AnimationTree: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'");
continue;
}
TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
track_xform->type = Animation::TYPE_POSITION_3D;
track_xform->spatial = spatial;
track_xform->skeleton = nullptr;
track_xform->bone_idx = -1;
track_xform->transform_used = true;
if (path.get_subname_count() == 1 && Object::cast_to<Skeleton>(spatial)) { if (path.get_subname_count() == 1 && Object::cast_to<Skeleton>(spatial)) {
Skeleton *sk = Object::cast_to<Skeleton>(spatial); Skeleton *sk = Object::cast_to<Skeleton>(spatial);
@ -614,6 +656,21 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
track = track_xform; track = track_xform;
switch (track_type) {
case Animation::TYPE_POSITION_3D: {
track_xform->loc_used = true;
} break;
case Animation::TYPE_ROTATION_3D: {
track_xform->rot_used = true;
} break;
case Animation::TYPE_SCALE_3D: {
track_xform->scale_used = true;
} break;
default: {
}
}
#endif
} break; } break;
case Animation::TYPE_METHOD: { case Animation::TYPE_METHOD: {
TrackCacheMethod *track_method = memnew(TrackCacheMethod); TrackCacheMethod *track_method = memnew(TrackCacheMethod);
@ -668,6 +725,28 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
} }
track_cache[path] = track; track_cache[path] = track;
} else if (track_cache_type == Animation::TYPE_POSITION_3D) {
TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track);
if (track->setup_pass != setup_pass) {
track_xform->loc_used = false;
track_xform->rot_used = false;
track_xform->scale_used = false;
}
switch (track_type) {
case Animation::TYPE_POSITION_3D: {
track_xform->loc_used = true;
} break;
case Animation::TYPE_ROTATION_3D: {
track_xform->rot_used = true;
} break;
case Animation::TYPE_SCALE_3D: {
track_xform->scale_used = true;
} break;
default: {
}
}
} }
track->setup_pass = setup_pass; track->setup_pass = setup_pass;
@ -831,8 +910,11 @@ void AnimationTree::_process_graph(float p_delta) {
ERR_CONTINUE(!track_cache.has(path)); ERR_CONTINUE(!track_cache.has(path));
TrackCache *track = track_cache[path]; TrackCache *track = track_cache[path];
if (track->type != a->track_get_type(i)) {
continue; //may happen should not Animation::TrackType ttype = a->track_get_type(i);
if (ttype != Animation::TYPE_TRANSFORM && ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) {
//broken animation, but avoid error spamming
continue;
} }
track->root_motion = root_motion_track == path; track->root_motion = root_motion_track == path;
@ -850,6 +932,7 @@ void AnimationTree::_process_graph(float p_delta) {
switch (track->type) { switch (track->type) {
case Animation::TYPE_TRANSFORM: { case Animation::TYPE_TRANSFORM: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion) { if (track->root_motion) {
@ -935,7 +1018,209 @@ void AnimationTree::_process_graph(float p_delta) {
} }
t->scale = t->scale.linear_interpolate(scale, blend); t->scale = t->scale.linear_interpolate(scale, blend);
} }
#endif
} break;
case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (t->process_pass != process_pass) {
t->process_pass = process_pass;
t->loc = Vector3();
t->rot = Quat();
t->rot_blend_accum = 0;
t->scale = Vector3(1, 1, 1);
}
if (track->root_motion) {
double prev_time = time - delta;
if (prev_time < 0) {
if (!a->has_loop()) {
prev_time = 0;
} else {
prev_time = a->get_length() + prev_time;
}
}
Vector3 loc[2];
if (prev_time > time) {
Error err = a->position_track_interpolate(i, prev_time, &loc[0]);
if (err != OK) {
continue;
}
a->position_track_interpolate(i, (double)a->get_length(), &loc[1]);
t->loc += (loc[1] - loc[0]) * blend;
prev_time = 0;
}
Error err = a->position_track_interpolate(i, prev_time, &loc[0]);
if (err != OK) {
continue;
}
a->position_track_interpolate(i, time, &loc[1]);
t->loc += (loc[1] - loc[0]) * blend;
prev_time = 0;
} else {
Vector3 loc;
Error err = a->position_track_interpolate(i, time, &loc);
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
if (err != OK) {
continue;
}
t->loc = t->loc.linear_interpolate(loc, blend);
}
#endif // _3D_DISABLED
} break;
case Animation::TYPE_ROTATION_3D: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (t->process_pass != process_pass) {
t->process_pass = process_pass;
t->loc = Vector3();
t->rot = Quat();
t->rot_blend_accum = 0;
t->scale = Vector3(1, 1, 1);
}
if (track->root_motion) {
double prev_time = time - delta;
if (prev_time < 0) {
if (!a->has_loop()) {
prev_time = 0;
} else {
prev_time = a->get_length() + prev_time;
}
}
Quat rot[2];
if (prev_time > time) {
Error err = a->rotation_track_interpolate(i, prev_time, &rot[0]);
if (err != OK) {
continue;
}
a->rotation_track_interpolate(i, (double)a->get_length(), &rot[1]);
Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
t->rot = (t->rot * q).normalized();
prev_time = 0;
}
Error err = a->rotation_track_interpolate(i, prev_time, &rot[0]);
if (err != OK) {
continue;
}
a->rotation_track_interpolate(i, time, &rot[1]);
Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized();
t->rot = (t->rot * q).normalized();
prev_time = 0;
} else {
Quat rot;
Error err = a->rotation_track_interpolate(i, time, &rot);
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
if (err != OK) {
continue;
}
if (t->rot_blend_accum == 0) {
t->rot = rot;
t->rot_blend_accum = blend;
} else {
real_t rot_total = t->rot_blend_accum + blend;
t->rot = rot.slerp(t->rot, t->rot_blend_accum / rot_total).normalized();
t->rot_blend_accum = rot_total;
}
}
#endif // _3D_DISABLED
} break;
case Animation::TYPE_SCALE_3D: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (t->process_pass != process_pass) {
t->process_pass = process_pass;
t->loc = Vector3();
t->rot = Quat();
t->rot_blend_accum = 0;
t->scale = Vector3(1, 1, 1);
}
if (track->root_motion) {
double prev_time = time - delta;
if (prev_time < 0) {
if (!a->has_loop()) {
prev_time = 0;
} else {
prev_time = a->get_length() + prev_time;
}
}
Vector3 scale[2];
if (prev_time > time) {
Error err = a->scale_track_interpolate(i, prev_time, &scale[0]);
if (err != OK) {
continue;
}
a->scale_track_interpolate(i, (double)a->get_length(), &scale[1]);
t->scale += (scale[1] - scale[0]) * blend;
prev_time = 0;
}
Error err = a->scale_track_interpolate(i, prev_time, &scale[0]);
if (err != OK) {
continue;
}
a->scale_track_interpolate(i, time, &scale[1]);
t->scale += (scale[1] - scale[0]) * blend;
prev_time = 0;
} else {
Vector3 scale;
Error err = a->scale_track_interpolate(i, time, &scale);
//ERR_CONTINUE(err!=OK); //used for testing, should be removed
if (err != OK) {
continue;
}
t->scale = t->scale.linear_interpolate(scale, blend);
}
#endif // _3D_DISABLED
} break; } break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track); TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
@ -1198,6 +1483,7 @@ void AnimationTree::_process_graph(float p_delta) {
switch (track->type) { switch (track->type) {
case Animation::TYPE_TRANSFORM: { case Animation::TYPE_TRANSFORM: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
Transform xform; Transform xform;
@ -1217,7 +1503,45 @@ void AnimationTree::_process_graph(float p_delta) {
} else if (!t->skeleton) { } else if (!t->skeleton) {
t->spatial->set_transform(xform); t->spatial->set_transform(xform);
} }
#endif
} break;
case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (t->root_motion) {
Transform xform;
xform.origin = t->loc;
xform.basis.set_quat_scale(t->rot, t->scale);
root_motion_transform = xform;
if (t->skeleton && t->bone_idx >= 0) {
root_motion_transform = (t->skeleton->get_bone_rest(t->bone_idx) * root_motion_transform) * t->skeleton->get_bone_rest(t->bone_idx).affine_inverse();
}
} else if (t->skeleton && t->bone_idx >= 0) {
if (t->loc_used) {
t->skeleton->set_bone_pose_position(t->bone_idx, t->loc);
}
if (t->rot_used) {
t->skeleton->set_bone_pose_rotation(t->bone_idx, t->rot);
}
if (t->scale_used) {
t->skeleton->set_bone_pose_scale(t->bone_idx, t->scale);
}
} else if (!t->skeleton) {
if (t->loc_used) {
t->spatial->set_translation(t->loc);
}
if (t->rot_used) {
t->spatial->set_rotation(t->rot.get_euler());
}
if (t->scale_used) {
t->spatial->set_scale(t->scale);
}
}
#endif // _3D_DISABLED
} break; } break;
case Animation::TYPE_VALUE: { case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track); TrackCacheValue *t = static_cast<TrackCacheValue *>(track);

View File

@ -174,6 +174,7 @@ private:
ObjectID object_id; ObjectID object_id;
TrackCache() { TrackCache() {
type = Animation::TYPE_ANIMATION;
root_motion = false; root_motion = false;
setup_pass = 0; setup_pass = 0;
process_pass = 0; process_pass = 0;
@ -187,16 +188,24 @@ private:
Spatial *spatial; Spatial *spatial;
Skeleton *skeleton; Skeleton *skeleton;
int bone_idx; int bone_idx;
bool transform_used;
bool loc_used;
bool rot_used;
bool scale_used;
Vector3 loc; Vector3 loc;
Quat rot; Quat rot;
float rot_blend_accum; float rot_blend_accum;
Vector3 scale; Vector3 scale;
TrackCacheTransform() { TrackCacheTransform() {
type = Animation::TYPE_TRANSFORM; type = Animation::TYPE_POSITION_3D;
spatial = nullptr; spatial = nullptr;
bone_idx = -1; bone_idx = -1;
skeleton = nullptr; skeleton = nullptr;
transform_used = false;
loc_used = false;
rot_used = false;
scale_used = false;
} }
}; };

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,9 @@ public:
enum TrackType { enum TrackType {
TYPE_VALUE, ///< Set a value in a property, can be interpolated. TYPE_VALUE, ///< Set a value in a property, can be interpolated.
TYPE_TRANSFORM, ///< Transform a node or a bone. TYPE_TRANSFORM, ///< Transform a node or a bone.
TYPE_POSITION_3D, ///< Position 3D track
TYPE_ROTATION_3D, ///< Rotation 3D track
TYPE_SCALE_3D, ///< Scale 3D track
TYPE_METHOD, ///< Call any method on a specific node. TYPE_METHOD, ///< Call any method on a specific node.
TYPE_BEZIER, ///< Bezier curve TYPE_BEZIER, ///< Bezier curve
TYPE_AUDIO, TYPE_AUDIO,
@ -97,6 +100,30 @@ private:
Vector3 scale; Vector3 scale;
}; };
/* POSITION TRACK */
struct PositionTrack : public Track {
Vector<TKey<Vector3>> positions;
//int32_t compressed_track = -1;
PositionTrack() { type = TYPE_POSITION_3D; }
};
/* ROTATION TRACK */
struct RotationTrack : public Track {
Vector<TKey<Quat>> rotations;
//int32_t compressed_track = -1;
RotationTrack() { type = TYPE_ROTATION_3D; }
};
/* SCALE TRACK */
struct ScaleTrack : public Track {
Vector<TKey<Vector3>> scales;
//int32_t compressed_track = -1;
ScaleTrack() { type = TYPE_SCALE_3D; }
};
/* TRANSFORM TRACK */ /* TRANSFORM TRACK */
struct TransformTrack : public Track { struct TransformTrack : public Track {
@ -255,6 +282,14 @@ private:
bool _transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err, float p_alowed_angular_err, float p_max_optimizable_angle, const Vector3 &p_norm); bool _transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err, float p_alowed_angular_err, float p_max_optimizable_angle, const Vector3 &p_norm);
void _transform_track_optimize(int p_idx, float p_allowed_linear_err = 0.05, float p_allowed_angular_err = 0.01, float p_max_optimizable_angle = Math_PI * 0.125); void _transform_track_optimize(int p_idx, float p_allowed_linear_err = 0.05, float p_allowed_angular_err = 0.01, float p_max_optimizable_angle = Math_PI * 0.125);
bool _position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_alowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm);
bool _rotation_track_optimize_key(const TKey<Quat> &t0, const TKey<Quat> &t1, const TKey<Quat> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle);
bool _scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error);
void _position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err);
void _rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle);
void _scale_track_optimize(int p_idx, real_t p_allowed_linear_err);
protected: protected:
bool _set(const StringName &p_name, const Variant &p_value); bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const; bool _get(const StringName &p_name, Variant &r_ret) const;
@ -299,6 +334,19 @@ public:
int transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quat &p_rot = Quat(), const Vector3 &p_scale = Vector3()); int transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quat &p_rot = Quat(), const Vector3 &p_scale = Vector3());
Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const; Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const;
int position_track_insert_key(int p_track, double p_time, const Vector3 &p_position);
Error position_track_get_key(int p_track, int p_key, Vector3 *r_position) const;
Error position_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const;
int rotation_track_insert_key(int p_track, double p_time, const Quat &p_rotation);
Error rotation_track_get_key(int p_track, int p_key, Quat *r_rotation) const;
Error rotation_track_interpolate(int p_track, double p_time, Quat *r_interpolation) const;
int scale_track_insert_key(int p_track, double p_time, const Vector3 &p_scale);
Error scale_track_get_key(int p_track, int p_key, Vector3 *r_scale) const;
Error scale_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const;
void track_set_interpolation_type(int p_track, InterpolationType p_interp); void track_set_interpolation_type(int p_track, InterpolationType p_interp);
InterpolationType track_get_interpolation_type(int p_track) const; InterpolationType track_get_interpolation_type(int p_track) const;