Started working on evaluating embedded blend trees.
parent
99f11e61d8
commit
0aebe44bd5
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -250,36 +250,7 @@ struct NodeDescriptor<MathFloatToVec3Node> : 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,
|
||||
|
|
|
@ -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<AnimGraphResource*>(node_resource);
|
||||
assert(embedded_blend_tree_resource != nullptr);
|
||||
AnimGraphBlendTree* embedded_blend_tree = dynamic_cast<AnimGraphBlendTree*>(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 =
|
||||
|
@ -569,6 +582,13 @@ void AnimGraphResource::PrepareBlendTreeIOData(
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
@ -1022,3 +1024,37 @@ TEST_CASE_METHOD(
|
|||
== 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();
|
||||
}
|
Loading…
Reference in New Issue