From 0aebe44bd51393e292cbc633ccb3b3c4650f652e Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Mon, 25 Mar 2024 22:26:29 +0100 Subject: [PATCH] Started working on evaluating embedded blend trees. --- src/AnimGraph/AnimGraphBlendTree.cc | 2 +- src/AnimGraph/AnimGraphBlendTree.h | 4 ++-- src/AnimGraph/AnimGraphNodes.cc | 33 ++++++++++++++++++++++++++ src/AnimGraph/AnimGraphNodes.h | 31 +------------------------ src/AnimGraph/AnimGraphResource.cc | 26 ++++++++++++++++++--- src/AnimGraph/AnimGraphResource.h | 1 - tests/AnimGraphResourceTests.cc | 36 +++++++++++++++++++++++++++++ 7 files changed, 96 insertions(+), 37 deletions(-) diff --git a/src/AnimGraph/AnimGraphBlendTree.cc b/src/AnimGraph/AnimGraphBlendTree.cc index 6cff7bb..d582779 100644 --- a/src/AnimGraph/AnimGraphBlendTree.cc +++ b/src/AnimGraph/AnimGraphBlendTree.cc @@ -73,7 +73,7 @@ void AnimGraphBlendTree::MarkActiveInputs() { } } - for (size_t i = m_eval_ordered_nodes.size() - 1; i > 0; i--) { + for (size_t i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) { AnimNode* node = m_eval_ordered_nodes[i]; if (checkIsNodeActive(node)) { node->MarkActiveInputs(); diff --git a/src/AnimGraph/AnimGraphBlendTree.h b/src/AnimGraph/AnimGraphBlendTree.h index acd922c..5f83828 100644 --- a/src/AnimGraph/AnimGraphBlendTree.h +++ b/src/AnimGraph/AnimGraphBlendTree.h @@ -29,10 +29,10 @@ struct AnimGraphBlendTree : public AnimNode { AnimDataAllocator m_anim_data_allocator; - ~AnimGraphBlendTree() { dealloc(); } + ~AnimGraphBlendTree() override { dealloc(); } // AnimNode overrides - bool Init(AnimGraphContext& context); + bool Init(AnimGraphContext& context) override; void MarkActiveInputs() override; void CalcSyncTrack() override; void UpdateTime(float time_last, float time_now) override; diff --git a/src/AnimGraph/AnimGraphNodes.cc b/src/AnimGraph/AnimGraphNodes.cc index 0704e38..bc9bfb5 100644 --- a/src/AnimGraph/AnimGraphNodes.cc +++ b/src/AnimGraph/AnimGraphNodes.cc @@ -3,6 +3,7 @@ // #include "AnimGraphNodes.h" +#include "AnimGraphBlendTree.h" #include "ozz/base/log.h" #include "ozz/animation/runtime/blending_job.h" @@ -10,6 +11,38 @@ #include "ozz/base/io/archive.h" #include "ozz/base/io/stream.h" +AnimNode* AnimNodeFactory(const std::string& name) { + AnimNode* result; + if (name == "Blend2") { + result = new Blend2Node; + } else if (name == "SpeedScale") { + result = new SpeedScaleNode; + } else if (name == "AnimSampler") { + result = new AnimSamplerNode; + } else if (name == "LockTranslationNode") { + result = new LockTranslationNode; + } else if (name == "BlendTree") { + result = new AnimGraphBlendTree; + } else if (name == "BlendTreeSockets") { + result = new BlendTreeNode; + } else if (name == "MathAddNode") { + result = new MathAddNode; + } else if (name == "MathFloatToVec3Node") { + result = new MathFloatToVec3Node; + } else if (name == "ConstScalarNode") { + result = new ConstScalarNode; + } + + if (result != nullptr) { + result->m_node_type_name = name; + return result; + } + + std::cerr << "Invalid node type: " << name << std::endl; + return nullptr; +} + + void Blend2Node::Evaluate(AnimGraphContext& context) { assert (i_input0 != nullptr); assert (i_input1 != nullptr); diff --git a/src/AnimGraph/AnimGraphNodes.h b/src/AnimGraph/AnimGraphNodes.h index 8d960fc..d4b2d77 100644 --- a/src/AnimGraph/AnimGraphNodes.h +++ b/src/AnimGraph/AnimGraphNodes.h @@ -250,36 +250,7 @@ struct NodeDescriptor : public NodeDescriptorBase { }; -static inline AnimNode* AnimNodeFactory(const std::string& name) { - AnimNode* result; - if (name == "Blend2") { - result = new Blend2Node; - } else if (name == "SpeedScale") { - result = new SpeedScaleNode; - } else if (name == "AnimSampler") { - result = new AnimSamplerNode; - } else if (name == "LockTranslationNode") { - result = new LockTranslationNode; - } else if (name == "BlendTree") { - result = new BlendTreeNode; - } else if (name == "BlendTreeSockets") { - result = new BlendTreeNode; - } else if (name == "MathAddNode") { - result = new MathAddNode; - } else if (name == "MathFloatToVec3Node") { - result = new MathFloatToVec3Node; - } else if (name == "ConstScalarNode") { - result = new ConstScalarNode; - } - - if (result != nullptr) { - result->m_node_type_name = name; - return result; - } - - std::cerr << "Invalid node type: " << name << std::endl; - return nullptr; -} +AnimNode* AnimNodeFactory(const std::string& name); static inline NodeDescriptorBase* AnimNodeDescriptorFactory( const std::string& node_type_name, diff --git a/src/AnimGraph/AnimGraphResource.cc b/src/AnimGraph/AnimGraphResource.cc index 64e2595..4687086 100644 --- a/src/AnimGraph/AnimGraphResource.cc +++ b/src/AnimGraph/AnimGraphResource.cc @@ -483,6 +483,18 @@ void AnimGraphResource::CreateBlendTreeRuntimeNodeInstances( AnimGraphBlendTree& result) const { for (auto node_resource : m_blend_tree_resource.m_nodes) { AnimNode* node = AnimNodeFactory(node_resource->m_node_type_name); + + if (node_resource->m_node_type_name == "BlendTree") { + AnimGraphResource* embedded_blend_tree_resource = dynamic_cast(node_resource); + assert(embedded_blend_tree_resource != nullptr); + AnimGraphBlendTree* embedded_blend_tree = dynamic_cast(node); + assert(embedded_blend_tree != nullptr); + + embedded_blend_tree_resource->CreateBlendTreeInstance(*embedded_blend_tree); + embedded_blend_tree_resource->m_socket_accessor->m_inputs = embedded_blend_tree->m_node_descriptor->m_outputs; + embedded_blend_tree_resource->m_socket_accessor->m_outputs = embedded_blend_tree->m_node_descriptor->m_inputs; + } + node->m_name = node_resource->m_name; node->m_node_type_name = node_resource->m_node_type_name; result.m_nodes.push_back(node); @@ -497,6 +509,7 @@ void AnimGraphResource::PrepareBlendTreeIOData( AnimGraphBlendTree& instance) const { instance.m_node_descriptor = AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]); + instance.m_node_descriptor->m_outputs = m_blend_tree_resource.m_nodes[1]->m_socket_accessor->m_outputs; instance.m_node_descriptor->m_inputs = @@ -566,9 +579,16 @@ void AnimGraphResource::PrepareBlendTreeIOData( m_blend_tree_resource.m_nodes.size(), nullptr); for (int i = 0; i < m_blend_tree_resource.m_nodes.size(); i++) { - instance_node_descriptors[i] = AnimNodeDescriptorFactory( - m_blend_tree_resource.m_nodes[i]->m_node_type_name, - instance.m_nodes[i]); + instance_node_descriptors[i] = AnimNodeDescriptorFactory( + m_blend_tree_resource.m_nodes[i]->m_node_type_name, + instance.m_nodes[i]); + + if (i > 1 && m_blend_tree_resource.m_nodes[i]->m_node_type_name == "BlendTree") { + instance_node_descriptors[i]->m_inputs = + m_blend_tree_resource.m_nodes[i]->m_socket_accessor->m_inputs; + instance_node_descriptors[i]->m_outputs = + m_blend_tree_resource.m_nodes[i]->m_socket_accessor->m_outputs; + } } instance_node_descriptors[0]->m_inputs = instance.m_node_descriptor->m_inputs; diff --git a/src/AnimGraph/AnimGraphResource.h b/src/AnimGraph/AnimGraphResource.h index 39ba194..e94fbb6 100644 --- a/src/AnimGraph/AnimGraphResource.h +++ b/src/AnimGraph/AnimGraphResource.h @@ -116,7 +116,6 @@ struct StateMachineResource { struct AnimGraphResource: AnimNodeResource { std::string m_graph_type_name; - std::string m_name; BlendTreeResource m_blend_tree_resource; StateMachineResource m_state_machine_resource; diff --git a/tests/AnimGraphResourceTests.cc b/tests/AnimGraphResourceTests.cc index 2e275ca..6c4b2d4 100644 --- a/tests/AnimGraphResourceTests.cc +++ b/tests/AnimGraphResourceTests.cc @@ -181,6 +181,7 @@ class EmbeddedBlendTreeGraphResource { parent_blend_tree_resource->m_nodes.back()); embedded_graph->m_name = "EmbeddedBlendTree"; embedded_graph->m_node_type_name = "BlendTree"; + embedded_graph->m_graph_type_name = "BlendTree"; embedded_blend_tree_resource = &embedded_graph->m_blend_tree_resource; // Embedded: outputs @@ -202,6 +203,7 @@ class EmbeddedBlendTreeGraphResource { AnimNodeResourceFactory("SpeedScale")); AnimNodeResource* embedded_speed_scale_resource = embedded_blend_tree_resource->m_nodes.back(); + embedded_speed_scale_resource->m_socket_accessor->SetInputValue("SpeedScale", 0.1f); // Embedded: setup connections embedded_blend_tree_resource->ConnectSockets( @@ -1021,4 +1023,38 @@ TEST_CASE_METHOD( embedded_connection.target_socket_name == embedded_connection_loaded.target_socket_name); } +} + +TEST_CASE_METHOD( + EmbeddedBlendTreeGraphResource, + "EmbeddedBlendTreeGraphResource instantiation", + "[EmbeddedBlendTreeGraphResource]") { + AnimGraphBlendTree blend_tree; + + parent_graph_resource.CreateBlendTreeInstance(blend_tree); + AnimGraphContext graph_context; + + ozz::animation::Skeleton skeleton; + REQUIRE(load_skeleton(skeleton, "media/skeleton.ozz")); + 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); + blend_tree.Evaluate(graph_context); + + graph_context.freeAnimations(); } \ No newline at end of file