feature/blend_tree_editor #1
@ -257,8 +257,7 @@ public:
|
|||||||
double sync_position = 0.0;
|
double sync_position = 0.0;
|
||||||
bool is_synced = false;
|
bool is_synced = false;
|
||||||
|
|
||||||
// TODO: 2026-02-17: how to initialize loop_mode e.g. for a BlendTree or a StateMachine?
|
Animation::LoopMode loop_mode = Animation::LOOP_NONE;
|
||||||
Animation::LoopMode loop_mode = Animation::LOOP_LINEAR;
|
|
||||||
SyncTrack sync_track;
|
SyncTrack sync_track;
|
||||||
};
|
};
|
||||||
NodeTimeInfo node_time_info;
|
NodeTimeInfo node_time_info;
|
||||||
@ -753,6 +752,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
tree_graph.nodes[0]->active = true;
|
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++) {
|
for (uint32_t i = 0; i < tree_graph.nodes.size(); i++) {
|
||||||
const Ref<BLTAnimationNode> &node = tree_graph.nodes[i];
|
const Ref<BLTAnimationNode> &node = tree_graph.nodes[i];
|
||||||
|
|
||||||
@ -777,14 +778,21 @@ public:
|
|||||||
const NodeRuntimeData &node_runtime_data = _node_runtime_data[i];
|
const NodeRuntimeData &node_runtime_data = _node_runtime_data[i];
|
||||||
|
|
||||||
node->calculate_sync_track(node_runtime_data.input_nodes);
|
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 {
|
void update_time(double p_delta) override {
|
||||||
GodotProfileZone("SyncedBlendTree::update_time");
|
GodotProfileZone("SyncedBlendTree::update_time");
|
||||||
|
|
||||||
tree_graph.nodes[0]->node_time_info.delta = p_delta;
|
BLTAnimationNode::update_time(p_delta);
|
||||||
tree_graph.nodes[0]->node_time_info.position += 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;
|
||||||
|
|
||||||
for (uint32_t i = 1; i < tree_graph.nodes.size(); i++) {
|
for (uint32_t i = 1; i < tree_graph.nodes.size(); i++) {
|
||||||
const Ref<BLTAnimationNode> &node = tree_graph.nodes[i];
|
const Ref<BLTAnimationNode> &node = tree_graph.nodes[i];
|
||||||
|
|||||||
@ -8,7 +8,28 @@ animation = &"Walk-InPlace"
|
|||||||
|
|
||||||
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_lquwl"]
|
[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]
|
[resource]
|
||||||
|
graph_offset = Vector2(-217.4643, 82.84979)
|
||||||
nodes/output/position = Vector2(540, 140)
|
nodes/output/position = Vector2(540, 140)
|
||||||
nodes/Animation/node = SubResource("AnimationNodeAnimation_1bvp3")
|
nodes/Animation/node = SubResource("AnimationNodeAnimation_1bvp3")
|
||||||
nodes/Animation/position = Vector2(120, 80)
|
nodes/Animation/position = Vector2(120, 80)
|
||||||
@ -16,4 +37,6 @@ nodes/Animation/position = Vector2(120, 80)
|
|||||||
"nodes/Animation 2/position" = Vector2(80, 320)
|
"nodes/Animation 2/position" = Vector2(80, 320)
|
||||||
nodes/Blend2/node = SubResource("AnimationNodeBlend2_lquwl")
|
nodes/Blend2/node = SubResource("AnimationNodeBlend2_lquwl")
|
||||||
nodes/Blend2/position = Vector2(360, 180)
|
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"]
|
node_connections = [&"output", 0, &"Blend2", &"Blend2", 0, &"Animation", &"Blend2", 1, &"Animation 2"]
|
||||||
|
|||||||
@ -34,6 +34,7 @@ glow_enabled = true
|
|||||||
[sub_resource type="BLTAnimationNodeBlend2" id="BLTAnimationNodeBlend2_7mycd"]
|
[sub_resource type="BLTAnimationNodeBlend2" id="BLTAnimationNodeBlend2_7mycd"]
|
||||||
resource_name = "BLTAnimationNodeBlend2"
|
resource_name = "BLTAnimationNodeBlend2"
|
||||||
position = Vector2(-320, -40)
|
position = Vector2(-320, -40)
|
||||||
|
blend_amount = 0.81
|
||||||
|
|
||||||
[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_272bh"]
|
[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_272bh"]
|
||||||
resource_name = "BLTAnimationNodeSampler"
|
resource_name = "BLTAnimationNodeSampler"
|
||||||
@ -43,7 +44,7 @@ animation = &"animation_library/Walk-InPlace"
|
|||||||
[sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_5vw27"]
|
[sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_5vw27"]
|
||||||
resource_name = "BLTAnimationNodeBlendTree"
|
resource_name = "BLTAnimationNodeBlendTree"
|
||||||
position = Vector2(-640, -20)
|
position = Vector2(-640, -20)
|
||||||
graph_offset = Vector2(-766.67163, -102.823944)
|
graph_offset = Vector2(-760.67163, -24.823944)
|
||||||
nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_272bh")
|
nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_272bh")
|
||||||
nodes/BLTAnimationNodeSampler/graph_offset = Vector2(-490, 7)
|
nodes/BLTAnimationNodeSampler/graph_offset = Vector2(-490, 7)
|
||||||
node_connections = ["Output", 0, "BLTAnimationNodeSampler"]
|
node_connections = ["Output", 0, "BLTAnimationNodeSampler"]
|
||||||
@ -51,11 +52,11 @@ node_connections = ["Output", 0, "BLTAnimationNodeSampler"]
|
|||||||
[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_kek77"]
|
[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_kek77"]
|
||||||
resource_name = "BLTAnimationNodeSampler"
|
resource_name = "BLTAnimationNodeSampler"
|
||||||
position = Vector2(-620, 140)
|
position = Vector2(-620, 140)
|
||||||
animation = &"animation_library/Walk-InPlace"
|
animation = &"animation_library/Run-InPlace"
|
||||||
|
|
||||||
[sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_7mycd"]
|
[sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_7mycd"]
|
||||||
resource_name = "Root"
|
resource_name = "Root"
|
||||||
graph_offset = Vector2(-1054.4585, -50.771484)
|
graph_offset = Vector2(-869, -71)
|
||||||
nodes/BLTAnimationNodeBlend2/node = SubResource("BLTAnimationNodeBlend2_7mycd")
|
nodes/BLTAnimationNodeBlend2/node = SubResource("BLTAnimationNodeBlend2_7mycd")
|
||||||
nodes/BLTAnimationNodeBlend2/graph_offset = Vector2(-320, -40)
|
nodes/BLTAnimationNodeBlend2/graph_offset = Vector2(-320, -40)
|
||||||
nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_kek77")
|
nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_kek77")
|
||||||
@ -318,7 +319,7 @@ libraries/animation_library = ExtResource("3_1bvp3")
|
|||||||
animation_player = NodePath("../AnimationPlayer2")
|
animation_player = NodePath("../AnimationPlayer2")
|
||||||
tree_root = SubResource("BLTAnimationNodeBlendTree_7mycd")
|
tree_root = SubResource("BLTAnimationNodeBlendTree_7mycd")
|
||||||
skeleton = NodePath("../Armature/Skeleton3D")
|
skeleton = NodePath("../Armature/Skeleton3D")
|
||||||
parameters/BLTAnimationNodeBlend2/blend_amount = 0.0
|
parameters/BLTAnimationNodeBlend2/blend_amount = 0.81
|
||||||
|
|
||||||
[connection signal="value_changed" from="UI/MarginContainer/HBoxContainer/BlendWeightSlider" to="." method="_on_blend_weight_slider_value_changed"]
|
[connection signal="value_changed" from="UI/MarginContainer/HBoxContainer/BlendWeightSlider" to="." method="_on_blend_weight_slider_value_changed"]
|
||||||
|
|
||||||
|
|||||||
@ -607,7 +607,6 @@ TEST_CASE_FIXTURE(BlendTreeFixture, "[SceneTree][Blendalot][BlendTreeGraph][Embe
|
|||||||
// TestAnimationB
|
// TestAnimationB
|
||||||
Ref<BLTAnimationNodeSampler> animation_sampler_node_b;
|
Ref<BLTAnimationNodeSampler> animation_sampler_node_b;
|
||||||
animation_sampler_node_b.instantiate();
|
animation_sampler_node_b.instantiate();
|
||||||
animation_sampler_node_b->animation_name = "animation_library/TestAnimationB";
|
|
||||||
|
|
||||||
embedded_blend_tree->add_node(animation_sampler_node_b);
|
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");
|
embedded_blend_tree->add_connection(animation_sampler_node_b, embedded_blend_tree->get_output_node(), "Output");
|
||||||
@ -619,15 +618,11 @@ TEST_CASE_FIXTURE(BlendTreeFixture, "[SceneTree][Blendalot][BlendTreeGraph][Embe
|
|||||||
Ref<BLTAnimationNodeBlend2> blend2;
|
Ref<BLTAnimationNodeBlend2> blend2;
|
||||||
blend2.instantiate();
|
blend2.instantiate();
|
||||||
blend2->set_name("Blend2");
|
blend2->set_name("Blend2");
|
||||||
blend2->blend_weight = 0.5;
|
|
||||||
blend2->sync = true;
|
|
||||||
|
|
||||||
blend_tree->add_node(blend2);
|
blend_tree->add_node(blend2);
|
||||||
|
|
||||||
// TestAnimationA
|
// TestAnimationA
|
||||||
Ref<BLTAnimationNodeSampler> animation_sampler_node_a;
|
Ref<BLTAnimationNodeSampler> animation_sampler_node_a;
|
||||||
animation_sampler_node_a.instantiate();
|
animation_sampler_node_a.instantiate();
|
||||||
animation_sampler_node_a->animation_name = "animation_library/TestAnimationA";
|
|
||||||
|
|
||||||
blend_tree->add_node(animation_sampler_node_a);
|
blend_tree->add_node(animation_sampler_node_a);
|
||||||
|
|
||||||
@ -637,6 +632,12 @@ TEST_CASE_FIXTURE(BlendTreeFixture, "[SceneTree][Blendalot][BlendTreeGraph][Embe
|
|||||||
blend_tree->add_connection(embedded_blend_tree, blend2, "Input1");
|
blend_tree->add_connection(embedded_blend_tree, blend2, "Input1");
|
||||||
blend_tree->add_connection(blend2, blend_tree->get_output_node(), "Output");
|
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
|
// Trigger initialization
|
||||||
animation_graph->set_root_animation_node(blend_tree);
|
animation_graph->set_root_animation_node(blend_tree);
|
||||||
GraphEvaluationContext &graph_context = animation_graph->get_context();
|
GraphEvaluationContext &graph_context = animation_graph->get_context();
|
||||||
@ -654,6 +655,31 @@ TEST_CASE_FIXTURE(BlendTreeFixture, "[SceneTree][Blendalot][BlendTreeGraph][Embe
|
|||||||
CHECK(hip_transform_value->loc[0] == doctest::Approx(0.15));
|
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[1] == doctest::Approx(0.3));
|
||||||
CHECK(hip_transform_value->loc[2] == doctest::Approx(0.45));
|
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
|
} //namespace TestBlendalotAnimationGraph
|
||||||
Loading…
x
Reference in New Issue
Block a user