Added support of time updates for simple embedded graphs.

This commit is contained in:
Martin Felis
2024-04-01 12:33:23 +02:00
parent 0aebe44bd5
commit 76ea38f118
12 changed files with 392 additions and 198 deletions
+75 -27
View File
@@ -140,7 +140,9 @@ class EmbeddedBlendTreeGraphResource {
BlendTreeResource* embedded_blend_tree_resource = nullptr;
size_t walk_node_index = -1;
AnimNodeResource* walk_node = nullptr;
AnimNodeResource* walk_node_resource = nullptr;
size_t embedded_blend_tree_node_index = -1;
size_t embedded_speed_scale_index = -1;
public:
EmbeddedBlendTreeGraphResource() {
@@ -163,10 +165,11 @@ class EmbeddedBlendTreeGraphResource {
// Parent AnimSampler
parent_blend_tree_resource->m_nodes.push_back(
AnimNodeResourceFactory("AnimSampler"));
walk_node_index = parent_blend_tree_resource->m_nodes.size() - 1;
walk_node = parent_blend_tree_resource->m_nodes.back();
walk_node->m_name = "WalkAnim";
walk_node->m_socket_accessor->SetPropertyValue(
walk_node_resource = parent_blend_tree_resource->m_nodes[walk_node_index];
walk_node_resource->m_name = "WalkAnim";
walk_node_resource->m_socket_accessor->SetPropertyValue(
"Filename",
std::string("media/Walking-loop.ozz"));
@@ -175,7 +178,7 @@ class EmbeddedBlendTreeGraphResource {
//
parent_blend_tree_resource->m_nodes.push_back(
AnimNodeResourceFactory("BlendTree"));
size_t embedded_blend_tree_node_index =
embedded_blend_tree_node_index =
parent_blend_tree_resource->m_nodes.size() - 1;
embedded_graph = dynamic_cast<AnimGraphResource*>(
parent_blend_tree_resource->m_nodes.back());
@@ -201,9 +204,13 @@ class EmbeddedBlendTreeGraphResource {
// Embedded: SpeedScale node
embedded_blend_tree_resource->m_nodes.push_back(
AnimNodeResourceFactory("SpeedScale"));
embedded_speed_scale_index =
embedded_blend_tree_resource->m_nodes.size() - 1;
AnimNodeResource* embedded_speed_scale_resource =
embedded_blend_tree_resource->m_nodes.back();
embedded_speed_scale_resource->m_socket_accessor->SetInputValue("SpeedScale", 0.1f);
embedded_blend_tree_resource->m_nodes[embedded_speed_scale_index];
embedded_speed_scale_resource->m_socket_accessor->SetInputValue(
"SpeedScale",
0.1f);
// Embedded: setup connections
embedded_blend_tree_resource->ConnectSockets(
@@ -219,7 +226,7 @@ class EmbeddedBlendTreeGraphResource {
// Parent: setup connections
REQUIRE(parent_blend_tree_resource->ConnectSockets(
walk_node,
walk_node_resource,
"Output",
embedded_graph,
"AnimInput"));
@@ -346,8 +353,8 @@ TEST_CASE_METHOD(
AnimSamplerNode* anim_sampler_walk =
dynamic_cast<AnimSamplerNode*>(anim_graph_blend_tree.m_nodes[2]);
BlendTreeNode* graph_output_node =
dynamic_cast<BlendTreeNode*>(anim_graph_blend_tree.m_nodes[0]);
BlendTreeSocketNode* graph_output_node =
dynamic_cast<BlendTreeSocketNode*>(anim_graph_blend_tree.m_nodes[0]);
// check node input dependencies
size_t anim_sampler_index =
@@ -937,7 +944,8 @@ TEST_CASE_METHOD(
parent_blend_tree_resource->m_nodes.size()
== parent_blend_tree_resource_loaded.m_nodes.size());
for (size_t i = 0; i < parent_blend_tree_resource->m_nodes.size(); i++) {
const AnimNodeResource* parent_node = parent_blend_tree_resource->m_nodes[i];
const AnimNodeResource* parent_node =
parent_blend_tree_resource->m_nodes[i];
const AnimNodeResource* parent_node_loaded =
parent_blend_tree_resource_loaded.m_nodes[i];
@@ -949,7 +957,8 @@ TEST_CASE_METHOD(
CHECK(
parent_blend_tree_resource->m_connections.size()
== parent_blend_tree_resource_loaded.m_connections.size());
for (size_t i = 0; i < parent_blend_tree_resource->m_connections.size(); i++) {
for (size_t i = 0; i < parent_blend_tree_resource->m_connections.size();
i++) {
const BlendTreeConnectionResource& parent_connection =
parent_blend_tree_resource->m_connections[i];
const BlendTreeConnectionResource& parent_connection_loaded =
@@ -1039,22 +1048,61 @@ TEST_CASE_METHOD(
graph_context.m_skeleton = &skeleton;
blend_tree.Init(graph_context);
// Marking of active inputs is not properly working as we do not properly
// populate AnimNode::m_inputs.
//
// Here comes an iffy problem: How to mark nodes in a parent blend tree
// as active?
//
// - Simplest would be if the AnimNodes don't distinguish between nodes within
// the tree they are contained or in a possible parent (or nested) tree.
// - But then how to propagate active connections across multiple layers?
// - Therefore probably better to have a blend tree store which sockets are
// active and use that within the graph.
// - But then: AnimGraphConnection already stores raw AnimNode pointers of the
// connected nodes. Still... populating them accross layers could be messy.
blend_tree.MarkActiveInputs();
blend_tree.UpdateTime(0.f, 0.1f);
const AnimSamplerNode* walk_node =
dynamic_cast<AnimSamplerNode*>(blend_tree.m_nodes[walk_node_index]);
const AnimGraphBlendTree* embedded_blend_tree_node =
dynamic_cast<AnimGraphBlendTree*>(
blend_tree.m_nodes[embedded_blend_tree_node_index]);
const SpeedScaleNode* speed_scale_node = dynamic_cast<SpeedScaleNode*>(
embedded_blend_tree_node->m_nodes[walk_node_index]);
blend_tree.StartUpdateTick();
blend_tree.MarkActiveInputs(std::vector<AnimGraphConnection>());
REQUIRE(embedded_blend_tree_node->m_state == AnimNodeEvalState::Activated);
REQUIRE(speed_scale_node->m_state == AnimNodeEvalState::Activated);
REQUIRE(walk_node->m_state == AnimNodeEvalState::Activated);
float time_last = 0.f;
float dt = 0.1f;
blend_tree.UpdateTime(time_last, time_last + dt);
CHECK(embedded_blend_tree_node->m_state == AnimNodeEvalState::TimeUpdated);
CHECK(speed_scale_node->m_state == AnimNodeEvalState::TimeUpdated);
CHECK(walk_node->m_state == AnimNodeEvalState::TimeUpdated);
CHECK_THAT(
walk_node->m_time_last,
Catch::Matchers::WithinAbs(time_last, 0.001));
CHECK_THAT(
walk_node->m_time_now,
Catch::Matchers::WithinAbs(
time_last + dt * (*speed_scale_node->i_speed_scale),
0.001));
blend_tree.Evaluate(graph_context);
WHEN("Updating the time a second time") {
// Perform another update
time_last = time_last + dt;
dt = 0.3f;
blend_tree.StartUpdateTick();
blend_tree.MarkActiveInputs(std::vector<AnimGraphConnection>());
blend_tree.UpdateTime(time_last, time_last + dt);
CHECK(embedded_blend_tree_node->m_state == AnimNodeEvalState::TimeUpdated);
CHECK(speed_scale_node->m_state == AnimNodeEvalState::TimeUpdated);
CHECK(walk_node->m_state == AnimNodeEvalState::TimeUpdated);
CHECK_THAT(
walk_node->m_time_last,
Catch::Matchers::WithinAbs(
time_last * (*speed_scale_node->i_speed_scale),
0.001));
CHECK_THAT(
walk_node->m_time_now,
Catch::Matchers::WithinAbs(
(time_last + dt) * (*speed_scale_node->i_speed_scale),
0.001));
}
graph_context.freeAnimations();
}