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.
</description>
</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">
<return type="void" />
<argument index="0" name="track_idx" type="int" />
@ -247,6 +255,22 @@
Removes a track by specifying the track index.
</description>
</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">
<return type="int" />
<argument index="0" name="track_idx" type="int" />
@ -531,16 +555,22 @@
<constant name="TYPE_TRANSFORM" value="1" enum="TrackType">
Transform tracks are used to change node local transforms or skeleton pose bones. Transitions are interpolated.
</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.
</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]).
</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.
</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.
</constant>
<constant name="INTERPOLATION_NEAREST" value="0" enum="InterpolationType">

View File

@ -22,7 +22,7 @@
<method name="get_root_motion_transform" qualifiers="const">
<return type="Transform" />
<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>
</method>
<method name="rename_parameter">
@ -45,7 +45,7 @@
</member>
<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code].
If the track has type [constant Animation.TYPE_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 name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root">
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.
</description>
</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">
<return type="Transform" />
<argument index="0" name="bone_idx" type="int" />
@ -198,8 +216,31 @@
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
<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>
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>
</method>
<method name="set_bone_rest">

View File

@ -31,16 +31,6 @@
#include "animation_track_editor.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/class_db.h"
#include "core/color.h"
@ -52,7 +42,9 @@
#include "core/math/transform.h"
#include "core/math/transform_2d.h"
#include "core/math/vector3.h"
#include "core/os/input.h"
#include "core/os/input_event.h"
#include "core/os/keyboard.h"
#include "core/os/memory.h"
#include "core/pair.h"
#include "core/resource.h"
@ -61,13 +53,18 @@
#include "core/string_name.h"
#include "core/typedefs.h"
#include "core/undo_redo.h"
#include "editor/animation_bezier_editor.h"
#include "editor/editor_data.h"
#include "editor/editor_inspector.h"
#include "editor/editor_settings.h"
#include "editor/editor_spin_slider.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/property_selector.h"
#include "editor/scene_tree_editor.h"
#include "editor_node.h"
#include "editor_scale.h"
#include "scene/2d/canvas_item.h"
#include "scene/3d/spatial.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/button.h"
#include "scene/gui/check_box.h"
@ -87,9 +84,12 @@
#include "scene/gui/texture_rect.h"
#include "scene/gui/tool_button.h"
#include "scene/gui/tree.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "scene/main/viewport.h"
#include "scene/resources/font.h"
#include "scene/resources/style_box.h"
#include "servers/audio/audio_stream.h"
class AnimationTrackKeyEdit : public Object {
GDCLASS(AnimationTrackKeyEdit, Object);
@ -230,6 +230,40 @@ public:
setting = false;
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") {
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: {
if (name == "value") {
Variant value = p_value;
@ -469,6 +503,14 @@ public:
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;
case Animation::TYPE_VALUE: {
if (name == "value") {
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::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;
case Animation::TYPE_VALUE: {
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);
update_obj = true;
} 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: {
if (name == "value") {
Variant value = p_value;
@ -1077,6 +1158,15 @@ public:
r_ret = d[p_name];
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;
case Animation::TYPE_VALUE: {
if (name == "value") {
@ -1226,6 +1316,15 @@ public:
p_list->push_back(PropertyInfo(Variant::QUAT, "rotation"));
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::QUAT, "scale"));
} break;
case Animation::TYPE_SCALE_3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
} break;
case Animation::TYPE_VALUE: {
if (same_key_type) {
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()->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("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("KeyBezier", "EditorIcons"), TTR("Bezier Curve 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.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);
}
//make it easier to click
interp_mode_rect.position.y = 0;
interp_mode_rect.size.y = get_size().height;
@ -2116,7 +2221,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + 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));
interp_mode_rect.size.x += down_icon->get_width();
} 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.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);
}
@ -2149,7 +2256,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + 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));
loop_mode_rect.size.x += down_icon->get_width();
} 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> type_icons[6] = {
Ref<Texture> type_icons[9] = {
get_icon("KeyValue", "EditorIcons"),
get_icon("KeyXform", "EditorIcons"),
get_icon("KeyXPosition", "EditorIcons"),
get_icon("KeyXRotation", "EditorIcons"),
get_icon("KeyXScale", "EditorIcons"),
get_icon("KeyCall", "EditorIcons"),
get_icon("KeyBezier", "EditorIcons"),
get_icon("KeyAudio", "EditorIcons"),
@ -2560,6 +2670,18 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
text += "Scale: " + String(d["scale"]) + "\n";
}
} 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: {
const Variant &v = animation->track_get_key_value(track, key_idx);
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_BEZIER:
case Animation::TYPE_TRANSFORM:
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D:
return true;
default:
return false;
@ -3584,34 +3709,53 @@ void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p
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++) {
if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM) {
continue;
}
if (animation->track_get_path(i) != np) {
continue;
}
track_idx = i;
break;
if (animation->track_get_type(i) == Animation::TYPE_POSITION_3D) {
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;
Dictionary val;
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.
id.query = vformat(TTR("node '%s'"), p_node->get_name());
id.advance = false;
//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) {
@ -4063,6 +4207,12 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
d["rotation"] = Quat(tr.basis);
value = d;
} 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: {
Array array;
array.resize(5);
@ -4479,8 +4629,8 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
ERR_FAIL_COND(!node);
NodePath path_to = root->get_path_to(node);
if (adding_track_type == Animation::TYPE_TRANSFORM && !node->is_class("Spatial")) {
EditorNode::get_singleton()->show_warning(TTR("Transform tracks only apply to Spatial-based nodes."));
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/Position/Rotation/Scale 3D tracks only apply to Spatial-based nodes."));
return;
}
@ -4491,6 +4641,9 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
prop_selector->select_property_from_instance(node);
} break;
case Animation::TYPE_TRANSFORM:
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D:
case Animation::TYPE_METHOD: {
undo_redo->create_action(TTR("Add Track"));
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->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;
case Animation::TYPE_VALUE: {
NodePath bp;
@ -5365,6 +5578,15 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
case Animation::TYPE_TRANSFORM:
track_type = TTR("Transform");
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:
track_type = TTR("Methods");
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 "core/io/resource_saver.h"
#include "core/os/dir_access.h"
#include "editor/editor_node.h"
#include "scene/3d/collision_shape.h"
#include "scene/3d/mesh_instance.h"
@ -41,16 +42,14 @@
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/resources/box_shape.h"
#include "scene/resources/mesh.h"
#include "scene/resources/navigation_mesh.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/plane_shape.h"
#include "scene/resources/ray_shape.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 "core/os/dir_access.h"
#include "scene/resources/sphere_shape.h"
uint32_t EditorSceneImporter::get_import_flags() const {
if (get_script_instance()) {
@ -681,8 +680,19 @@ void ResourceImporterScene::_create_clips(Node *scene, const Array &p_clips, boo
Vector3 s;
default_anim->transform_track_interpolate(j, from, &p, &q, &s);
new_anim->transform_track_insert_key(dtrack, 0, p, q, s);
}
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
} else if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
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);
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;
default_anim->transform_track_get_key(j, k, &p, &q, &s);
new_anim->transform_track_insert_key(dtrack, kt - from, p, q, s);
}
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
} else if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
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);
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;
default_anim->transform_track_interpolate(j, to, &p, &q, &s);
new_anim->transform_track_insert_key(dtrack, to - from, p, q, s);
}
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
} else if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
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);
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);
default_anim->transform_track_interpolate(j, to, &p, &q, &s);
new_anim->transform_track_insert_key(dtrack, to - from, p, q, s);
}
if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
} else if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
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);
new_anim->track_insert_key(dtrack, 0, var);
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_angle"), 22));
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));
for (int i = 0; i < 256; i++) {
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 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);

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);
} else {
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();

View File

@ -95,6 +95,12 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
set_bone_enabled(which, p_value);
} else if (what == "pose") {
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") {
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);
} else if (what == "pose") {
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") {
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::BOOL, prep + "enabled"));
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"));
}
}
@ -239,7 +254,8 @@ void Skeleton::_notification(int p_what) {
if (b.disable_rest) {
if (b.enabled) {
Transform pose = b.pose;
b.update_pose_cache();
Transform pose = b.pose_cache;
if (b.custom_pose_enable) {
pose = b.custom_pose * pose;
}
@ -261,7 +277,8 @@ void Skeleton::_notification(int p_what) {
}
} else {
if (b.enabled) {
Transform pose = b.pose;
b.update_pose_cache();
Transform pose = b.pose_cache;
if (b.custom_pose_enable) {
pose = b.custom_pose * pose;
}
@ -561,16 +578,75 @@ void Skeleton::clear_bones() {
// posing api
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()) {
_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 {
ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
return bones[p_bone].pose;
const int bone_size = bones.size();
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) {
@ -925,8 +1001,15 @@ void Skeleton::_bind_methods() {
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_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("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;
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_no_override;
@ -192,7 +206,14 @@ public:
// posing api
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;
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);
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) {
entry->object->set_indexed(entry->subpath, entry->value);
} 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());
setup_pass++;
for (int i = 0; i < a->get_track_count(); i++) {
p_anim->node_cache.write[i] = NULL;
RES resource;
@ -278,44 +289,100 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
node_cache_map[key] = TrackNodeCache();
}
p_anim->node_cache.write[i] = &node_cache_map[key];
p_anim->node_cache[i]->path = a->track_get_path(i);
p_anim->node_cache[i]->node = child;
p_anim->node_cache[i]->resource = resource;
p_anim->node_cache[i]->node_2d = Object::cast_to<Node2D>(child);
TrackNodeCache *node_cache = &node_cache_map[key];
p_anim->node_cache.write[i] = node_cache;
node_cache->path = a->track_get_path(i);
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) {
// special cases and caches for transform tracks
// cache spatial
p_anim->node_cache[i]->spatial = Object::cast_to<Spatial>(child);
node_cache->spatial = Object::cast_to<Spatial>(child);
// cache skeleton
p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton>(child);
if (p_anim->node_cache[i]->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);
p_anim->node_cache[i]->bone_idx = p_anim->node_cache[i]->skeleton->find_bone(bone_name);
if (p_anim->node_cache[i]->bone_idx < 0) {
node_cache->bone_idx = node_cache->skeleton->find_bone(bone_name);
if (node_cache->bone_idx < 0) {
// broken track (nonexistent bone)
p_anim->node_cache[i]->skeleton = nullptr;
p_anim->node_cache[i]->spatial = nullptr;
ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0);
node_cache->skeleton = nullptr;
node_cache->spatial = nullptr;
ERR_CONTINUE(node_cache->bone_idx < 0);
}
} else {
// 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 (!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;
pa.subpath = leftover_path;
pa.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child;
pa.special = SP_NONE;
pa.owner = p_anim->node_cache[i];
if (false && p_anim->node_cache[i]->node_2d) {
pa.owner = node_cache;
if (false && node_cache->node_2d) {
if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_pos) {
pa.special = SP_NODE2D_POS;
} 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;
}
}
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 (!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;
ba.bezier_property = leftover_path;
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)) {
case Animation::TYPE_TRANSFORM: {
#ifndef _3D_DISABLED
if (!nc->spatial) {
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->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;
case Animation::TYPE_VALUE: {
if (!nc->node) {
@ -855,14 +1006,43 @@ void AnimationPlayer::_animation_update_transforms() {
ERR_CONTINUE(nc->accum_pass != accum_pass);
t.origin = nc->loc_accum;
t.basis.set_quat_scale(nc->rot_accum, nc->scale_accum);
#ifndef _3D_DISABLED
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) {
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;
entry.object = nc->skeleton;
entry.bone_idx = nc->bone_idx;
entry.value = nc->skeleton->get_bone_pose(nc->bone_idx);
if (nc->transform_used) {
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);
} else {
if (nc->spatial) {

View File

@ -93,6 +93,8 @@ private:
SP_NODE2D_SCALE,
};
uint32_t setup_pass = 1;
struct TrackNodeCache {
NodePath path;
uint32_t id;
@ -104,6 +106,14 @@ private:
int bone_idx;
// 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;
Quat rot_accum;
Vector3 scale_accum;
@ -128,7 +138,8 @@ private:
owner(nullptr),
special(SP_NONE),
object(nullptr),
accum_pass(0) {}
accum_pass(0) {
}
};
Map<StringName, PropertyAnim> property_anim;
@ -149,6 +160,8 @@ private:
Map<StringName, BezierAnim> bezier_anim;
uint32_t last_setup_pass;
TrackNodeCache() :
id(0),
node(nullptr),
@ -160,7 +173,16 @@ private:
audio_playing(false),
audio_start(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 {

View File

@ -543,13 +543,18 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
NodePath path = anim->track_get_path(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;
if (track_cache.has(path)) {
track = track_cache.get(path);
}
//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);
memdelete(track);
track_cache.erase(path);
@ -587,6 +592,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
} break;
case Animation::TYPE_TRANSFORM: {
#ifndef _3D_DISABLED
Spatial *spatial = Object::cast_to<Spatial>(child);
if (!spatial) {
@ -595,10 +601,46 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
}
TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
track_xform->type = Animation::TYPE_TRANSFORM;
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)) {
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)) {
Skeleton *sk = Object::cast_to<Skeleton>(spatial);
@ -614,6 +656,21 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
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;
case Animation::TYPE_METHOD: {
TrackCacheMethod *track_method = memnew(TrackCacheMethod);
@ -668,6 +725,28 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
}
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;
@ -831,8 +910,11 @@ void AnimationTree::_process_graph(float p_delta) {
ERR_CONTINUE(!track_cache.has(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;
@ -850,6 +932,7 @@ void AnimationTree::_process_graph(float p_delta) {
switch (track->type) {
case Animation::TYPE_TRANSFORM: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion) {
@ -935,7 +1018,209 @@ void AnimationTree::_process_graph(float p_delta) {
}
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;
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
@ -1198,6 +1483,7 @@ void AnimationTree::_process_graph(float p_delta) {
switch (track->type) {
case Animation::TYPE_TRANSFORM: {
#ifndef _3D_DISABLED
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
Transform xform;
@ -1217,7 +1503,45 @@ void AnimationTree::_process_graph(float p_delta) {
} else if (!t->skeleton) {
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;
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);

View File

@ -174,6 +174,7 @@ private:
ObjectID object_id;
TrackCache() {
type = Animation::TYPE_ANIMATION;
root_motion = false;
setup_pass = 0;
process_pass = 0;
@ -187,16 +188,24 @@ private:
Spatial *spatial;
Skeleton *skeleton;
int bone_idx;
bool transform_used;
bool loc_used;
bool rot_used;
bool scale_used;
Vector3 loc;
Quat rot;
float rot_blend_accum;
Vector3 scale;
TrackCacheTransform() {
type = Animation::TYPE_TRANSFORM;
type = Animation::TYPE_POSITION_3D;
spatial = nullptr;
bone_idx = -1;
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 {
TYPE_VALUE, ///< Set a value in a property, can be interpolated.
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_BEZIER, ///< Bezier curve
TYPE_AUDIO,
@ -97,6 +100,30 @@ private:
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 */
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);
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:
bool _set(const StringName &p_name, const Variant &p_value);
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());
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);
InterpolationType track_get_interpolation_type(int p_track) const;