Compare commits
No commits in common. "095f1e5d0cead88e4f06ddc0d88066efc1e12098" and "be6e021198d7ab8406bc63405dd8898573ff22bc" have entirely different histories.
095f1e5d0c
...
be6e021198
@ -257,7 +257,8 @@ public:
|
||||
double sync_position = 0.0;
|
||||
bool is_synced = false;
|
||||
|
||||
Animation::LoopMode loop_mode = Animation::LOOP_NONE;
|
||||
// TODO: 2026-02-17: how to initialize loop_mode e.g. for a BlendTree or a StateMachine?
|
||||
Animation::LoopMode loop_mode = Animation::LOOP_LINEAR;
|
||||
SyncTrack sync_track;
|
||||
};
|
||||
NodeTimeInfo node_time_info;
|
||||
@ -350,7 +351,6 @@ public:
|
||||
void set_animation_player(AnimationPlayer *p_player);
|
||||
bool set_animation(const StringName &p_name);
|
||||
StringName get_animation() const;
|
||||
AnimationPlayer *get_animation_player() const;
|
||||
|
||||
TypedArray<StringName> get_animations_as_typed_array() const;
|
||||
|
||||
@ -753,8 +753,6 @@ public:
|
||||
}
|
||||
|
||||
tree_graph.nodes[0]->active = true;
|
||||
tree_graph.nodes[0]->node_time_info.is_synced = node_time_info.is_synced;
|
||||
|
||||
for (uint32_t i = 0; i < tree_graph.nodes.size(); i++) {
|
||||
const Ref<BLTAnimationNode> &node = tree_graph.nodes[i];
|
||||
|
||||
@ -779,21 +777,14 @@ public:
|
||||
const NodeRuntimeData &node_runtime_data = _node_runtime_data[i];
|
||||
|
||||
node->calculate_sync_track(node_runtime_data.input_nodes);
|
||||
|
||||
if (i == 1) {
|
||||
node_time_info = node->node_time_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_time(double p_delta) override {
|
||||
GodotProfileZone("SyncedBlendTree::update_time");
|
||||
|
||||
BLTAnimationNode::update_time(p_delta);
|
||||
|
||||
tree_graph.nodes[0]->node_time_info.delta = node_time_info.delta;
|
||||
tree_graph.nodes[0]->node_time_info.position = node_time_info.position;
|
||||
tree_graph.nodes[0]->node_time_info.sync_position = node_time_info.sync_position;
|
||||
tree_graph.nodes[0]->node_time_info.delta = p_delta;
|
||||
tree_graph.nodes[0]->node_time_info.position += p_delta;
|
||||
|
||||
for (uint32_t i = 1; i < tree_graph.nodes.size(); i++) {
|
||||
const Ref<BLTAnimationNode> &node = tree_graph.nodes[i];
|
||||
|
||||
@ -6,13 +6,12 @@ class_name AnimationGraphEditor
|
||||
@onready var breadcrumb_button_container: HBoxContainer = %BreadcrumbButtons
|
||||
@onready var active_graph_control: Control = %ActiveGraphControl
|
||||
|
||||
var animation_graph:BLTAnimationGraph = null
|
||||
var active_animation_graph_node:BLTAnimationGraph = null
|
||||
var animation_graph_root_node:BLTAnimationNode = null
|
||||
var graph_node_stack:Array[BLTAnimationNode] = []
|
||||
var active_graph_edit:Control = null
|
||||
var active_graph_edit_index = -1
|
||||
|
||||
|
||||
func reset_graph_control():
|
||||
for child in active_graph_control.get_children():
|
||||
active_graph_control.remove_child(child)
|
||||
@ -20,7 +19,6 @@ func reset_graph_control():
|
||||
|
||||
|
||||
func edit_animation_root_node(blt_node:BLTAnimationNode):
|
||||
print("Setting root node")
|
||||
graph_node_stack = []
|
||||
active_graph_edit_index = -1
|
||||
truncate_graph_stack(0)
|
||||
@ -31,9 +29,6 @@ func edit_animation_root_node(blt_node:BLTAnimationNode):
|
||||
animation_graph_root_node = blt_node
|
||||
push_graph_stack(blt_node)
|
||||
edit_graph(blt_node)
|
||||
return
|
||||
|
||||
assert(is_instance_valid(animation_graph))
|
||||
|
||||
push_warning("Cannot edit node %s. Graph type %s not yet supported." % [blt_node.resource_name, blt_node.get_class()])
|
||||
|
||||
|
||||
@ -105,25 +105,12 @@ func create_graph_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)
|
||||
|
||||
if blt_node.get_class() == "BLTAnimationNodeSampler":
|
||||
var animation_sampler_node:BLTAnimationNodeSampler = blt_node as BLTAnimationNodeSampler
|
||||
var animation_selector_button = OptionButton.new()
|
||||
var animation_player:AnimationPlayer = animation_sampler_node.get_animation_player()
|
||||
for animation_name in animation_player.get_animation_list():
|
||||
animation_selector_button.add_item(animation_name)
|
||||
if animation_name == animation_sampler_node.animation:
|
||||
animation_selector_button.select(animation_selector_button.item_count - 1)
|
||||
|
||||
animation_selector_button.item_selected.connect(_on_animation_select.bind(animation_sampler_node, animation_selector_button))
|
||||
|
||||
result_graph_node.add_child(animation_selector_button)
|
||||
|
||||
blt_node.node_changed.connect(_trigger_graph_changed)
|
||||
|
||||
return result_graph_node
|
||||
|
||||
|
||||
func _trigger_graph_changed(_node_name):
|
||||
func _trigger_graph_changed():
|
||||
graph_changed.emit()
|
||||
|
||||
|
||||
@ -167,15 +154,6 @@ func _on_blend_tree_graph_edit_connection_request(from_node: StringName, from_po
|
||||
print("Success!")
|
||||
|
||||
|
||||
func _on_blend_tree_graph_edit_disconnection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void:
|
||||
var blend_tree_source_node = blend_tree.get_node(from_node)
|
||||
var blend_tree_target_node = blend_tree.get_node(to_node)
|
||||
var target_port_name = blend_tree_target_node.get_input_names()[to_port]
|
||||
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 _on_blend_tree_graph_edit_delete_nodes_request(nodes: Array[StringName]) -> void:
|
||||
for node_name:StringName in nodes:
|
||||
print("remove node '%s'" % node_name)
|
||||
@ -220,7 +198,6 @@ func _on_blend_tree_graph_edit_node_selected(graph_node: Node) -> void:
|
||||
|
||||
|
||||
func _on_blend_tree_graph_edit_scroll_offset_changed(offset: Vector2) -> void:
|
||||
if is_instance_valid(blend_tree):
|
||||
blend_tree.graph_offset = offset
|
||||
|
||||
|
||||
@ -266,10 +243,3 @@ func _on_node_double_click(graph_node:GraphNode):
|
||||
|
||||
if blend_tree_node is BLTAnimationNodeBlendTree:
|
||||
edit_subgraph.emit(blend_tree_node)
|
||||
|
||||
#
|
||||
# Animation selection for BltAnimationNodeSampler
|
||||
#
|
||||
func _on_animation_select(index:int, blt_node_sampler:BLTAnimationNodeSampler, option_button:OptionButton):
|
||||
blt_node_sampler.animation = option_button.get_item_text(index)
|
||||
blt_node_sampler.node_changed.emit(blt_node_sampler.resource_name)
|
||||
|
||||
@ -44,7 +44,6 @@ right_disconnects = true
|
||||
[connection signal="index_pressed" from="Panel/AddNodePopupMenu" to="." method="_on_add_node_popup_menu_index_pressed"]
|
||||
[connection signal="connection_request" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_connection_request"]
|
||||
[connection signal="delete_nodes_request" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_delete_nodes_request"]
|
||||
[connection signal="disconnection_request" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_disconnection_request"]
|
||||
[connection signal="end_node_move" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_end_node_move"]
|
||||
[connection signal="node_deselected" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_node_deselected"]
|
||||
[connection signal="node_selected" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_node_selected"]
|
||||
|
||||
@ -8,28 +8,7 @@ animation = &"Walk-InPlace"
|
||||
|
||||
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_lquwl"]
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_vyt75"]
|
||||
|
||||
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_hom0r"]
|
||||
|
||||
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_vyt75"]
|
||||
|
||||
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_1rfsi"]
|
||||
nodes/BlendTree/node = SubResource("AnimationNodeBlendTree_vyt75")
|
||||
nodes/BlendTree/position = Vector2(694.9995, 215.55058)
|
||||
|
||||
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_8tpve"]
|
||||
graph_offset = Vector2(-782, 179.47485)
|
||||
nodes/Animation/node = SubResource("AnimationNodeAnimation_vyt75")
|
||||
nodes/Animation/position = Vector2(-320, 140)
|
||||
nodes/Blend2/node = SubResource("AnimationNodeBlend2_hom0r")
|
||||
nodes/Blend2/position = Vector2(-115.66393, 127.37674)
|
||||
nodes/BlendTree/node = SubResource("AnimationNodeBlendTree_1rfsi")
|
||||
nodes/BlendTree/position = Vector2(-480, 400)
|
||||
node_connections = [&"output", 0, &"Blend2", &"Blend2", 0, &"Animation", &"Blend2", 1, &"BlendTree"]
|
||||
|
||||
[resource]
|
||||
graph_offset = Vector2(-217.4643, 82.84979)
|
||||
nodes/output/position = Vector2(540, 140)
|
||||
nodes/Animation/node = SubResource("AnimationNodeAnimation_1bvp3")
|
||||
nodes/Animation/position = Vector2(120, 80)
|
||||
@ -37,6 +16,4 @@ nodes/Animation/position = Vector2(120, 80)
|
||||
"nodes/Animation 2/position" = Vector2(80, 320)
|
||||
nodes/Blend2/node = SubResource("AnimationNodeBlend2_lquwl")
|
||||
nodes/Blend2/position = Vector2(360, 180)
|
||||
nodes/BlendTree/node = SubResource("AnimationNodeBlendTree_8tpve")
|
||||
nodes/BlendTree/position = Vector2(778.0867, 295.33868)
|
||||
node_connections = [&"output", 0, &"Blend2", &"Blend2", 0, &"Animation", &"Blend2", 1, &"Animation 2"]
|
||||
|
||||
@ -34,7 +34,6 @@ glow_enabled = true
|
||||
[sub_resource type="BLTAnimationNodeBlend2" id="BLTAnimationNodeBlend2_7mycd"]
|
||||
resource_name = "BLTAnimationNodeBlend2"
|
||||
position = Vector2(-320, -40)
|
||||
blend_amount = 0.81
|
||||
|
||||
[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_272bh"]
|
||||
resource_name = "BLTAnimationNodeSampler"
|
||||
@ -44,7 +43,7 @@ animation = &"animation_library/Walk-InPlace"
|
||||
[sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_5vw27"]
|
||||
resource_name = "BLTAnimationNodeBlendTree"
|
||||
position = Vector2(-640, -20)
|
||||
graph_offset = Vector2(-760.67163, -24.823944)
|
||||
graph_offset = Vector2(-766.67163, -102.823944)
|
||||
nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_272bh")
|
||||
nodes/BLTAnimationNodeSampler/graph_offset = Vector2(-490, 7)
|
||||
node_connections = ["Output", 0, "BLTAnimationNodeSampler"]
|
||||
@ -52,11 +51,11 @@ node_connections = ["Output", 0, "BLTAnimationNodeSampler"]
|
||||
[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_kek77"]
|
||||
resource_name = "BLTAnimationNodeSampler"
|
||||
position = Vector2(-620, 140)
|
||||
animation = &"animation_library/Run-InPlace"
|
||||
animation = &"animation_library/Walk-InPlace"
|
||||
|
||||
[sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_7mycd"]
|
||||
resource_name = "Root"
|
||||
graph_offset = Vector2(-869, -71)
|
||||
graph_offset = Vector2(-1054.4585, -50.771484)
|
||||
nodes/BLTAnimationNodeBlend2/node = SubResource("BLTAnimationNodeBlend2_7mycd")
|
||||
nodes/BLTAnimationNodeBlend2/graph_offset = Vector2(-320, -40)
|
||||
nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_kek77")
|
||||
@ -319,7 +318,7 @@ libraries/animation_library = ExtResource("3_1bvp3")
|
||||
animation_player = NodePath("../AnimationPlayer2")
|
||||
tree_root = SubResource("BLTAnimationNodeBlendTree_7mycd")
|
||||
skeleton = NodePath("../Armature/Skeleton3D")
|
||||
parameters/BLTAnimationNodeBlend2/blend_amount = 0.81
|
||||
parameters/BLTAnimationNodeBlend2/blend_amount = 0.0
|
||||
|
||||
[connection signal="value_changed" from="UI/MarginContainer/HBoxContainer/BlendWeightSlider" to="." method="_on_blend_weight_slider_value_changed"]
|
||||
|
||||
|
||||
@ -599,87 +599,4 @@ TEST_CASE_FIXTURE(BlendTreeFixture, "[SceneTree][Blendalot][BlendTreeGraph][Chan
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BlendTreeFixture, "[SceneTree][Blendalot][BlendTreeGraph][EmbeddedBlendTree] BlendTree with an embedded BlendTree subgraph") {
|
||||
// Embedded BlendTree
|
||||
Ref<BLTAnimationNodeBlendTree> embedded_blend_tree;
|
||||
embedded_blend_tree.instantiate();
|
||||
|
||||
// TestAnimationB
|
||||
Ref<BLTAnimationNodeSampler> animation_sampler_node_b;
|
||||
animation_sampler_node_b.instantiate();
|
||||
|
||||
embedded_blend_tree->add_node(animation_sampler_node_b);
|
||||
embedded_blend_tree->add_connection(animation_sampler_node_b, embedded_blend_tree->get_output_node(), "Output");
|
||||
|
||||
Ref<BLTAnimationNodeBlendTree> blend_tree;
|
||||
blend_tree.instantiate();
|
||||
|
||||
// Blend2
|
||||
Ref<BLTAnimationNodeBlend2> blend2;
|
||||
blend2.instantiate();
|
||||
blend2->set_name("Blend2");
|
||||
blend_tree->add_node(blend2);
|
||||
|
||||
// TestAnimationA
|
||||
Ref<BLTAnimationNodeSampler> animation_sampler_node_a;
|
||||
animation_sampler_node_a.instantiate();
|
||||
|
||||
blend_tree->add_node(animation_sampler_node_a);
|
||||
|
||||
blend_tree->add_node(embedded_blend_tree);
|
||||
|
||||
blend_tree->add_connection(animation_sampler_node_a, blend2, "Input0");
|
||||
blend_tree->add_connection(embedded_blend_tree, blend2, "Input1");
|
||||
blend_tree->add_connection(blend2, blend_tree->get_output_node(), "Output");
|
||||
|
||||
SUBCASE("Perform regular blend") {
|
||||
animation_sampler_node_b->animation_name = "animation_library/TestAnimationB";
|
||||
animation_sampler_node_a->animation_name = "animation_library/TestAnimationA";
|
||||
blend2->blend_weight = 0.5;
|
||||
blend2->sync = false;
|
||||
|
||||
// Trigger initialization
|
||||
animation_graph->set_root_animation_node(blend_tree);
|
||||
GraphEvaluationContext &graph_context = animation_graph->get_context();
|
||||
REQUIRE(blend_tree->initialize(graph_context));
|
||||
|
||||
// Perform evaluation
|
||||
AnimationData *graph_output = graph_context.animation_data_allocator.allocate();
|
||||
blend_tree->activate_inputs(Vector<Ref<BLTAnimationNode>>());
|
||||
blend_tree->calculate_sync_track(Vector<Ref<BLTAnimationNode>>());
|
||||
blend_tree->update_time(0.1);
|
||||
blend_tree->evaluate(graph_context, LocalVector<AnimationData *>(), *graph_output);
|
||||
|
||||
// Check values
|
||||
AnimationData::TransformTrackValue *hip_transform_value = graph_output->get_value<AnimationData::TransformTrackValue>(test_animation_a->get_tracks()[0]->thash);
|
||||
CHECK(hip_transform_value->loc[0] == doctest::Approx(0.15));
|
||||
CHECK(hip_transform_value->loc[1] == doctest::Approx(0.3));
|
||||
CHECK(hip_transform_value->loc[2] == doctest::Approx(0.45));
|
||||
}
|
||||
SUBCASE("Perform synced blend") {
|
||||
animation_sampler_node_b->animation_name = "animation_library/TestAnimationSyncA";
|
||||
animation_sampler_node_a->animation_name = "animation_library/TestAnimationSyncB";
|
||||
blend2->blend_weight = 0.5;
|
||||
blend2->sync = true;
|
||||
|
||||
// Trigger initialization
|
||||
animation_graph->set_root_animation_node(blend_tree);
|
||||
GraphEvaluationContext &graph_context = animation_graph->get_context();
|
||||
REQUIRE(blend_tree->initialize(graph_context));
|
||||
|
||||
// Perform evaluation
|
||||
AnimationData *graph_output = graph_context.animation_data_allocator.allocate();
|
||||
blend_tree->activate_inputs(Vector<Ref<BLTAnimationNode>>());
|
||||
blend_tree->calculate_sync_track(Vector<Ref<BLTAnimationNode>>());
|
||||
blend_tree->update_time(0.825);
|
||||
blend_tree->evaluate(graph_context, LocalVector<AnimationData *>(), *graph_output);
|
||||
|
||||
// Check values
|
||||
AnimationData::TransformTrackValue *hip_transform_value = graph_output->get_value<AnimationData::TransformTrackValue>(test_animation_a->get_tracks()[0]->thash);
|
||||
CHECK(hip_transform_value->loc[0] == doctest::Approx(1.5));
|
||||
CHECK(hip_transform_value->loc[1] == doctest::Approx(3.0));
|
||||
CHECK(hip_transform_value->loc[2] == doctest::Approx(4.5));
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace TestBlendalotAnimationGraph
|
||||
Loading…
x
Reference in New Issue
Block a user