diff options
Diffstat (limited to 'scene')
-rw-r--r-- | scene/2d/tile_map.cpp | 44 | ||||
-rw-r--r-- | scene/2d/tile_map.h | 3 | ||||
-rw-r--r-- | scene/3d/camera_3d.cpp | 1 | ||||
-rw-r--r-- | scene/3d/skeleton_3d.cpp | 81 | ||||
-rw-r--r-- | scene/3d/skeleton_3d.h | 23 | ||||
-rw-r--r-- | scene/animation/animation_cache.cpp | 314 | ||||
-rw-r--r-- | scene/animation/animation_cache.h | 84 | ||||
-rw-r--r-- | scene/animation/animation_player.cpp | 168 | ||||
-rw-r--r-- | scene/animation/animation_player.h | 7 | ||||
-rw-r--r-- | scene/animation/animation_tree.cpp | 250 | ||||
-rw-r--r-- | scene/animation/animation_tree.h | 5 | ||||
-rw-r--r-- | scene/resources/animation.cpp | 977 | ||||
-rw-r--r-- | scene/resources/animation.h | 74 | ||||
-rw-r--r-- | scene/resources/mesh.cpp | 2 | ||||
-rw-r--r-- | scene/resources/visual_shader.cpp | 52 | ||||
-rw-r--r-- | scene/resources/visual_shader.h | 2 | ||||
-rw-r--r-- | scene/resources/visual_shader_particle_nodes.cpp | 20 | ||||
-rw-r--r-- | scene/resources/visual_shader_particle_nodes.h | 5 |
18 files changed, 1225 insertions, 887 deletions
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 222ec986b0..42c54a950d 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -409,6 +409,19 @@ bool TileMap::is_layer_enabled(int p_layer) const { return layers[p_layer].enabled; } +void TileMap::set_layer_modulate(int p_layer, Color p_modulate) { + ERR_FAIL_INDEX(p_layer, (int)layers.size()); + layers[p_layer].modulate = p_modulate; + _clear_internals(); + _recreate_internals(); + emit_signal(SNAME("changed")); +} + +Color TileMap::get_layer_modulate(int p_layer) const { + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), Color()); + return layers[p_layer].modulate; +} + void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); layers[p_layer].y_sort_enabled = p_y_sort_enabled; @@ -832,6 +845,19 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List int prev_z_index = 0; RID prev_canvas_item; + Color modulate = get_self_modulate(); + modulate *= get_layer_modulate(q.layer); + if (selected_layer >= 0) { + int z1 = get_layer_z_index(q.layer); + int z2 = get_layer_z_index(selected_layer); + if (z1 < z2 || (z1 == z2 && q.layer < selected_layer)) { + modulate = modulate.darkened(0.5); + } else if (z1 > z2 || (z1 == z2 && q.layer > selected_layer)) { + modulate = modulate.darkened(0.5); + modulate.a *= 0.3; + } + } + // Iterate over the cells of the quadrant. for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) { TileMapCell c = get_cell(q.layer, E_cell.value, true); @@ -894,15 +920,6 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List } // Drawing the tile in the canvas item. - Color modulate = get_self_modulate(); - if (selected_layer >= 0) { - if (q.layer < selected_layer) { - modulate = modulate.darkened(0.5); - } else if (q.layer > selected_layer) { - modulate = modulate.darkened(0.5); - modulate.a *= 0.3; - } - } draw_tile(canvas_item, E_cell.key - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, modulate); // --- Occluders --- @@ -2083,6 +2100,9 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { } else if (components[1] == "enabled") { set_layer_enabled(index, p_value); return true; + } else if (components[1] == "modulate") { + set_layer_modulate(index, p_value); + return true; } else if (components[1] == "y_sort_enabled") { set_layer_y_sort_enabled(index, p_value); return true; @@ -2119,6 +2139,9 @@ bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { } else if (components[1] == "enabled") { r_ret = is_layer_enabled(index); return true; + } else if (components[1] == "modulate") { + r_ret = get_layer_modulate(index); + return true; } else if (components[1] == "y_sort_enabled") { r_ret = is_layer_y_sort_enabled(index); return true; @@ -2144,6 +2167,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const { for (unsigned int i = 0; i < layers.size(); i++) { p_list->push_back(PropertyInfo(Variant::STRING, vformat("layer_%d/name", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::BOOL, vformat("layer_%d/enabled", i), PROPERTY_HINT_NONE)); + p_list->push_back(PropertyInfo(Variant::COLOR, vformat("layer_%d/modulate", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::BOOL, vformat("layer_%d/y_sort_enabled", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/y_sort_origin", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/z_index", i), PROPERTY_HINT_NONE)); @@ -3027,6 +3051,8 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_layer_name", "layer"), &TileMap::get_layer_name); ClassDB::bind_method(D_METHOD("set_layer_enabled", "layer", "enabled"), &TileMap::set_layer_enabled); ClassDB::bind_method(D_METHOD("is_layer_enabled", "layer"), &TileMap::is_layer_enabled); + ClassDB::bind_method(D_METHOD("set_layer_modulate", "layer", "enabled"), &TileMap::set_layer_modulate); + ClassDB::bind_method(D_METHOD("get_layer_modulate", "layer"), &TileMap::get_layer_modulate); ClassDB::bind_method(D_METHOD("set_layer_y_sort_enabled", "layer", "y_sort_enabled"), &TileMap::set_layer_y_sort_enabled); ClassDB::bind_method(D_METHOD("is_layer_y_sort_enabled", "layer"), &TileMap::is_layer_y_sort_enabled); ClassDB::bind_method(D_METHOD("set_layer_y_sort_origin", "layer", "y_sort_origin"), &TileMap::set_layer_y_sort_origin); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 2faede2445..b1fbdfdf8a 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -219,6 +219,7 @@ private: struct TileMapLayer { String name; bool enabled = true; + Color modulate = Color(1, 1, 1, 1); bool y_sort_enabled = false; int y_sort_origin = 0; int z_index = 0; @@ -321,6 +322,8 @@ public: String get_layer_name(int p_layer) const; void set_layer_enabled(int p_layer, bool p_visible); bool is_layer_enabled(int p_layer) const; + void set_layer_modulate(int p_layer, Color p_modulate); + Color get_layer_modulate(int p_layer) const; void set_layer_y_sort_enabled(int p_layer, bool p_enabled); bool is_layer_y_sort_enabled(int p_layer) const; void set_layer_y_sort_origin(int p_layer, int p_y_sort_origin); diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 18b7bcc789..588d2b5018 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -656,6 +656,7 @@ Vector3 Camera3D::get_doppler_tracked_velocity() const { } RID Camera3D::get_pyramid_shape_rid() { + ERR_FAIL_COND_V_MSG(!is_inside_tree(), RID(), "Camera is not inside scene."); if (pyramid_shape == RID()) { pyramid_shape_points = get_near_plane_points(); pyramid_shape = PhysicsServer3D::get_singleton()->convex_polygon_shape_create(); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 2b52f034b2..79504b10bb 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -99,8 +99,12 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) { set_bone_rest(which, p_value); } else if (what == "enabled") { 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 { return false; } @@ -135,8 +139,12 @@ bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const { r_ret = get_bone_rest(which); } else if (what == "enabled") { 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 { return false; } @@ -151,7 +159,9 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::QUATERNION, prep + "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); } #ifndef _3D_DISABLED @@ -657,19 +667,60 @@ void Skeleton3D::clear_bones() { // Posing api -void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) { +void Skeleton3D::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 = p_pose; + bones.write[p_bone].pose_position = p_position; + bones.write[p_bone].pose_cache_dirty = true; if (is_inside_tree()) { _make_dirty(); } } +void Skeleton3D::set_bone_pose_rotation(int p_bone, const Quaternion &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 Skeleton3D::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(); + } +} + +Vector3 Skeleton3D::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; +} + +Quaternion Skeleton3D::get_bone_pose_rotation(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Quaternion()); + return bones[p_bone].pose_rotation; +} + +Vector3 Skeleton3D::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; +} + Transform3D Skeleton3D::get_bone_pose(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - return bones[p_bone].pose; + ((Skeleton3D *)this)->bones.write[p_bone].update_pose_cache(); + return bones[p_bone].pose_cache; } void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose) { @@ -989,7 +1040,8 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { if (b.disable_rest) { if (bone_enabled) { - Transform3D pose = b.pose; + b.update_pose_cache(); + Transform3D pose = b.pose_cache; if (b.custom_pose_enable) { pose = b.custom_pose * pose; } @@ -1012,7 +1064,8 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { } else { if (bone_enabled) { - Transform3D pose = b.pose; + b.update_pose_cache(); + Transform3D pose = b.pose_cache; if (b.custom_pose_enable) { pose = b.custom_pose * pose; } @@ -1193,7 +1246,13 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton3D::clear_bones); ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose); - ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_pose); + ClassDB::bind_method(D_METHOD("set_bone_pose_position", "bone_idx", "position"), &Skeleton3D::set_bone_pose_position); + ClassDB::bind_method(D_METHOD("set_bone_pose_rotation", "bone_idx", "rotation"), &Skeleton3D::set_bone_pose_rotation); + ClassDB::bind_method(D_METHOD("set_bone_pose_scale", "bone_idx", "scale"), &Skeleton3D::set_bone_pose_scale); + + ClassDB::bind_method(D_METHOD("get_bone_pose_position", "bone_idx"), &Skeleton3D::get_bone_pose_position); + ClassDB::bind_method(D_METHOD("get_bone_pose_rotation", "bone_idx"), &Skeleton3D::get_bone_pose_rotation); + ClassDB::bind_method(D_METHOD("get_bone_pose_scale", "bone_idx"), &Skeleton3D::get_bone_pose_scale); ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled); ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true)); diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 9aa4fc823f..aacee3da4e 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -79,7 +79,19 @@ private: bool disable_rest = false; Transform3D rest; - Transform3D pose; + _FORCE_INLINE_ void update_pose_cache() { + if (pose_cache_dirty) { + pose_cache.basis.set_quaternion_scale(pose_rotation, pose_scale); + pose_cache.origin = pose_position; + pose_cache_dirty = false; + } + } + bool pose_cache_dirty = true; + Transform3D pose_cache; + Vector3 pose_position; + Quaternion pose_rotation; + Vector3 pose_scale = Vector3(1, 1, 1); + Transform3D pose_global; Transform3D pose_global_no_override; @@ -206,9 +218,16 @@ public: // posing api - void set_bone_pose(int p_bone, const Transform3D &p_pose); + void set_bone_pose_position(int p_bone, const Vector3 &p_position); + void set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation); + void set_bone_pose_scale(int p_bone, const Vector3 &p_scale); + Transform3D get_bone_pose(int p_bone) const; + Vector3 get_bone_pose_position(int p_bone) const; + Quaternion 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 Transform3D &p_custom_pose); Transform3D get_bone_custom_pose(int p_bone) const; diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp deleted file mode 100644 index 56743007e4..0000000000 --- a/scene/animation/animation_cache.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/*************************************************************************/ -/* animation_cache.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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" - -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", callable_mp(this, &AnimationCache::_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_TRANSFORM3D) { -#ifndef _3D_DISABLED - if (np.get_subname_count() > 1) { - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D, "Transform tracks can't have a subpath '" + np + "'."); - } - - Node3D *sp = Object::cast_to<Node3D>(node); - - if (!sp) { - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(!sp, "Transform track not of type Node3D '" + np + "'."); - } - - if (np.get_subname_count() == 1) { - StringName property = np.get_subname(0); - String ps = property; - - Skeleton3D *sk = Object::cast_to<Skeleton3D>(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.node_3d = sp; -#endif // _3D_DISABLED - } 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", callable_mp(this, &AnimationCache::_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 Transform3D &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; - } - -#ifndef _3D_DISABLED - ERR_FAIL_COND(!p.node); - ERR_FAIL_COND(!p.node_3d); - - if (p.skeleton) { - p.skeleton->set_bone_pose(p.bone_idx, p_transform); - } else { - p.node_3d->set_transform(p_transform); - } -#endif // _3D_DISABLED -} - -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, Callable::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_TRANSFORM3D: { - Vector3 loc, scale; - Quaternion rot; - animation->transform_track_interpolate(i, p_time, &loc, &rot, &scale); - Transform3D 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 (int &E : indices) { - Variant v = animation->track_get_key_value(i, E); - 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 (int &E : indices) { - Vector<Variant> args = animation->method_track_get_params(i, E); - StringName name = animation->method_track_get_name(i, E); - Callable::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", callable_mp(this, &AnimationCache::_animation_changed)); - } - - animation = p_animation; - - if (animation.is_valid()) { - animation->connect("changed", callable_mp(this, &AnimationCache::_animation_changed)); - } -} - -void AnimationCache::_bind_methods() { -} - -void AnimationCache::set_root(Node *p_root) { - _clear_cache(); - root = p_root; -} - -AnimationCache::AnimationCache() { -} diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h deleted file mode 100644 index c856e644f7..0000000000 --- a/scene/animation/animation_cache.h +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************/ -/* animation_cache.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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. */ -/*************************************************************************/ - -#ifndef ANIMATION_CACHE_H -#define ANIMATION_CACHE_H - -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/animation.h" - -class AnimationCache : public Object { - GDCLASS(AnimationCache, Object); - - struct Path { - RES resource; - Object *object = nullptr; -#ifndef _3D_DISABLED - Skeleton3D *skeleton = nullptr; - Node3D *node_3d = nullptr; -#endif // _3D_DISABLED - Node *node = nullptr; - - int bone_idx = -1; - Vector<StringName> subpath; - bool valid = false; - }; - - Set<Node *> connected_nodes; - Vector<Path> path_cache; - - Node *root = nullptr; - Ref<Animation> animation; - bool cache_dirty = true; - bool cache_valid = false; - - 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 Transform3D &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, Callable::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 diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 2c8c4ee788..8407e0dd99 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -60,7 +60,12 @@ void AnimatedValuesBackup::restore() const { if (entry->bone_idx == -1) { entry->object->set_indexed(entry->subpath, entry->value); } else { - Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose(entry->bone_idx, entry->value); + Array arr = entry->value; + if (arr.size() == 3) { + Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_position(entry->bone_idx, arr[0]); + Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_rotation(entry->bone_idx, arr[1]); + Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_scale(entry->bone_idx, arr[0]); + } } } } @@ -242,6 +247,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] = nullptr; RES resource; @@ -275,46 +282,68 @@ 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_TRANSFORM3D) { + 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 node_3d - p_anim->node_cache[i]->node_3d = Object::cast_to<Node3D>(child); + node_cache->node_3d = Object::cast_to<Node3D>(child); // cache skeleton - p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton3D>(child); - if (p_anim->node_cache[i]->skeleton) { + node_cache->skeleton = Object::cast_to<Skeleton3D>(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]->node_3d = nullptr; - ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0); + node_cache->skeleton = nullptr; + node_cache->node_3d = 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; + } + } + + 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) { + 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) { @@ -323,20 +352,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]; - 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; } } @@ -369,17 +400,15 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } switch (a->track_get_type(i)) { - case Animation::TYPE_TRANSFORM3D: { + case Animation::TYPE_POSITION_3D: { #ifndef _3D_DISABLED if (!nc->node_3d) { continue; } Vector3 loc; - Quaternion rot; - Vector3 scale; - Error err = a->transform_track_interpolate(i, p_time, &loc, &rot, &scale); + Error err = a->position_track_interpolate(i, p_time, &loc); //ERR_CONTINUE(err!=OK); //used for testing, should be removed if (err != OK) { @@ -391,12 +420,63 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double cache_update[cache_update_size++] = nc; nc->accum_pass = accum_pass; nc->loc_accum = loc; - nc->rot_accum = rot; - nc->scale_accum = scale; - + nc->rot_accum = Quaternion(); + nc->scale_accum = Vector3(); } else { nc->loc_accum = nc->loc_accum.lerp(loc, p_interp); + } +#endif // _3D_DISABLED + } break; + case Animation::TYPE_ROTATION_3D: { +#ifndef _3D_DISABLED + if (!nc->node_3d) { + continue; + } + + Quaternion 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 = Vector3(); + nc->rot_accum = rot; + nc->scale_accum = Vector3(); + } 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->node_3d) { + 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 = Vector3(); + nc->rot_accum = Quaternion(); + nc->scale_accum = scale; + } else { nc->scale_accum = nc->scale_accum.lerp(scale, p_interp); } #endif // _3D_DISABLED @@ -855,15 +935,30 @@ void AnimationPlayer::_animation_update_transforms() { TrackNodeCache *nc = cache_update[i]; ERR_CONTINUE(nc->accum_pass != accum_pass); - - t.origin = nc->loc_accum; - t.basis.set_quaternion_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->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->node_3d) { - nc->node_3d->set_transform(t); + if (nc->loc_used) { + nc->node_3d->set_position(nc->loc_accum); + } + if (nc->rot_used) { + nc->node_3d->set_rotation(nc->rot_accum.get_euler()); + } + if (nc->scale_used) { + nc->node_3d->set_scale(nc->scale_accum); + } } + #endif // _3D_DISABLED } } @@ -1527,7 +1622,12 @@ 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); + 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->node_3d) { diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index b693e29bdf..f8e72a67b6 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -88,6 +88,8 @@ private: SP_NODE2D_SCALE, }; + uint32_t setup_pass = 1; + struct TrackNodeCache { NodePath path; uint32_t id = 0; @@ -101,6 +103,10 @@ private: int bone_idx = -1; // accumulated transforms + bool loc_used = false; + bool rot_used = false; + bool scale_used = false; + Vector3 loc_accum; Quaternion rot_accum; Vector3 scale_accum; @@ -134,6 +140,7 @@ private: Map<StringName, BezierAnim> bezier_anim; + uint32_t last_setup_pass = 0; TrackNodeCache() {} }; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 9ca8d478b1..2ed8268289 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -544,13 +544,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_POSITION_3D || 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,7 +592,9 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { track = track_value; } break; - case Animation::TYPE_TRANSFORM3D: { + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { #ifndef _3D_DISABLED Node3D *node_3d = Object::cast_to<Node3D>(child); @@ -597,6 +604,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { } TrackCacheTransform *track_xform = memnew(TrackCacheTransform); + track_xform->type = Animation::TYPE_POSITION_3D; track_xform->node_3d = node_3d; track_xform->skeleton = nullptr; @@ -615,6 +623,21 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { track_xform->object_id = track_xform->object->get_instance_id(); 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 // _3D_DISABLED } break; case Animation::TYPE_METHOD: { @@ -670,6 +693,26 @@ 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 +874,11 @@ void AnimationTree::_process_graph(real_t 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_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; @@ -848,20 +894,81 @@ void AnimationTree::_process_graph(real_t p_delta) { continue; //nothing to blend } - switch (track->type) { - case Animation::TYPE_TRANSFORM3D: { + switch (ttype) { + 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 = Quaternion(); + t->rot_blend_accum = 0; + t->scale = Vector3(1, 1, 1); + } + if (track->root_motion) { - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = Vector3(); - t->rot = Quaternion(); - t->rot_blend_accum = 0; - t->scale = Vector3(1, 1, 1); + real_t 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, 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.lerp(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 = Quaternion(); + t->rot_blend_accum = 0; + t->scale = Vector3(1, 1, 1); + } + + if (track->root_motion) { real_t prev_time = time - delta; if (prev_time < 0) { if (!a->has_loop()) { @@ -871,61 +978,44 @@ void AnimationTree::_process_graph(real_t p_delta) { } } - Vector3 loc[2]; Quaternion rot[2]; - Vector3 scale[2]; if (prev_time > time) { - Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); + Error err = a->rotation_track_interpolate(i, prev_time, &rot[0]); if (err != OK) { continue; } - a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]); + a->rotation_track_interpolate(i, a->get_length(), &rot[1]); - t->loc += (loc[1] - loc[0]) * blend; - t->scale += (scale[1] - scale[0]) * blend; Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); prev_time = 0; } - Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); + Error err = a->rotation_track_interpolate(i, prev_time, &rot[0]); if (err != OK) { continue; } - a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1]); + a->rotation_track_interpolate(i, time, &rot[1]); - t->loc += (loc[1] - loc[0]) * blend; - t->scale += (scale[1] - scale[0]) * blend; Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); prev_time = 0; } else { - Vector3 loc; Quaternion rot; - Vector3 scale; - Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); + Error err = a->rotation_track_interpolate(i, time, &rot); //ERR_CONTINUE(err!=OK); //used for testing, should be removed - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = loc; - t->rot = rot; - t->rot_blend_accum = 0; - t->scale = scale; - } - if (err != OK) { continue; } - t->loc = t->loc.lerp(loc, blend); if (t->rot_blend_accum == 0) { t->rot = rot; t->rot_blend_accum = blend; @@ -934,6 +1024,67 @@ void AnimationTree::_process_graph(real_t p_delta) { 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 = Quaternion(); + t->rot_blend_accum = 0; + t->scale = Vector3(1, 1, 1); + } + + if (track->root_motion) { + real_t 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, 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.lerp(scale, blend); } #endif // _3D_DISABLED @@ -1198,26 +1349,41 @@ void AnimationTree::_process_graph(real_t p_delta) { } switch (track->type) { - case Animation::TYPE_TRANSFORM3D: { + case Animation::TYPE_POSITION_3D: { #ifndef _3D_DISABLED TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); - Transform3D xform; - xform.origin = t->loc; - - xform.basis.set_quaternion_scale(t->rot, t->scale); - if (t->root_motion) { + Transform3D xform; + xform.origin = t->loc; + xform.basis.set_quaternion_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) { - t->skeleton->set_bone_pose(t->bone_idx, xform); + 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) { - t->node_3d->set_transform(xform); + if (t->loc_used) { + t->node_3d->set_position(t->loc); + } + if (t->rot_used) { + t->node_3d->set_rotation(t->rot.get_euler()); + } + if (t->scale_used) { + t->node_3d->set_scale(t->scale); + } } #endif // _3D_DISABLED } break; diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 1e0267682e..ed207dfe0c 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -197,13 +197,16 @@ private: Skeleton3D *skeleton = nullptr; #endif // _3D_DISABLED int bone_idx = -1; + bool loc_used = false; + bool rot_used = false; + bool scale_used = false; Vector3 loc; Quaternion rot; real_t rot_blend_accum = 0.0; Vector3 scale; TrackCacheTransform() { - type = Animation::TYPE_TRANSFORM3D; + type = Animation::TYPE_POSITION_3D; } }; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index b4eec2530b..6612c5ff3c 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -43,8 +43,12 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { if (tracks.size() == track && what == "type") { String type = p_value; - if (type == "transform" || type == "transform3d") { - add_track(TYPE_TRANSFORM3D); + if (type == "position_3d") { + add_track(TYPE_POSITION_3D); + } else if (type == "rotation_3d") { + add_track(TYPE_ROTATION_3D); + } else if (type == "scale_3d") { + add_track(TYPE_SCALE_3D); } else if (type == "value") { add_track(TYPE_VALUE); } else if (type == "method") { @@ -75,35 +79,72 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { } else if (what == "enabled") { track_set_enabled(track, p_value); } else if (what == "keys" || what == "key_values") { - if (track_get_type(track) == TYPE_TRANSFORM3D) { - TransformTrack *tt = static_cast<TransformTrack *>(tracks[track]); + if (track_get_type(track) == TYPE_POSITION_3D) { + PositionTrack *tt = static_cast<PositionTrack *>(tracks[track]); Vector<real_t> values = p_value; int vcount = values.size(); - ERR_FAIL_COND_V(vcount % TRANSFORM_TRACK_SIZE, false); + ERR_FAIL_COND_V(vcount % POSITION_TRACK_SIZE, false); const real_t *r = values.ptr(); - int64_t count = vcount / TRANSFORM_TRACK_SIZE; - tt->transforms.resize(count); + int64_t count = vcount / POSITION_TRACK_SIZE; + tt->positions.resize(count); + TKey<Vector3> *tw = tt->positions.ptrw(); for (int i = 0; i < count; i++) { - TKey<TransformKey> &tk = tt->transforms.write[i]; - const real_t *ofs = &r[i * TRANSFORM_TRACK_SIZE]; + TKey<Vector3> &tk = tw[i]; + const real_t *ofs = &r[i * POSITION_TRACK_SIZE]; tk.time = ofs[0]; tk.transition = ofs[1]; - tk.value.loc.x = ofs[2]; - tk.value.loc.y = ofs[3]; - tk.value.loc.z = ofs[4]; + tk.value.x = ofs[2]; + tk.value.y = ofs[3]; + tk.value.z = ofs[4]; + } + } else if (track_get_type(track) == TYPE_ROTATION_3D) { + RotationTrack *rt = static_cast<RotationTrack *>(tracks[track]); + Vector<real_t> values = p_value; + int vcount = values.size(); + ERR_FAIL_COND_V(vcount % ROTATION_TRACK_SIZE, false); + + const real_t *r = values.ptr(); + + int64_t count = vcount / ROTATION_TRACK_SIZE; + rt->rotations.resize(count); + + TKey<Quaternion> *rw = rt->rotations.ptrw(); + for (int i = 0; i < count; i++) { + TKey<Quaternion> &rk = rw[i]; + const real_t *ofs = &r[i * ROTATION_TRACK_SIZE]; + rk.time = ofs[0]; + rk.transition = ofs[1]; + + rk.value.x = ofs[2]; + rk.value.y = ofs[3]; + rk.value.z = ofs[4]; + rk.value.w = ofs[5]; + } + } else if (track_get_type(track) == TYPE_SCALE_3D) { + ScaleTrack *st = static_cast<ScaleTrack *>(tracks[track]); + Vector<real_t> values = p_value; + int vcount = values.size(); + ERR_FAIL_COND_V(vcount % SCALE_TRACK_SIZE, false); - tk.value.rot.x = ofs[5]; - tk.value.rot.y = ofs[6]; - tk.value.rot.z = ofs[7]; - tk.value.rot.w = ofs[8]; + const real_t *r = values.ptr(); + + int64_t count = vcount / SCALE_TRACK_SIZE; + st->scales.resize(count); - tk.value.scale.x = ofs[9]; - tk.value.scale.y = ofs[10]; - tk.value.scale.z = ofs[11]; + TKey<Vector3> *sw = st->scales.ptrw(); + for (int i = 0; i < count; i++) { + TKey<Vector3> &sk = sw[i]; + const real_t *ofs = &r[i * SCALE_TRACK_SIZE]; + sk.time = ofs[0]; + sk.transition = ofs[1]; + + sk.value.x = ofs[2]; + sk.value.y = ofs[3]; + sk.value.z = ofs[4]; } } else if (track_get_type(track) == TYPE_VALUE) { @@ -319,8 +360,14 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { ERR_FAIL_INDEX_V(track, tracks.size(), false); if (what == "type") { switch (track_get_type(track)) { - case TYPE_TRANSFORM3D: - r_ret = "transform"; + case TYPE_POSITION_3D: + r_ret = "position_3d"; + break; + case TYPE_ROTATION_3D: + r_ret = "rotation_3d"; + break; + case TYPE_SCALE_3D: + r_ret = "scale_3d"; break; case TYPE_VALUE: r_ret = "value"; @@ -352,31 +399,64 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { } else if (what == "enabled") { r_ret = track_is_enabled(track); } else if (what == "keys") { - if (track_get_type(track) == TYPE_TRANSFORM3D) { + if (track_get_type(track) == TYPE_POSITION_3D) { Vector<real_t> keys; int kk = track_get_key_count(track); - keys.resize(kk * TRANSFORM_TRACK_SIZE); + keys.resize(kk * POSITION_TRACK_SIZE); real_t *w = keys.ptrw(); int idx = 0; for (int i = 0; i < track_get_key_count(track); i++) { Vector3 loc; - Quaternion rot; - Vector3 scale; - transform_track_get_key(track, i, &loc, &rot, &scale); + position_track_get_key(track, i, &loc); w[idx++] = track_get_key_time(track, i); w[idx++] = track_get_key_transition(track, i); w[idx++] = loc.x; w[idx++] = loc.y; w[idx++] = loc.z; + } + r_ret = keys; + return true; + } else if (track_get_type(track) == TYPE_ROTATION_3D) { + Vector<real_t> keys; + int kk = track_get_key_count(track); + keys.resize(kk * ROTATION_TRACK_SIZE); + + real_t *w = keys.ptrw(); + + int idx = 0; + for (int i = 0; i < track_get_key_count(track); i++) { + Quaternion rot; + rotation_track_get_key(track, i, &rot); + + w[idx++] = track_get_key_time(track, i); + w[idx++] = track_get_key_transition(track, i); w[idx++] = rot.x; w[idx++] = rot.y; w[idx++] = rot.z; w[idx++] = rot.w; + } + r_ret = keys; + return true; + + } else if (track_get_type(track) == TYPE_SCALE_3D) { + Vector<real_t> keys; + int kk = track_get_key_count(track); + keys.resize(kk * SCALE_TRACK_SIZE); + + real_t *w = keys.ptrw(); + + int idx = 0; + for (int i = 0; i < track_get_key_count(track); i++) { + Vector3 scale; + scale_track_get_key(track, i, &scale); + + w[idx++] = track_get_key_time(track, i); + w[idx++] = track_get_key_transition(track, i); w[idx++] = scale.x; w[idx++] = scale.y; w[idx++] = scale.z; @@ -384,7 +464,6 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { r_ret = keys; return true; - } else if (track_get_type(track) == TYPE_VALUE) { const ValueTrack *vt = static_cast<const ValueTrack *>(tracks[track]); @@ -591,10 +670,18 @@ int Animation::add_track(TrackType p_type, int p_at_pos) { } switch (p_type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = memnew(TransformTrack); + case TYPE_POSITION_3D: { + PositionTrack *tt = memnew(PositionTrack); tracks.insert(p_at_pos, tt); } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = memnew(RotationTrack); + tracks.insert(p_at_pos, rt); + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = memnew(ScaleTrack); + tracks.insert(p_at_pos, st); + } break; case TYPE_VALUE: { tracks.insert(p_at_pos, memnew(ValueTrack)); @@ -629,9 +716,19 @@ void Animation::remove_track(int p_track) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - _clear(tt->transforms); + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + _clear(tt->positions); + + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + _clear(rt->rotations); + + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + _clear(st->scales); } break; case TYPE_VALUE: { @@ -672,7 +769,7 @@ int Animation::get_track_count() const { } Animation::TrackType Animation::track_get_type(int p_track) const { - ERR_FAIL_INDEX_V(p_track, tracks.size(), TYPE_TRANSFORM3D); + ERR_FAIL_INDEX_V(p_track, tracks.size(), TYPE_VALUE); return tracks[p_track]->type; } @@ -720,31 +817,6 @@ bool Animation::track_get_interpolation_loop_wrap(int p_track) const { return tracks[p_track]->loop_wrap; } -// transform -/* -template<class T> -int Animation::_insert_pos(double p_time, T& p_keys) { - // simple, linear time inset that should be fast enough in reality. - - int idx=p_keys.size(); - - while(true) { - - - if (idx==0 || p_keys[idx-1].time < p_time) { - //condition for insertion. - p_keys.insert(idx,T()); - return idx; - } else if (p_keys[idx-1].time == p_time) { - // condition for replacing. - return idx-1; - } - - idx--; - } -} - -*/ template <class T, class V> int Animation::_insert(double p_time, T &p_keys, const V &p_value) { int idx = p_keys.size(); @@ -774,45 +846,153 @@ void Animation::_clear(T &p_keys) { p_keys.clear(); } -Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const { +//// + +int Animation::position_track_insert_key(int p_track, double p_time, const Vector3 &p_position) { + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_POSITION_3D, -1); + + PositionTrack *tt = static_cast<PositionTrack *>(t); + + TKey<Vector3> tkey; + tkey.time = p_time; + tkey.value = p_position; + + int ret = _insert(p_time, tt->positions, tkey); + emit_changed(); + return ret; +} + +Error Animation::position_track_get_key(int p_track, int p_key, Vector3 *r_position) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); Track *t = tracks[p_track]; - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER); - ERR_FAIL_INDEX_V(p_key, tt->transforms.size(), ERR_INVALID_PARAMETER); + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_COND_V(t->type != TYPE_POSITION_3D, ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_key, tt->positions.size(), ERR_INVALID_PARAMETER); - if (r_loc) { - *r_loc = tt->transforms[p_key].value.loc; - } - if (r_rot) { - *r_rot = tt->transforms[p_key].value.rot; - } - if (r_scale) { - *r_scale = tt->transforms[p_key].value.scale; + *r_position = tt->positions[p_key].value; + + return OK; +} + +Error Animation::position_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_POSITION_3D, ERR_INVALID_PARAMETER); + + PositionTrack *tt = static_cast<PositionTrack *>(t); + + bool ok = false; + + Vector3 tk = _interpolate(tt->positions, p_time, tt->interpolation, tt->loop_wrap, &ok); + + if (!ok) { + return ERR_UNAVAILABLE; } + *r_interpolation = tk; + return OK; +} + +//// + +int Animation::rotation_track_insert_key(int p_track, double p_time, const Quaternion &p_rotation) { + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_ROTATION_3D, -1); + + RotationTrack *rt = static_cast<RotationTrack *>(t); + + TKey<Quaternion> tkey; + tkey.time = p_time; + tkey.value = p_rotation; + + int ret = _insert(p_time, rt->rotations, tkey); + emit_changed(); + return ret; +} + +Error Animation::rotation_track_get_key(int p_track, int p_key, Quaternion *r_rotation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_COND_V(t->type != TYPE_ROTATION_3D, ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_key, rt->rotations.size(), ERR_INVALID_PARAMETER); + + *r_rotation = rt->rotations[p_key].value; return OK; } -int Animation::transform_track_insert_key(int p_track, double p_time, const Vector3 &p_loc, const Quaternion &p_rot, const Vector3 &p_scale) { +Error Animation::rotation_track_interpolate(int p_track, double p_time, Quaternion *r_interpolation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_ROTATION_3D, ERR_INVALID_PARAMETER); + + RotationTrack *rt = static_cast<RotationTrack *>(t); + + bool ok = false; + + Quaternion tk = _interpolate(rt->rotations, p_time, rt->interpolation, rt->loop_wrap, &ok); + + if (!ok) { + return ERR_UNAVAILABLE; + } + *r_interpolation = tk; + return OK; +} + +//// + +int Animation::scale_track_insert_key(int p_track, double p_time, const Vector3 &p_scale) { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, -1); + ERR_FAIL_COND_V(t->type != TYPE_SCALE_3D, -1); - TransformTrack *tt = static_cast<TransformTrack *>(t); + ScaleTrack *st = static_cast<ScaleTrack *>(t); - TKey<TransformKey> tkey; + TKey<Vector3> tkey; tkey.time = p_time; - tkey.value.loc = p_loc; - tkey.value.rot = p_rot; - tkey.value.scale = p_scale; + tkey.value = p_scale; - int ret = _insert(p_time, tt->transforms, tkey); + int ret = _insert(p_time, st->scales, tkey); emit_changed(); return ret; } +Error Animation::scale_track_get_key(int p_track, int p_key, Vector3 *r_scale) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_COND_V(t->type != TYPE_SCALE_3D, ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_key, st->scales.size(), ERR_INVALID_PARAMETER); + + *r_scale = st->scales[p_key].value; + + return OK; +} + +Error Animation::scale_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_SCALE_3D, ERR_INVALID_PARAMETER); + + ScaleTrack *st = static_cast<ScaleTrack *>(t); + + bool ok = false; + + Vector3 tk = _interpolate(st->scales, p_time, st->interpolation, st->loop_wrap, &ok); + + if (!ok) { + return ERR_UNAVAILABLE; + } + *r_interpolation = tk; + return OK; +} + void Animation::track_remove_key_at_time(int p_track, double p_time) { int idx = track_find_key(p_track, p_time, true); ERR_FAIL_COND(idx < 0); @@ -824,10 +1004,22 @@ void Animation::track_remove_key(int p_track, int p_idx) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX(p_idx, tt->transforms.size()); - tt->transforms.remove(p_idx); + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX(p_idx, tt->positions.size()); + tt->positions.remove(p_idx); + + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX(p_idx, rt->rotations.size()); + rt->rotations.remove(p_idx); + + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX(p_idx, st->scales.size()); + st->scales.remove(p_idx); } break; case TYPE_VALUE: { @@ -870,13 +1062,37 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - int k = _find(tt->transforms, p_time); - if (k < 0 || k >= tt->transforms.size()) { + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + int k = _find(tt->positions, p_time); + if (k < 0 || k >= tt->positions.size()) { return -1; } - if (tt->transforms[k].time != p_time && p_exact) { + if (tt->positions[k].time != p_time && p_exact) { + return -1; + } + return k; + + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + int k = _find(rt->rotations, p_time); + if (k < 0 || k >= rt->rotations.size()) { + return -1; + } + if (rt->rotations[k].time != p_time && p_exact) { + return -1; + } + return k; + + } break; + case TYPE_SCALE_3D: { + ScaleTrack *rt = static_cast<ScaleTrack *>(t); + int k = _find(rt->scales, p_time); + if (k < 0 || k >= rt->scales.size()) { + return -1; + } + if (rt->scales[k].time != p_time && p_exact) { return -1; } return k; @@ -952,24 +1168,21 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - Dictionary d = p_key; - Vector3 loc; - if (d.has("location")) { - loc = d["location"]; - } - - Quaternion rot; - if (d.has("rotation")) { - rot = d["rotation"]; - } + case TYPE_POSITION_3D: { + ERR_FAIL_COND((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I)); + int idx = position_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, idx, p_transition); - Vector3 scale; - if (d.has("scale")) { - scale = d["scale"]; - } + } break; + case TYPE_ROTATION_3D: { + ERR_FAIL_COND((p_key.get_type() != Variant::QUATERNION) && (p_key.get_type() != Variant::BASIS)); + int idx = rotation_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, idx, p_transition); - int idx = transform_track_insert_key(p_track, p_time, loc, rot, scale); + } break; + case TYPE_SCALE_3D: { + ERR_FAIL_COND((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I)); + int idx = scale_track_insert_key(p_track, p_time, p_key); track_set_key_transition(p_track, idx, p_transition); } break; @@ -1054,9 +1267,17 @@ int Animation::track_get_key_count(int p_track) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - return tt->transforms.size(); + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + return tt->positions.size(); + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + return rt->rotations.size(); + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + return st->scales.size(); } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1089,16 +1310,23 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), Variant()); + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, tt->positions.size(), Variant()); - Dictionary d; - d["location"] = tt->transforms[p_key_idx].value.loc; - d["rotation"] = tt->transforms[p_key_idx].value.rot; - d["scale"] = tt->transforms[p_key_idx].value.scale; + return tt->positions[p_key_idx].value; + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, rt->rotations.size(), Variant()); - return d; + return rt->rotations[p_key_idx].value; + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, st->scales.size(), Variant()); + + return st->scales[p_key_idx].value; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1157,10 +1385,20 @@ double Animation::track_get_key_time(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), -1); - return tt->transforms[p_key_idx].time; + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, tt->positions.size(), -1); + return tt->positions[p_key_idx].time; + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, rt->rotations.size(), -1); + return rt->rotations[p_key_idx].time; + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, st->scales.size(), -1); + return st->scales[p_key_idx].time; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1202,13 +1440,31 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); - TKey<TransformKey> key = tt->transforms[p_key_idx]; + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->positions.size()); + TKey<Vector3> key = tt->positions[p_key_idx]; key.time = p_time; - tt->transforms.remove(p_key_idx); - _insert(p_time, tt->transforms, key); + tt->positions.remove(p_key_idx); + _insert(p_time, tt->positions, key); + return; + } + case TYPE_ROTATION_3D: { + RotationTrack *tt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->rotations.size()); + TKey<Quaternion> key = tt->rotations[p_key_idx]; + key.time = p_time; + tt->rotations.remove(p_key_idx); + _insert(p_time, tt->rotations, key); + return; + } + case TYPE_SCALE_3D: { + ScaleTrack *tt = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->scales.size()); + TKey<Vector3> key = tt->scales[p_key_idx]; + key.time = p_time; + tt->scales.remove(p_key_idx); + _insert(p_time, tt->scales, key); return; } case TYPE_VALUE: { @@ -1266,10 +1522,20 @@ real_t Animation::track_get_key_transition(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), -1); - return tt->transforms[p_key_idx].transition; + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, tt->positions.size(), -1); + return tt->positions[p_key_idx].transition; + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, rt->rotations.size(), -1); + return rt->rotations[p_key_idx].transition; + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, st->scales.size(), -1); + return st->scales[p_key_idx].transition; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1302,21 +1568,28 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); + case TYPE_POSITION_3D: { + ERR_FAIL_COND((p_value.get_type() != Variant::VECTOR3) && (p_value.get_type() != Variant::VECTOR3I)); + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->positions.size()); - Dictionary d = p_value; + tt->positions.write[p_key_idx].value = p_value; - if (d.has("location")) { - tt->transforms.write[p_key_idx].value.loc = d["location"]; - } - if (d.has("rotation")) { - tt->transforms.write[p_key_idx].value.rot = d["rotation"]; - } - if (d.has("scale")) { - tt->transforms.write[p_key_idx].value.scale = d["scale"]; - } + } break; + case TYPE_ROTATION_3D: { + ERR_FAIL_COND((p_value.get_type() != Variant::QUATERNION) && (p_value.get_type() != Variant::BASIS)); + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, rt->rotations.size()); + + rt->rotations.write[p_key_idx].value = p_value; + + } break; + case TYPE_SCALE_3D: { + ERR_FAIL_COND((p_value.get_type() != Variant::VECTOR3) && (p_value.get_type() != Variant::VECTOR3I)); + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, st->scales.size()); + + st->scales.write[p_key_idx].value = p_value; } break; case TYPE_VALUE: { @@ -1385,10 +1658,20 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, real_t p_tr Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); - tt->transforms.write[p_key_idx].transition = p_transition; + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->positions.size()); + tt->positions.write[p_key_idx].transition = p_transition; + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, rt->rotations.size()); + rt->rotations.write[p_key_idx].transition = p_transition; + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, st->scales.size()); + st->scales.write[p_key_idx].transition = p_transition; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1450,15 +1733,6 @@ int Animation::_find(const Vector<K> &p_keys, double p_time) const { return middle; } -Animation::TransformKey Animation::_interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, real_t p_c) const { - TransformKey ret; - ret.loc = _interpolate(p_a.loc, p_b.loc, p_c); - ret.rot = _interpolate(p_a.rot, p_b.rot, p_c); - ret.scale = _interpolate(p_a.scale, p_b.scale, p_c); - - return ret; -} - Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const { return p_a.lerp(p_b, p_c); } @@ -1477,16 +1751,6 @@ real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) return p_a * (1.0 - p_c) + p_b * p_c; } -Animation::TransformKey Animation::_cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, real_t p_c) const { - Animation::TransformKey tk; - - tk.loc = p_a.loc.cubic_interpolate(p_b.loc, p_pre_a.loc, p_post_b.loc, p_c); - tk.scale = p_a.scale.cubic_interpolate(p_b.scale, p_pre_a.scale, p_post_b.scale, p_c); - tk.rot = p_a.rot.cubic_slerp(p_b.rot, p_pre_a.rot, p_post_b.rot, p_c); - - return tk; -} - Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const { return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c); } @@ -1729,36 +1993,6 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol // do a barrel roll } -Error Animation::transform_track_interpolate(int p_track, double p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const { - ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); - Track *t = tracks[p_track]; - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER); - - TransformTrack *tt = static_cast<TransformTrack *>(t); - - bool ok = false; - - TransformKey tk = _interpolate(tt->transforms, p_time, tt->interpolation, tt->loop_wrap, &ok); - - if (!ok) { - return ERR_UNAVAILABLE; - } - - if (r_loc) { - *r_loc = tk.loc; - } - - if (r_rot) { - *r_rot = tk.rot; - } - - if (r_scale) { - *r_scale = tk.scale; - } - - return OK; -} - Variant Animation::value_track_interpolate(int p_track, double p_time) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); Track *t = tracks[p_track]; @@ -1933,10 +2167,22 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl // handle loop by splitting switch (t->type) { - case TYPE_TRANSFORM3D: { - const TransformTrack *tt = static_cast<const TransformTrack *>(t); - _track_get_key_indices_in_range(tt->transforms, from_time, length, p_indices); - _track_get_key_indices_in_range(tt->transforms, 0, to_time, p_indices); + case TYPE_POSITION_3D: { + const PositionTrack *tt = static_cast<const PositionTrack *>(t); + _track_get_key_indices_in_range(tt->positions, from_time, length, p_indices); + _track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices); + + } break; + case TYPE_ROTATION_3D: { + const RotationTrack *rt = static_cast<const RotationTrack *>(t); + _track_get_key_indices_in_range(rt->rotations, from_time, length, p_indices); + _track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices); + + } break; + case TYPE_SCALE_3D: { + const ScaleTrack *st = static_cast<const ScaleTrack *>(t); + _track_get_key_indices_in_range(st->scales, from_time, length, p_indices); + _track_get_key_indices_in_range(st->scales, 0, to_time, p_indices); } break; case TYPE_VALUE: { @@ -1989,9 +2235,19 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl } switch (t->type) { - case TYPE_TRANSFORM3D: { - const TransformTrack *tt = static_cast<const TransformTrack *>(t); - _track_get_key_indices_in_range(tt->transforms, from_time, to_time, p_indices); + case TYPE_POSITION_3D: { + const PositionTrack *tt = static_cast<const PositionTrack *>(t); + _track_get_key_indices_in_range(tt->positions, from_time, to_time, p_indices); + + } break; + case TYPE_ROTATION_3D: { + const RotationTrack *rt = static_cast<const RotationTrack *>(t); + _track_get_key_indices_in_range(rt->rotations, from_time, to_time, p_indices); + + } break; + case TYPE_SCALE_3D: { + const ScaleTrack *st = static_cast<const ScaleTrack *>(t); + _track_get_key_indices_in_range(st->scales, from_time, to_time, p_indices); } break; case TYPE_VALUE: { @@ -2608,7 +2864,10 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_set_enabled", "track_idx", "enabled"), &Animation::track_set_enabled); ClassDB::bind_method(D_METHOD("track_is_enabled", "track_idx"), &Animation::track_is_enabled); - ClassDB::bind_method(D_METHOD("transform_track_insert_key", "track_idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key); + ClassDB::bind_method(D_METHOD("position_track_insert_key", "track_idx", "time", "position"), &Animation::position_track_insert_key); + ClassDB::bind_method(D_METHOD("rotation_track_insert_key", "track_idx", "time", "rotation"), &Animation::rotation_track_insert_key); + ClassDB::bind_method(D_METHOD("scale_track_insert_key", "track_idx", "time", "scale"), &Animation::scale_track_insert_key); + ClassDB::bind_method(D_METHOD("track_insert_key", "track_idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1)); ClassDB::bind_method(D_METHOD("track_remove_key", "track_idx", "key_idx"), &Animation::track_remove_key); ClassDB::bind_method(D_METHOD("track_remove_key_at_time", "track_idx", "time"), &Animation::track_remove_key_at_time); @@ -2628,7 +2887,6 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_set_interpolation_loop_wrap", "track_idx", "interpolation"), &Animation::track_set_interpolation_loop_wrap); ClassDB::bind_method(D_METHOD("track_get_interpolation_loop_wrap", "track_idx"), &Animation::track_get_interpolation_loop_wrap); - ClassDB::bind_method(D_METHOD("transform_track_interpolate", "track_idx", "time_sec"), &Animation::_transform_track_interpolate); ClassDB::bind_method(D_METHOD("value_track_set_update_mode", "track_idx", "mode"), &Animation::value_track_set_update_mode); ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "track_idx"), &Animation::value_track_get_update_mode); @@ -2682,7 +2940,9 @@ void Animation::_bind_methods() { ADD_SIGNAL(MethodInfo("tracks_changed")); BIND_ENUM_CONSTANT(TYPE_VALUE); - BIND_ENUM_CONSTANT(TYPE_TRANSFORM3D); + BIND_ENUM_CONSTANT(TYPE_POSITION_3D); + BIND_ENUM_CONSTANT(TYPE_ROTATION_3D); + BIND_ENUM_CONSTANT(TYPE_SCALE_3D); BIND_ENUM_CONSTANT(TYPE_METHOD); BIND_ENUM_CONSTANT(TYPE_BEZIER); BIND_ENUM_CONSTANT(TYPE_AUDIO); @@ -2709,193 +2969,215 @@ void Animation::clear() { emit_signal(SceneStringNames::get_singleton()->tracks_changed); } -bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, real_t p_alowed_linear_err, real_t p_alowed_angular_err, real_t p_max_optimizable_angle, const Vector3 &p_norm) { - real_t c = (t1.time - t0.time) / (t2.time - t0.time); - real_t t[3] = { -1, -1, -1 }; +bool Animation::_position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm) { + const Vector3 &v0 = t0.value; + const Vector3 &v1 = t1.value; + const Vector3 &v2 = t2.value; - { //translation + if (v0.is_equal_approx(v2)) { + //0 and 2 are close, let's see if 1 is close + if (!v0.is_equal_approx(v1)) { + //not close, not optimizable + return false; + } - const Vector3 &v0 = t0.value.loc; - const Vector3 &v1 = t1.value.loc; - const Vector3 &v2 = t2.value.loc; + } else { + Vector3 pd = (v2 - v0); + real_t d0 = pd.dot(v0); + real_t d1 = pd.dot(v1); + real_t d2 = pd.dot(v2); + if (d1 < d0 || d1 > d2) { + return false; + } - if (v0.is_equal_approx(v2)) { - //0 and 2 are close, let's see if 1 is close - if (!v0.is_equal_approx(v1)) { - //not close, not optimizable - return false; - } + Vector3 s[2] = { v0, v2 }; + real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); - } else { - Vector3 pd = (v2 - v0); - real_t d0 = pd.dot(v0); - real_t d1 = pd.dot(v1); - real_t d2 = pd.dot(v2); - if (d1 < d0 || d1 > d2) { - return false; - } + if (d > pd.length() * p_allowed_linear_err) { + return false; //beyond allowed error for collinearity + } - Vector3 s[2] = { v0, v2 }; - real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); + if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_allowed_angular_error) { + return false; + } + } - if (d > pd.length() * p_alowed_linear_err) { - return false; //beyond allowed error for collinearity - } + return true; +} - if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_alowed_angular_err) { - return false; - } +bool Animation::_rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle) { + const Quaternion &q0 = t0.value; + const Quaternion &q1 = t1.value; + const Quaternion &q2 = t2.value; + + //localize both to rotation from q0 - t[0] = (d1 - d0) / (d2 - d0); + if (q0.is_equal_approx(q2)) { + if (!q0.is_equal_approx(q1)) { + return false; } - } - { //rotation + } else { + Quaternion r02 = (q0.inverse() * q2).normalized(); + Quaternion r01 = (q0.inverse() * q1).normalized(); - const Quaternion &q0 = t0.value.rot; - const Quaternion &q1 = t1.value.rot; - const Quaternion &q2 = t2.value.rot; + Vector3 v02, v01; + real_t a02, a01; - //localize both to rotation from q0 + r02.get_axis_angle(v02, a02); + r01.get_axis_angle(v01, a01); - if (q0.is_equal_approx(q2)) { - if (!q0.is_equal_approx(q1)) { - return false; - } + if (Math::abs(a02) > p_max_optimizable_angle) { + return false; + } - } else { - Quaternion r02 = (q0.inverse() * q2).normalized(); - Quaternion r01 = (q0.inverse() * q1).normalized(); + if (v01.dot(v02) < 0) { + //make sure both rotations go the same way to compare + v02 = -v02; + a02 = -a02; + } - Vector3 v02, v01; - real_t a02, a01; + real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized())) / Math_PI; + if (err_01 > p_allowed_angular_error) { + //not rotating in the same axis + return false; + } - r02.get_axis_angle(v02, a02); - r01.get_axis_angle(v01, a01); + if (a01 * a02 < 0) { + //not rotating in the same direction + return false; + } - if (Math::abs(a02) > p_max_optimizable_angle) { - return false; - } + real_t tr = a01 / a02; + if (tr < 0 || tr > 1) { + return false; //rotating too much or too less + } + } - if (v01.dot(v02) < 0) { - //make sure both rotations go the same way to compare - v02 = -v02; - a02 = -a02; - } + return true; +} - real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized())) / Math_PI; - if (err_01 > p_alowed_angular_err) { - //not rotating in the same axis - return false; - } +bool Animation::_scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error) { + const Vector3 &v0 = t0.value; + const Vector3 &v1 = t1.value; + const Vector3 &v2 = t2.value; - if (a01 * a02 < 0) { - //not rotating in the same direction - return false; - } + if (v0.is_equal_approx(v2)) { + //0 and 2 are close, let's see if 1 is close + if (!v0.is_equal_approx(v1)) { + //not close, not optimizable + return false; + } - real_t tr = a01 / a02; - if (tr < 0 || tr > 1) { - return false; //rotating too much or too less - } + } else { + Vector3 pd = (v2 - v0); + real_t d0 = pd.dot(v0); + real_t d1 = pd.dot(v1); + real_t d2 = pd.dot(v2); + if (d1 < d0 || d1 > d2) { + return false; //beyond segment range + } - t[1] = tr; + Vector3 s[2] = { v0, v2 }; + real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); + + if (d > pd.length() * p_allowed_linear_error) { + return false; //beyond allowed error for colinearity } } - { //scale + return true; +} - const Vector3 &v0 = t0.value.scale; - const Vector3 &v1 = t1.value.scale; - const Vector3 &v2 = t2.value.scale; +void Animation::_position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err) { + ERR_FAIL_INDEX(p_idx, tracks.size()); + ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D); + PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]); + bool prev_erased = false; + TKey<Vector3> first_erased; - if (v0.is_equal_approx(v2)) { - //0 and 2 are close, let's see if 1 is close - if (!v0.is_equal_approx(v1)) { - //not close, not optimizable - return false; - } + Vector3 norm; - } else { - Vector3 pd = (v2 - v0); - real_t d0 = pd.dot(v0); - real_t d1 = pd.dot(v1); - real_t d2 = pd.dot(v2); - if (d1 < d0 || d1 > d2) { - return false; //beyond segment range - } + for (int i = 1; i < tt->positions.size() - 1; i++) { + TKey<Vector3> &t0 = tt->positions.write[i - 1]; + TKey<Vector3> &t1 = tt->positions.write[i]; + TKey<Vector3> &t2 = tt->positions.write[i + 1]; - Vector3 s[2] = { v0, v2 }; - real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); + bool erase = _position_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, norm); + if (erase && !prev_erased) { + norm = (t2.value - t1.value).normalized(); + } + + if (prev_erased && !_position_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err, p_allowed_angular_err, norm)) { + //avoid error to go beyond first erased key + erase = false; + } - if (d > pd.length() * p_alowed_linear_err) { - return false; //beyond allowed error for collinearity + if (erase) { + if (!prev_erased) { + first_erased = t1; + prev_erased = true; } - t[2] = (d1 - d0) / (d2 - d0); + tt->positions.remove(i); + i--; + + } else { + prev_erased = false; + norm = Vector3(); } } +} - bool erase = false; - if (t[0] == -1 && t[1] == -1 && t[2] == -1) { - erase = true; - } else { - erase = true; - real_t lt = -1.0; - for (int j = 0; j < 3; j++) { - //search for t on first, one must be it - if (t[j] != -1) { - lt = t[j]; //official t - //validate rest - for (int k = j + 1; k < 3; k++) { - if (t[k] == -1) { - continue; - } +void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { + ERR_FAIL_INDEX(p_idx, tracks.size()); + ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D); + RotationTrack *tt = static_cast<RotationTrack *>(tracks[p_idx]); + bool prev_erased = false; + TKey<Quaternion> first_erased; - if (Math::abs(lt - t[k]) > p_alowed_linear_err) { - erase = false; - break; - } - } - break; - } - } + for (int i = 1; i < tt->rotations.size() - 1; i++) { + TKey<Quaternion> &t0 = tt->rotations.write[i - 1]; + TKey<Quaternion> &t1 = tt->rotations.write[i]; + TKey<Quaternion> &t2 = tt->rotations.write[i + 1]; - ERR_FAIL_COND_V(lt == -1, false); + bool erase = _rotation_track_optimize_key(t0, t1, t2, p_allowed_angular_err, p_max_optimizable_angle); + + if (prev_erased && !_rotation_track_optimize_key(t0, first_erased, t2, p_allowed_angular_err, p_max_optimizable_angle)) { + //avoid error to go beyond first erased key + erase = false; + } if (erase) { - if (Math::abs(lt - c) > p_alowed_linear_err) { - //todo, evaluate changing the transition if this fails? - //this could be done as a second pass and would be - //able to optimize more - erase = false; + if (!prev_erased) { + first_erased = t1; + prev_erased = true; } + + tt->rotations.remove(i); + i--; + + } else { + prev_erased = false; } } - - return erase; } -void Animation::_transform_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { +void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_linear_err) { ERR_FAIL_INDEX(p_idx, tracks.size()); - ERR_FAIL_COND(tracks[p_idx]->type != TYPE_TRANSFORM3D); - TransformTrack *tt = static_cast<TransformTrack *>(tracks[p_idx]); + ERR_FAIL_COND(tracks[p_idx]->type != TYPE_SCALE_3D); + ScaleTrack *tt = static_cast<ScaleTrack *>(tracks[p_idx]); bool prev_erased = false; - TKey<TransformKey> first_erased; + TKey<Vector3> first_erased; - Vector3 norm; + for (int i = 1; i < tt->scales.size() - 1; i++) { + TKey<Vector3> &t0 = tt->scales.write[i - 1]; + TKey<Vector3> &t1 = tt->scales.write[i]; + TKey<Vector3> &t2 = tt->scales.write[i + 1]; - for (int i = 1; i < tt->transforms.size() - 1; i++) { - TKey<TransformKey> &t0 = tt->transforms.write[i - 1]; - TKey<TransformKey> &t1 = tt->transforms.write[i]; - TKey<TransformKey> &t2 = tt->transforms.write[i + 1]; + bool erase = _scale_track_optimize_key(t0, t1, t2, p_allowed_linear_err); - bool erase = _transform_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle, norm); - if (erase && !prev_erased) { - norm = (t2.value.loc - t1.value.loc).normalized(); - } - - if (prev_erased && !_transform_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle, norm)) { + if (prev_erased && !_scale_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) { //avoid error to go beyond first erased key erase = false; } @@ -2906,20 +3188,23 @@ void Animation::_transform_track_optimize(int p_idx, real_t p_allowed_linear_err prev_erased = true; } - tt->transforms.remove(i); + tt->scales.remove(i); i--; } else { prev_erased = false; - norm = Vector3(); } } } void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { for (int i = 0; i < tracks.size(); i++) { - if (tracks[i]->type == TYPE_TRANSFORM3D) { - _transform_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle); + if (tracks[i]->type == TYPE_POSITION_3D) { + _position_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err); + } else if (tracks[i]->type == TYPE_ROTATION_3D) { + _rotation_track_optimize(i, p_allowed_angular_err, p_max_optimizable_angle); + } else if (tracks[i]->type == TYPE_SCALE_3D) { + _scale_track_optimize(i, p_allowed_linear_err); } } } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 9a410bd566..614e12a560 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -42,7 +42,9 @@ class Animation : public Resource { public: enum TrackType { TYPE_VALUE, ///< Set a value in a property, can be interpolated. - TYPE_TRANSFORM3D, ///< 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, @@ -86,21 +88,31 @@ private: T value; }; - struct TransformKey { - Vector3 loc; - Quaternion rot; - Vector3 scale; + const int32_t POSITION_TRACK_SIZE = 5; + const int32_t ROTATION_TRACK_SIZE = 6; + const int32_t SCALE_TRACK_SIZE = 5; + + /* POSITION TRACK */ + + struct PositionTrack : public Track { + Vector<TKey<Vector3>> positions; + + PositionTrack() { type = TYPE_POSITION_3D; } }; - // Not necessarily the same size as Transform3D. The amount of numbers in Animation::Key and TransformKey. - const int32_t TRANSFORM_TRACK_SIZE = 12; + /* ROTATION TRACK */ - /* TRANSFORM TRACK */ + struct RotationTrack : public Track { + Vector<TKey<Quaternion>> rotations; - struct TransformTrack : public Track { - Vector<TKey<TransformKey>> transforms; + RotationTrack() { type = TYPE_ROTATION_3D; } + }; - TransformTrack() { type = TYPE_TRANSFORM3D; } + /* SCALE TRACK */ + + struct ScaleTrack : public Track { + Vector<TKey<Vector3>> scales; + ScaleTrack() { type = TYPE_SCALE_3D; } }; /* PROPERTY VALUE TRACK */ @@ -186,14 +198,11 @@ private: template <class K> inline int _find(const Vector<K> &p_keys, double p_time) const; - _FORCE_INLINE_ Animation::TransformKey _interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, real_t p_c) const; - _FORCE_INLINE_ Vector3 _interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const; _FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, real_t p_c) const; _FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const; _FORCE_INLINE_ real_t _interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const; - _FORCE_INLINE_ Animation::TransformKey _cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, real_t p_c) const; _FORCE_INLINE_ Vector3 _cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const; _FORCE_INLINE_ Quaternion _cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c) const; _FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const; @@ -214,18 +223,6 @@ private: // bind helpers private: - Array _transform_track_interpolate(int p_track, double p_time) const { - Vector3 loc; - Quaternion rot; - Vector3 scale; - transform_track_interpolate(p_track, p_time, &loc, &rot, &scale); - Array ret; - ret.push_back(loc); - ret.push_back(rot); - ret.push_back(scale); - return ret; - } - Vector<int> _value_track_get_key_indices(int p_track, double p_time, double p_delta) const { List<int> idxs; value_track_get_key_indices(p_track, p_time, p_delta, &idxs); @@ -247,8 +244,13 @@ private: return idxr; } - bool _transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, real_t p_alowed_linear_err, real_t p_alowed_angular_err, real_t p_max_optimizable_angle, const Vector3 &p_norm); - void _transform_track_optimize(int p_idx, real_t p_allowed_linear_err = 0.05, real_t p_allowed_angular_err = 0.01, real_t 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<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &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); @@ -294,8 +296,18 @@ public: double track_get_key_time(int p_track, int p_key_idx) const; real_t track_get_key_transition(int p_track, int p_key_idx) const; - int transform_track_insert_key(int p_track, double p_time, const Vector3 &p_loc, const Quaternion &p_rot = Quaternion(), const Vector3 &p_scale = Vector3()); - Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *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 Quaternion &p_rotation); + Error rotation_track_get_key(int p_track, int p_key, Quaternion *r_rotation) const; + Error rotation_track_interpolate(int p_track, double p_time, Quaternion *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; @@ -324,8 +336,6 @@ public: void track_set_interpolation_loop_wrap(int p_track, bool p_enable); bool track_get_interpolation_loop_wrap(int p_track) const; - Error transform_track_interpolate(int p_track, double p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const; - Variant value_track_interpolate(int p_track, double p_time) const; void value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const; void value_track_set_update_mode(int p_track, UpdateMode p_mode); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 18e6a51118..7ffe0b03e1 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1577,7 +1577,7 @@ void ArrayMesh::regen_normal_maps() { } //dirty hack -bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = NULL; +bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = nullptr; struct ArrayMeshLightmapSurface { Ref<Material> material; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 934d16bd7e..0dc83b4bb8 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -113,6 +113,10 @@ bool VisualShaderNode::is_output_port_expandable(int p_port) const { return false; } +bool VisualShaderNode::has_output_port_preview(int p_port) const { + return true; +} + void VisualShaderNode::_set_output_ports_expanded(const Array &p_values) { for (int i = 0; i < p_values.size(); i++) { expanded_output_ports[p_values[i]] = true; @@ -2307,7 +2311,21 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { }; const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { + // Spatial, Vertex + + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "vec3(1.0, 0.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Spatial, Fragment + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0, 1.0, 0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "vec3(1.0, 0.0, 0.0)" }, @@ -2315,44 +2333,59 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "1.0" }, - - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Spatial, Light - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Canvas Item, Vertex + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Canvas Item, Fragment + + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Canvas Item, Light + + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Sky + + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Particles + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr }, }; @@ -2413,13 +2446,10 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T case PORT_TYPE_VECTOR: { code = " " + p_output_vars[0] + " = vec3(0.0);\n"; } break; - case PORT_TYPE_TRANSFORM: { - code = " " + p_output_vars[0] + " = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; - } break; case PORT_TYPE_BOOLEAN: { code = " " + p_output_vars[0] + " = false;\n"; } break; - default: //default (none found) is scalar + default: break; } } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index b3efac02aa..f910f28536 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -254,6 +254,8 @@ public: void set_input_port_connected(int p_port, bool p_connected); virtual bool is_generate_input_var(int p_port) const; + virtual bool has_output_port_preview(int p_port) const; + virtual bool is_output_port_expandable(int p_port) const; void _set_output_ports_expanded(const Array &p_data); Array _get_output_ports_expanded() const; diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index 5fe801e037..18b933e5cf 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -47,6 +47,10 @@ String VisualShaderNodeParticleEmitter::get_output_port_name(int p_port) const { return String(); } +bool VisualShaderNodeParticleEmitter::has_output_port_preview(int p_port) const { + return false; +} + VisualShaderNodeParticleEmitter::VisualShaderNodeParticleEmitter() { } @@ -265,6 +269,10 @@ Vector<StringName> VisualShaderNodeParticleMultiplyByAxisAngle::get_editable_pro return props; } +bool VisualShaderNodeParticleMultiplyByAxisAngle::has_output_port_preview(int p_port) const { + return false; +} + VisualShaderNodeParticleMultiplyByAxisAngle::VisualShaderNodeParticleMultiplyByAxisAngle() { set_input_port_default_value(1, Vector3(1, 0, 0)); set_input_port_default_value(2, 0.0); @@ -313,6 +321,10 @@ String VisualShaderNodeParticleConeVelocity::get_output_port_name(int p_port) co return String(); } +bool VisualShaderNodeParticleConeVelocity::has_output_port_preview(int p_port) const { + return false; +} + String VisualShaderNodeParticleConeVelocity::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; code += " __radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; @@ -421,6 +433,10 @@ VisualShaderNodeParticleRandomness::OpType VisualShaderNodeParticleRandomness::g return op_type; } +bool VisualShaderNodeParticleRandomness::has_output_port_preview(int p_port) const { + return false; +} + VisualShaderNodeParticleRandomness::VisualShaderNodeParticleRandomness() { set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 1.0); @@ -521,6 +537,10 @@ VisualShaderNodeParticleAccelerator::Mode VisualShaderNodeParticleAccelerator::g return mode; } +bool VisualShaderNodeParticleAccelerator::has_output_port_preview(int p_port) const { + return false; +} + VisualShaderNodeParticleAccelerator::VisualShaderNodeParticleAccelerator() { set_input_port_default_value(0, Vector3(1, 1, 1)); set_input_port_default_value(1, 0.0); diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h index f5435c3511..b8bc7992cc 100644 --- a/scene/resources/visual_shader_particle_nodes.h +++ b/scene/resources/visual_shader_particle_nodes.h @@ -42,6 +42,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; VisualShaderNodeParticleEmitter(); }; @@ -112,6 +113,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; @@ -135,6 +137,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; @@ -168,6 +171,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; @@ -209,6 +213,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; |