From 00ea4b8b7e3fadf54cdb7ab66b5326eae37c2a66 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Mon, 2 Feb 2026 16:17:33 +0100 Subject: [PATCH] BlendTreeEditor starts to be usable. --- blendalot_animation_graph.cpp | 9 +- blendalot_animation_graph.h | 1 + blendalot_animation_node.cpp | 77 +++++++--- blendalot_animation_node.h | 15 +- demo/addons/blendalot/blendalot_main_panel.gd | 78 ++++++---- .../blendalot/blendalot_main_panel.tscn | 7 +- demo/main.tscn | 145 ++++++++++++++++-- demo/synced_blend_tree_walk_limp.tres | 19 ++- demo/synced_blend_tree_walk_run.tres | 18 ++- tests/test_blendalot_animgraph.h | 1 + 10 files changed, 277 insertions(+), 93 deletions(-) diff --git a/blendalot_animation_graph.cpp b/blendalot_animation_graph.cpp index 079dc04..38d07aa 100644 --- a/blendalot_animation_graph.cpp +++ b/blendalot_animation_graph.cpp @@ -256,6 +256,8 @@ NodePath BLTAnimationGraph::get_animation_player() const { } void BLTAnimationGraph::set_root_animation_node(const Ref &p_animation_node) { + print_line(vformat("setting root node to node %s", p_animation_node->get_name())); + if (root_animation_node.is_valid()) { root_animation_node->disconnect(SNAME("node_changed"), callable_mp(this, &BLTAnimationGraph::_graph_changed)); } @@ -265,7 +267,6 @@ void BLTAnimationGraph::set_root_animation_node(const Ref &p_a if (root_animation_node.is_valid()) { _setup_graph(); root_animation_node->connect(SNAME("node_changed"), callable_mp(this, &BLTAnimationGraph::_graph_changed)); - print_line(vformat("connected node_changed event to graph %x", (uintptr_t)this)); } properties_dirty = true; @@ -298,7 +299,7 @@ NodePath BLTAnimationGraph::get_skeleton() const { } void BLTAnimationGraph::_process_graph(double p_delta, bool p_update_only) { - if (!root_animation_node.is_valid()) { + if (!root_animation_node.is_valid() || is_graph_initialization_valid == false) { return; } @@ -383,8 +384,8 @@ void BLTAnimationGraph::_setup_graph() { } print_line(vformat("_setup_graph() on graph %x and root node %x", (uintptr_t)(void *)(this), (uintptr_t)(root_animation_node.ptr()))); - - root_animation_node->initialize(graph_context); + is_graph_initialization_valid = root_animation_node->initialize(graph_context); + print_line(vformat("is_graph_initialization_valid = %s", is_graph_initialization_valid ? "true" : "false")); } BLTAnimationGraph::BLTAnimationGraph() { diff --git a/blendalot_animation_graph.h b/blendalot_animation_graph.h index 560ba2c..807d2c0 100644 --- a/blendalot_animation_graph.h +++ b/blendalot_animation_graph.h @@ -19,6 +19,7 @@ private: mutable AHashMap, StringName>> parameter_to_node_parameter_map; mutable bool properties_dirty = true; + bool is_graph_initialization_valid = false; void _update_properties() const; void _update_properties_for_node(const String &p_base_path, Ref p_node) const; diff --git a/blendalot_animation_node.cpp b/blendalot_animation_node.cpp index a1d55ea..6b7cc7e 100644 --- a/blendalot_animation_node.cpp +++ b/blendalot_animation_node.cpp @@ -274,36 +274,21 @@ bool BLTAnimationNodeSampler::initialize(GraphEvaluationContext &context) { } animation_player = context.animation_player; - if (animation_name.is_empty()) { - return true; + + if (animation_player == nullptr) { + return false; } - animation = animation_player->get_animation(animation_name); - if (!animation.is_valid()) { - print_error(vformat("Cannot initialize node %s: animation '%s' not found in animation player.", get_name(), animation_name)); + if (animation_name.is_empty()) { + return false; + } + + if (!set_animation(animation_name)) { return false; } context.animation_data_allocator.register_track_values(animation, context.skeleton_3d); - node_time_info.loop_mode = animation->get_loop_mode(); - - // Initialize Sync Track from marker - LocalVector sync_markers; - int marker_index = 0; - StringName marker_name = itos(marker_index); - while (animation->has_marker(marker_name)) { - sync_markers.push_back(animation->get_marker_time(marker_name)); - marker_index++; - marker_name = itos(marker_index); - } - - if (sync_markers.size() > 0) { - node_time_info.sync_track = SyncTrack::create_from_markers(animation->get_length(), sync_markers); - } else { - node_time_info.sync_track = SyncTrack::create_from_markers(animation->get_length(), { 0 }); - } - return true; } @@ -343,8 +328,52 @@ void BLTAnimationNodeSampler::set_animation_player(AnimationPlayer *p_player) { _node_changed(); } -void BLTAnimationNodeSampler::set_animation(const StringName &p_name) { +bool BLTAnimationNodeSampler::set_animation(const StringName &p_name) { + bool has_animation_name_changed = p_name != animation_name; animation_name = p_name; + + if (animation_player == nullptr) { + return false; + } + + if (!animation_player->has_animation(p_name)) { + if (has_animation_name_changed) { + _node_changed(); + } + return false; + } + + animation = animation_player->get_animation(p_name); + if (!animation.is_valid()) { + print_error(vformat("Cannot initialize node %s: animation '%s' not found in animation player.", get_name(), animation_name)); + + _node_changed(); + return false; + } + + node_time_info.loop_mode = animation->get_loop_mode(); + + // Initialize Sync Track from marker + LocalVector sync_markers; + int marker_index = 0; + StringName marker_name = itos(marker_index); + while (animation->has_marker(marker_name)) { + sync_markers.push_back(animation->get_marker_time(marker_name)); + marker_index++; + marker_name = itos(marker_index); + } + + if (sync_markers.size() > 0) { + node_time_info.sync_track = SyncTrack::create_from_markers(animation->get_length(), sync_markers); + } else { + node_time_info.sync_track = SyncTrack::create_from_markers(animation->get_length(), { 0 }); + } + + if (has_animation_name_changed) { + _node_changed(); + } + + return true; } StringName BLTAnimationNodeSampler::get_animation() const { diff --git a/blendalot_animation_node.h b/blendalot_animation_node.h index b187890..41e6922 100644 --- a/blendalot_animation_node.h +++ b/blendalot_animation_node.h @@ -348,7 +348,7 @@ public: AnimationPlayer *animation_player = nullptr; void set_animation_player(AnimationPlayer *p_player); - void set_animation(const StringName &p_name); + bool set_animation(const StringName &p_name); StringName get_animation() const; TypedArray get_animations_as_typed_array() const; @@ -394,6 +394,11 @@ public: node_time_info.loop_mode = Animation::LOOP_LINEAR; } + if (node_time_info.loop_mode != Animation::LOOP_LINEAR) { + print_line(vformat("Forcing loop mode to linear on nonde %s", get_name())); + node_time_info.loop_mode = Animation::LOOP_LINEAR; + } + return true; } void activate_inputs(const Vector> &input_nodes) override { @@ -421,9 +426,9 @@ public: if (!Math::is_zero_approx(node_time_info.sync_track.duration)) { node_time_info.position = Math::fposmod(static_cast(node_time_info.position), node_time_info.sync_track.duration); node_time_info.sync_position = node_time_info.sync_track.calc_sync_from_abs_time(node_time_info.position); - } else { - assert(false && !"Loop mode ping-pong not yet supported"); } + } else { + assert(false && !"Loop mode ping-pong not yet supported"); } } } @@ -690,6 +695,10 @@ public: return result; } + void _tree_node_changed(const StringName &node_name) { + _node_changed(); + } + // overrides from BLTAnimationNode bool initialize(GraphEvaluationContext &context) override { if (!BLTAnimationNode::initialize(context)) { diff --git a/demo/addons/blendalot/blendalot_main_panel.gd b/demo/addons/blendalot/blendalot_main_panel.gd index b8e943e..b25746d 100644 --- a/demo/addons/blendalot/blendalot_main_panel.gd +++ b/demo/addons/blendalot/blendalot_main_panel.gd @@ -7,6 +7,8 @@ extends Control @onready var tree_option_button: OptionButton = %TreeOptionButton @onready var add_node_popup_menu: PopupMenu = %AddNodePopupMenu +var root_animation_node:BLTAnimationNode = null +var last_edited_graph_node:GraphNode = null var blend_tree:BLTAnimationNodeBlendTree = BLTAnimationNodeBlendTree.new() var blend_tree_node_to_graph_node = {} var graph_node_to_blend_tree_node = {} @@ -31,6 +33,7 @@ func _ready() -> void: func _process(delta: float) -> void: pass + func create_node_for_blt_node(blt_node: BLTAnimationNode) -> GraphNode: var result_graph_node:GraphNode = GraphNode.new() result_graph_node.name = blt_node.resource_name @@ -53,15 +56,41 @@ func create_node_for_blt_node(blt_node: BLTAnimationNode) -> GraphNode: result_graph_node.add_child(slot_label) result_graph_node.set_slot(i + result_slot_offset, true, 1, Color.WHITE, false, 1, Color.BLACK) + blt_node.node_changed.connect(_triggrer_animation_graph_initialize) + return result_graph_node -func _on_add_node_button_pressed() -> void: - blend_tree_graph_edit.add_child(create_node_for_blt_node(BLTAnimationNodeOutput.new())) - blend_tree_graph_edit.add_child(create_node_for_blt_node(BLTAnimationNodeBlend2.new())) +func _on_blend_tree_graph_edit_delete_nodes_request(nodes: Array[StringName]) -> void: + for node_name:StringName in nodes: + print("remove node '%s'" % node_name) + var blend_tree_node:BLTAnimationNode = blend_tree.get_node(node_name) + + if blend_tree_node == null: + push_error("Cannot delete node '%s': node not found." % node_name) + continue + + if blend_tree_node == blend_tree.get_output_node(): + push_warning("Output node not allowed to be removed.") + continue + + blend_tree_node.node_changed.disconnect(_triggrer_animation_graph_initialize) + + var graph_node:GraphNode = blend_tree_node_to_graph_node[blend_tree_node] + blend_tree.remove_node(blend_tree_node) + blend_tree_node_to_graph_node.erase(blend_tree_node) + + _blend_tree_graph_edit_remove_node_connections(graph_node) + graph_node_to_blend_tree_node.erase(graph_node) + blend_tree_graph_edit.remove_child(graph_node) + _on_blend_tree_graph_edit_node_deselected(graph_node) + + EditorInterface.get_inspector().edit(null) func _on_reset_graph_button_pressed() -> void: + EditorInterface.get_inspector().edit(null) + _reset_editor() _update_editor_from_blend_tree() @@ -89,11 +118,13 @@ func edit_blend_tree(blend_tree_animation_node:BLTAnimationNode): print("Starting to edit blend_tree_animation_node " + str(blend_tree_animation_node)) print("Owner: %s" % blend_tree_animation_node) _reset_editor() + root_animation_node = blend_tree_animation_node blend_tree = blend_tree_animation_node _update_editor_nodes_from_blend_tree() _update_editor_connections_from_blend_tree() + func _update_editor_nodes_from_blend_tree(): for node_name in blend_tree.get_node_names(): var blend_tree_node:BLTAnimationNode = blend_tree.get_node(node_name) @@ -207,6 +238,7 @@ func _on_blend_tree_graph_edit_begin_node_move() -> void: func _on_blend_tree_graph_edit_node_selected(graph_node: Node) -> void: selected_nodes[graph_node] = graph_node + last_edited_graph_node = graph_node EditorInterface.get_inspector().edit(graph_node_to_blend_tree_node[graph_node]) @@ -224,14 +256,14 @@ func _on_blend_tree_graph_edit_popup_request(at_position: Vector2) -> void: func _on_add_node_popup_menu_index_pressed(index: int) -> void: var new_blend_tree_node: BLTAnimationNode = ClassDB.instantiate(registered_nodes[index]) - blend_tree.add_node(new_blend_tree_node) + blend_tree.add_node(new_blend_tree_node) + var graph_node:GraphNode = create_node_for_blt_node(new_blend_tree_node) + blend_tree_graph_edit.add_child(graph_node) graph_node_to_blend_tree_node[graph_node] = new_blend_tree_node blend_tree_node_to_graph_node[new_blend_tree_node] = graph_node - blend_tree_graph_edit.add_child(graph_node) - if new_node_position != Vector2.INF: graph_node.position_offset = new_node_position @@ -250,31 +282,6 @@ func _blend_tree_graph_edit_remove_node_connections(graph_node:GraphNode): blend_tree_graph_edit.disconnect_node(node_connection["from_node"], node_connection["from_port"], node_connection["to_node"], node_connection["to_port"]) -func _on_blend_tree_graph_edit_delete_nodes_request(nodes: Array[StringName]) -> void: - for node_name:StringName in nodes: - print("remove node '%s'" % node_name) - var blend_tree_node:BLTAnimationNode = blend_tree.get_node(node_name) - - if blend_tree_node == null: - push_error("Cannot delete node '%s': node not found." % node_name) - continue - - if blend_tree_node == blend_tree.get_output_node(): - push_warning("Output node not allowed to be removed.") - continue - - var graph_node:GraphNode = blend_tree_node_to_graph_node[blend_tree_node] - blend_tree.remove_node(blend_tree_node) - blend_tree_node_to_graph_node.erase(blend_tree_node) - - _blend_tree_graph_edit_remove_node_connections(graph_node) - graph_node_to_blend_tree_node.erase(graph_node) - blend_tree_graph_edit.remove_child(graph_node) - _on_blend_tree_graph_edit_node_deselected(graph_node) - - EditorInterface.get_inspector().edit(null) - - func _on_blend_tree_graph_edit_disconnection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void: print("removing connection") @@ -284,3 +291,12 @@ func _on_blend_tree_graph_edit_disconnection_request(from_node: StringName, from blend_tree.remove_connection(blend_tree_source_node, blend_tree_target_node, target_port_name) blend_tree_graph_edit.disconnect_node(from_node, from_port, to_node, to_port) + + +func _trigger_animation_graph_initialize(node_name:StringName) -> void: + root_animation_node.node_changed.emit("root") + + +func _on_visibility_changed() -> void: + if visible and is_instance_valid(last_edited_graph_node): + _on_blend_tree_graph_edit_node_selected(last_edited_graph_node) diff --git a/demo/addons/blendalot/blendalot_main_panel.tscn b/demo/addons/blendalot/blendalot_main_panel.tscn index 78b70ad..bc0b98e 100644 --- a/demo/addons/blendalot/blendalot_main_panel.tscn +++ b/demo/addons/blendalot/blendalot_main_panel.tscn @@ -47,10 +47,10 @@ size_flags_horizontal = 0 text = "Load " -[node name="AddNodeButton" type="Button" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=985452697] +[node name="ReinitializeButton" type="Button" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=719949205] layout_mode = 2 size_flags_horizontal = 0 -text = "Add Node" +text = "Reinitialize" [node name="TreeOptionButton" type="OptionButton" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=760974122] unique_name_in_owner = true @@ -92,10 +92,11 @@ grow_horizontal = 2 grow_vertical = 2 right_disconnects = true +[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"] [connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/ResetGraphButton" to="." method="_on_reset_graph_button_pressed"] [connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/SaveButton" to="." method="_on_save_button_pressed"] [connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/LoadButton" to="." method="_on_load_button_pressed"] -[connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/AddNodeButton" to="." method="_on_add_node_button_pressed"] +[connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/ReinitializeButton" to="." method="_trigger_animation_graph_initialize"] [connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/InstantiateTreeButton" to="." method="_on_instantiate_tree_button_pressed"] [connection signal="index_pressed" from="BlendTreeEditorContainer/Panel/AddNodePopupMenu" to="." method="_on_add_node_popup_menu_index_pressed"] [connection signal="begin_node_move" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_begin_node_move"] diff --git a/demo/main.tscn b/demo/main.tscn index 1d1932f..e766978 100644 --- a/demo/main.tscn +++ b/demo/main.tscn @@ -4,8 +4,9 @@ [ext_resource type="Script" uid="uid://bjvgqujpqumj7" path="res://main.gd" id="1_1bvp3"] [ext_resource type="AnimationLibrary" uid="uid://dwubn740aqx51" path="res://animation_library.res" id="3_1bvp3"] [ext_resource type="AnimationNodeBlendTree" uid="uid://dqy0dgwsm8t46" path="res://animation_tree_walk_limp.tres" id="3_272bh"] -[ext_resource type="BLTAnimationNodeBlendTree" uid="uid://2qfwr1xkiw0s" path="res://synced_blend_tree_walk_limp.tres" id="4_lquwl"] [ext_resource type="AnimationNodeBlendTree" uid="uid://vsf71o82lkld" path="res://animation_tree_walk_run.tres" id="6_5vw27"] +[ext_resource type="BLTAnimationNodeBlendTree" uid="uid://2qfwr1xkiw0s" path="res://synced_blend_tree_walk_limp.tres" id="6_272bh"] +[ext_resource type="BLTAnimationNodeBlendTree" uid="uid://qsk64ax2o47f" path="res://synced_blend_tree_walk_run.tres" id="7_272bh"] [sub_resource type="Theme" id="Theme_272bh"] default_font_size = 30 @@ -31,17 +32,6 @@ sky = SubResource("Sky_1bvp3") tonemap_mode = 2 glow_enabled = true -[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_7mycd"] -resource_name = "BLTAnimationNodeSampler" -position = Vector2(149.47485, 361.29053) -animation = &"animation_library/Walk-InPlace" - -[sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_272bh"] -nodes/Output/position = Vector2(602.0149, 281.4305) -nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_7mycd") -nodes/BLTAnimationNodeSampler/position = Vector2(149.47485, 361.29053) -node_connections = ["Output", 0, "BLTAnimationNodeSampler"] - [node name="Main" type="Node3D" unique_id=933302313] script = ExtResource("1_1bvp3") @@ -157,22 +147,145 @@ libraries/animation_library = ExtResource("3_1bvp3") [node name="SyncedAnimationGraph" type="BLTAnimationGraph" parent="Characters/MixamoAmyWalkLimpSynced" unique_id=1866796918] animation_player = NodePath("../AnimationPlayer2") -tree_root = ExtResource("4_lquwl") +tree_root = ExtResource("6_272bh") skeleton = NodePath("../Armature/Skeleton3D") -parameters/BLTAnimationNodeBlend2/blend_amount = 0.4 +parameters/BLTAnimationNodeBlend2/blend_amount = 1.0 [node name="MixamoAmyWalkRunSynced" parent="Characters" unique_id=2088190993 instance=ExtResource("1_0xm2m")] unique_name_in_owner = true transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4, 0, 0) -[node name="AnimationPlayer2" type="AnimationPlayer" parent="Characters/MixamoAmyWalkRunSynced" unique_id=1255239074] +[node name="Skeleton3D" parent="Characters/MixamoAmyWalkRunSynced/Armature" parent_id_path=PackedInt32Array(2088190993, 52334938) index="0" unique_id=2014991417] +bones/0/position = Vector3(2.3944292, 58.292915, 0) +bones/2/position = Vector3(2.3954058, -1.2283401, -67.867485) +bones/2/rotation = Quaternion(-0.7015852, -0.016084917, 0.002894751, 0.7123981) +bones/3/position = Vector3(1.8626451e-08, 3.9624305, -0.274297) +bones/3/rotation = Quaternion(-0.019988505, 0.0068857046, -0.0031864278, 0.9997697) +bones/4/position = Vector3(5.9604645e-08, 14.123348, 0.2644268) +bones/4/rotation = Quaternion(0.0014081367, 0.015367857, -0.008578158, 0.9998441) +bones/5/position = Vector3(3.7252903e-08, 11.404536, 0.106110305) +bones/5/rotation = Quaternion(0.0014081355, 0.0153678525, -0.0085781645, 0.9998441) +bones/6/position = Vector3(2.9802322e-08, 9.946667, 1.6090326e-08) +bones/6/rotation = Quaternion(0.039844688, -0.0022483557, 0.009721856, 0.9991561) +bones/7/position = Vector3(3.1292439e-07, 8.579114, 0.11416777) +bones/7/rotation = Quaternion(0.018197661, -0.0028079022, 0.025565712, 0.99950355) +bones/8/position = Vector3(1.8626451e-09, 25.089184, 0.33387405) +bones/9/position = Vector3(4.22409, 8.898366, -0.056614783) +bones/9/rotation = Quaternion(0.69302666, 0.2985537, -0.5364231, 0.3779267) +bones/10/position = Vector3(7.763405e-07, 8.86101, -1.885943e-05) +bones/10/rotation = Quaternion(0.36105165, -0.046350844, -0.1645193, 0.91674787) +bones/11/position = Vector3(-6.736064e-08, 18.975187, -5.359281e-06) +bones/11/rotation = Quaternion(0.03416674, 0.15374418, 0.242136, 0.9573729) +bones/12/position = Vector3(2.0505329e-06, 19.896036, 4.198435e-06) +bones/12/rotation = Quaternion(-0.02613752, 0.22233193, -0.068033114, 0.97224313) +bones/13/position = Vector3(-2.0888743, 2.1412597, 1.2094326) +bones/13/rotation = Quaternion(0.25766087, -0.0057431525, 0.24790713, 0.93387365) +bones/14/position = Vector3(-0.3297696, 2.5601492, 5.6111962e-06) +bones/14/rotation = Quaternion(-0.02088847, -0.0012659901, -0.06479406, 0.9976792) +bones/15/position = Vector3(0.07692051, 2.7271638, -7.698024e-07) +bones/15/rotation = Quaternion(0.041175473, -5.169663e-07, -3.3207877e-07, 0.99915195) +bones/16/position = Vector3(0.25285125, 2.2376482, -2.5033949e-06) +bones/17/position = Vector3(-2.5860305, 6.9422946, 0.029643927) +bones/17/rotation = Quaternion(0.3595198, 0.019201318, 0.093114324, 0.9282804) +bones/18/position = Vector3(0.0010065138, 2.844871, 2.6222544e-05) +bones/18/rotation = Quaternion(0.5266805, -0.009538538, 0.050116353, 0.8485306) +bones/19/position = Vector3(-0.001300633, 2.6654923, -3.370296e-06) +bones/19/rotation = Quaternion(0.0067229928, -1.8172469e-07, -1.12402185e-08, 0.9999774) +bones/20/position = Vector3(0.00029665232, 2.2974284, 2.6011842e-06) +bones/21/position = Vector3(-0.81500757, 6.8271494, -0.11008961) +bones/21/rotation = Quaternion(0.4838051, -0.02263074, 0.097104214, 0.86947656) +bones/22/position = Vector3(-0.011725575, 3.256784, 9.871595e-06) +bones/22/rotation = Quaternion(0.70388824, -0.007956969, 0.07827657, 0.70593894) +bones/23/position = Vector3(-0.00070961565, 3.1778917, -4.440292e-06) +bones/23/rotation = Quaternion(0.05807299, -2.1569534e-08, -4.8931874e-08, 0.99831235) +bones/24/position = Vector3(0.012437165, 2.6951318, 2.2368273e-05) +bones/25/position = Vector3(0.89882326, 6.7787366, -0.023027958) +bones/25/rotation = Quaternion(0.47609472, -0.10504542, 0.00788891, 0.87306076) +bones/26/position = Vector3(-0.0040293336, 2.958041, 1.3685599e-05) +bones/26/rotation = Quaternion(0.71283627, 0.0028766363, 0.06198941, 0.69857895) +bones/27/position = Vector3(0.0024927258, 2.756927, -1.8636636e-05) +bones/27/rotation = Quaternion(-0.0033205294, 3.9059813e-08, 6.5682637e-09, 0.9999945) +bones/28/position = Vector3(0.0015397072, 2.3345788, 1.1771219e-05) +bones/29/position = Vector3(2.5022223, 6.3907866, 0.08744741) +bones/29/rotation = Quaternion(0.5714825, -0.1510222, 0.0009240997, 0.8065963) +bones/30/position = Vector3(0.0032016933, 2.6237173, 5.5511973e-06) +bones/30/rotation = Quaternion(0.638921, 0.023284703, 0.05857911, 0.7666847) +bones/31/position = Vector3(0.003878951, 2.1320877, -1.2886679e-06) +bones/31/rotation = Quaternion(-0.06925962, -1.0360488e-07, -7.0190005e-08, 0.9975987) +bones/32/position = Vector3(-0.0070759356, 1.7932303, -8.8289596e-07) +bones/33/position = Vector3(-4.2240915, 8.897269, -0.030230172) +bones/33/rotation = Quaternion(0.65103245, -0.34380102, 0.56754214, 0.36858305) +bones/34/position = Vector3(9.327891e-07, 8.8610115, -9.847447e-06) +bones/34/rotation = Quaternion(0.4207574, -0.005679023, 0.07089772, 0.9043808) +bones/35/position = Vector3(6.476337e-07, 18.973557, 5.8403616e-06) +bones/35/rotation = Quaternion(-0.0409054, -0.11762145, -0.36220855, 0.92374086) +bones/36/position = Vector3(-7.630494e-08, 19.89834, -1.8180976e-06) +bones/36/rotation = Quaternion(-0.18468891, -0.12580799, -0.09516018, 0.97005504) +bones/37/position = Vector3(2.0620086, 2.1477072, 1.2410417) +bones/37/rotation = Quaternion(0.1984708, 0.031765047, -0.28800797, 0.9362969) +bones/38/position = Vector3(0.2744484, 2.5658755, 3.7584634e-06) +bones/38/rotation = Quaternion(0.081494935, -0.19653738, 0.11717984, 0.9700518) +bones/39/position = Vector3(-0.076725245, 2.730221, -7.234994e-06) +bones/39/rotation = Quaternion(0.037325032, -2.1781963e-08, 1.19075e-07, 0.99930316) +bones/40/position = Vector3(-0.19772077, 2.2442596, 9.685756e-06) +bones/41/position = Vector3(2.5699375, 7.0537868, 0.05093465) +bones/41/rotation = Quaternion(0.48021728, 0.0082633095, -0.045813248, 0.87591136) +bones/42/position = Vector3(-0.0015108623, 2.816315, -9.529522e-06) +bones/42/rotation = Quaternion(0.6120701, 0.02828741, -0.048200864, 0.78882384) +bones/43/position = Vector3(0.0011758618, 2.6396425, 2.472788e-06) +bones/43/rotation = Quaternion(0.0026853334, 3.311302e-08, -5.8677845e-08, 0.9999965) +bones/44/position = Vector3(0.00033191964, 2.2415001, 1.3194513e-06) +bones/45/position = Vector3(0.76549155, 7.018211, -0.09038047) +bones/45/rotation = Quaternion(0.49598414, 0.036653362, -0.038273394, 0.8667126) +bones/46/position = Vector3(0.008488461, 3.3401706, -6.017696e-06) +bones/46/rotation = Quaternion(0.70486575, 0.040216748, -0.058438864, 0.70578283) +bones/47/position = Vector3(-0.007900611, 3.0566626, 5.4270527e-06) +bones/47/rotation = Quaternion(-0.027461762, -2.0760188e-08, 5.6872928e-08, 0.9996229) +bones/48/position = Vector3(-0.00058989227, 2.63951, 9.457464e-06) +bones/49/position = Vector3(-0.8923034, 6.9110794, -0.12160769) +bones/49/rotation = Quaternion(0.49361324, 0.033564895, -0.017181082, 0.86886364) +bones/50/position = Vector3(-0.00297606, 2.923956, 1.7109673e-05) +bones/50/rotation = Quaternion(0.69540185, -0.01958265, -0.069078155, 0.7150251) +bones/51/position = Vector3(0.0026345253, 2.717951, -5.427028e-06) +bones/51/rotation = Quaternion(0.009096339, 7.025756e-08, 2.6579988e-08, 0.99995863) +bones/52/position = Vector3(0.0003426671, 2.379634, 1.4747493e-06) +bones/53/position = Vector3(-2.4431183, 6.453577, 0.12551774) +bones/53/rotation = Quaternion(0.45701033, 0.026051568, -0.02899594, 0.8886062) +bones/54/position = Vector3(-0.0026362836, 2.6278691, 4.2827646e-06) +bones/54/rotation = Quaternion(0.7443899, -0.044672288, -0.09278318, 0.6597555) +bones/55/position = Vector3(-0.001860708, 2.1224687, 9.940322e-07) +bones/55/rotation = Quaternion(-0.03619139, -1.1229469e-07, 2.121775e-08, 0.9993449) +bones/56/position = Vector3(0.004502952, 1.7919822, 1.2924895e-05) +bones/57/position = Vector3(7.557004, -4.826265, 0.30053553) +bones/57/rotation = Quaternion(-0.063634895, -0.18599084, -0.9804429, 0.009476706) +bones/58/position = Vector3(-0.124621816, 24.06574, 0.10470339) +bones/58/rotation = Quaternion(-0.25773793, 0.06259592, -0.01817601, 0.9640138) +bones/59/position = Vector3(-0.0060171685, 33.063114, 0.00394835) +bones/59/rotation = Quaternion(0.5448946, 0.0072068824, 0.026147991, 0.83806586) +bones/60/position = Vector3(-0.0052775713, 12.893309, -0.5155027) +bones/60/rotation = Quaternion(0.3145146, -0.058151364, 0.021719113, 0.9472208) +bones/61/position = Vector3(0.014227723, 6.420835, 0.007887725) +bones/62/position = Vector3(-7.557004, -4.826261, 0.30053535) +bones/62/rotation = Quaternion(-0.072349995, 0.14396061, 0.98645425, 0.030805206) +bones/63/position = Vector3(0.12476807, 24.070103, -0.14491707) +bones/63/rotation = Quaternion(-0.49734375, 0.011248301, -0.008667116, 0.86743724) +bones/64/position = Vector3(0.0060205855, 33.063133, 0.004499323) +bones/64/rotation = Quaternion(0.33301854, -0.06086632, -0.07533557, 0.9379331) +bones/65/position = Vector3(0.005378528, 12.718271, -0.52236915) +bones/65/rotation = Quaternion(0.49081448, 0.17055358, 0.0037184241, 0.8543996) +bones/66/position = Vector3(-0.014239848, 6.412128, 0.0079107955) + +[node name="AnimationPlayer" parent="Characters/MixamoAmyWalkRunSynced" index="1" unique_id=945472897] active = false + +[node name="AnimationPlayer2" type="AnimationPlayer" parent="Characters/MixamoAmyWalkRunSynced" unique_id=1255239074] libraries/animation_library = ExtResource("3_1bvp3") [node name="SyncedAnimationGraph" type="BLTAnimationGraph" parent="Characters/MixamoAmyWalkRunSynced" unique_id=1602406394] animation_player = NodePath("../AnimationPlayer2") -tree_root = SubResource("BLTAnimationNodeBlendTree_272bh") +tree_root = ExtResource("7_272bh") skeleton = NodePath("../Armature/Skeleton3D") +parameters/BLTAnimationNodeBlend2/blend_amount = 0.0 [connection signal="value_changed" from="UI/MarginContainer/HBoxContainer/BlendWeightSlider" to="." method="_on_blend_weight_slider_value_changed"] diff --git a/demo/synced_blend_tree_walk_limp.tres b/demo/synced_blend_tree_walk_limp.tres index fd2c576..20ac3b2 100644 --- a/demo/synced_blend_tree_walk_limp.tres +++ b/demo/synced_blend_tree_walk_limp.tres @@ -1,19 +1,26 @@ -[gd_resource type="BLTAnimationNodeBlendTree" load_steps=4 format=3 uid="uid://2qfwr1xkiw0s"] +[gd_resource type="BLTAnimationNodeBlendTree" format=3 uid="uid://2qfwr1xkiw0s"] [sub_resource type="BLTAnimationNodeBlend2" id="BLTAnimationNodeBlend2_bvt3d"] -blend_amount = 0.4 +resource_name = "BLTAnimationNodeBlend2" +position = Vector2(950.50195, 749.8301) +blend_amount = 1.0 [sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_sntl5"] +resource_name = "BLTAnimationNodeSampler 1" +position = Vector2(101.323975, 1247.624) animation = &"animation_library/Limping-InPlace" [sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_n4m28"] +resource_name = "BLTAnimationNodeSampler" +position = Vector2(101.323975, 398.44608) animation = &"animation_library/Walk-InPlace" [resource] +nodes/Output/position = Vector2(1741.1158, 925.52203) nodes/BLTAnimationNodeBlend2/node = SubResource("BLTAnimationNodeBlend2_bvt3d") -nodes/BLTAnimationNodeBlend2/position = Vector2(0, 0) +nodes/BLTAnimationNodeBlend2/position = Vector2(950.50195, 749.8301) "nodes/BLTAnimationNodeSampler 1/node" = SubResource("BLTAnimationNodeSampler_sntl5") -"nodes/BLTAnimationNodeSampler 1/position" = Vector2(0, 0) +"nodes/BLTAnimationNodeSampler 1/position" = Vector2(101.323975, 1247.624) nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_n4m28") -nodes/BLTAnimationNodeSampler/position = Vector2(0, 0) -node_connections = [&"BLTAnimationNodeBlend2", 0, &"BLTAnimationNodeSampler", &"BLTAnimationNodeBlend2", 1, &"BLTAnimationNodeSampler 1", &"Output", 0, &"BLTAnimationNodeBlend2"] +nodes/BLTAnimationNodeSampler/position = Vector2(101.323975, 398.44608) +node_connections = ["BLTAnimationNodeBlend2", 0, "BLTAnimationNodeSampler", "BLTAnimationNodeBlend2", 1, "BLTAnimationNodeSampler 1", "Output", 0, "BLTAnimationNodeBlend2"] diff --git a/demo/synced_blend_tree_walk_run.tres b/demo/synced_blend_tree_walk_run.tres index 10d6c6e..5728f70 100644 --- a/demo/synced_blend_tree_walk_run.tres +++ b/demo/synced_blend_tree_walk_run.tres @@ -1,19 +1,25 @@ -[gd_resource type="BLTAnimationNodeBlendTree" load_steps=4 format=3 uid="uid://qsk64ax2o47f"] +[gd_resource type="BLTAnimationNodeBlendTree" format=3 uid="uid://qsk64ax2o47f"] [sub_resource type="BLTAnimationNodeBlend2" id="BLTAnimationNodeBlend2_bvt3d"] -blend_amount = 0.4 +resource_name = "BLTAnimationNodeBlend2" +position = Vector2(-420, 220) [sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_sntl5"] +resource_name = "BLTAnimationNodeSampler 1" +position = Vector2(-1020, 380) animation = &"animation_library/Run-InPlace" [sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_n4m28"] +resource_name = "BLTAnimationNodeSampler" +position = Vector2(-880, 0) animation = &"animation_library/Walk-InPlace" [resource] +nodes/Output/position = Vector2(180, 80) nodes/BLTAnimationNodeBlend2/node = SubResource("BLTAnimationNodeBlend2_bvt3d") -nodes/BLTAnimationNodeBlend2/position = Vector2(0, 0) +nodes/BLTAnimationNodeBlend2/position = Vector2(-420, 220) "nodes/BLTAnimationNodeSampler 1/node" = SubResource("BLTAnimationNodeSampler_sntl5") -"nodes/BLTAnimationNodeSampler 1/position" = Vector2(0, 0) +"nodes/BLTAnimationNodeSampler 1/position" = Vector2(-1020, 380) nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_n4m28") -nodes/BLTAnimationNodeSampler/position = Vector2(0, 0) -node_connections = [&"BLTAnimationNodeBlend2", 0, &"BLTAnimationNodeSampler", &"BLTAnimationNodeBlend2", 1, &"BLTAnimationNodeSampler 1", &"Output", 0, &"BLTAnimationNodeBlend2"] +nodes/BLTAnimationNodeSampler/position = Vector2(-880, 0) +node_connections = ["BLTAnimationNodeBlend2", 0, "BLTAnimationNodeSampler", "BLTAnimationNodeBlend2", 1, "BLTAnimationNodeSampler 1", "Output", 0, "BLTAnimationNodeBlend2"] diff --git a/tests/test_blendalot_animgraph.h b/tests/test_blendalot_animgraph.h index 4bed159..bc6c5e6 100644 --- a/tests/test_blendalot_animgraph.h +++ b/tests/test_blendalot_animgraph.h @@ -542,6 +542,7 @@ TEST_CASE_FIXTURE(BlendTreeFixture, "[SceneTree][Blendalot][BlendTreeGraph][Chan int num_connections = blend_tree_graph.connections.size(); CHECK(blend_tree_graph.remove_node(blend_tree_graph.get_output_node()) == false); CHECK(blend_tree_graph.connections.size() == num_connections); + CHECK(blend_tree_graph.nodes.size() == num_nodes); } SUBCASE("Remove a node with no children") {