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];
|
AnimNode* node = m_eval_ordered_nodes[i];
|
||||||
if (checkIsNodeActive(node)) {
|
if (checkIsNodeActive(node)) {
|
||||||
node->MarkActiveInputs();
|
node->MarkActiveInputs();
|
||||||
|
|
|
@ -29,10 +29,10 @@ struct AnimGraphBlendTree : public AnimNode {
|
||||||
|
|
||||||
AnimDataAllocator m_anim_data_allocator;
|
AnimDataAllocator m_anim_data_allocator;
|
||||||
|
|
||||||
~AnimGraphBlendTree() { dealloc(); }
|
~AnimGraphBlendTree() override { dealloc(); }
|
||||||
|
|
||||||
// AnimNode overrides
|
// AnimNode overrides
|
||||||
bool Init(AnimGraphContext& context);
|
bool Init(AnimGraphContext& context) override;
|
||||||
void MarkActiveInputs() override;
|
void MarkActiveInputs() override;
|
||||||
void CalcSyncTrack() override;
|
void CalcSyncTrack() override;
|
||||||
void UpdateTime(float time_last, float time_now) override;
|
void UpdateTime(float time_last, float time_now) override;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "AnimGraphNodes.h"
|
#include "AnimGraphNodes.h"
|
||||||
|
#include "AnimGraphBlendTree.h"
|
||||||
|
|
||||||
#include "ozz/base/log.h"
|
#include "ozz/base/log.h"
|
||||||
#include "ozz/animation/runtime/blending_job.h"
|
#include "ozz/animation/runtime/blending_job.h"
|
||||||
|
@ -10,6 +11,38 @@
|
||||||
#include "ozz/base/io/archive.h"
|
#include "ozz/base/io/archive.h"
|
||||||
#include "ozz/base/io/stream.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) {
|
void Blend2Node::Evaluate(AnimGraphContext& context) {
|
||||||
assert (i_input0 != nullptr);
|
assert (i_input0 != nullptr);
|
||||||
assert (i_input1 != nullptr);
|
assert (i_input1 != nullptr);
|
||||||
|
|
|
@ -250,36 +250,7 @@ struct NodeDescriptor<MathFloatToVec3Node> : public NodeDescriptorBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static inline AnimNode* AnimNodeFactory(const std::string& name) {
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline NodeDescriptorBase* AnimNodeDescriptorFactory(
|
static inline NodeDescriptorBase* AnimNodeDescriptorFactory(
|
||||||
const std::string& node_type_name,
|
const std::string& node_type_name,
|
||||||
|
|
|
@ -483,6 +483,18 @@ void AnimGraphResource::CreateBlendTreeRuntimeNodeInstances(
|
||||||
AnimGraphBlendTree& result) const {
|
AnimGraphBlendTree& result) const {
|
||||||
for (auto node_resource : m_blend_tree_resource.m_nodes) {
|
for (auto node_resource : m_blend_tree_resource.m_nodes) {
|
||||||
AnimNode* node = AnimNodeFactory(node_resource->m_node_type_name);
|
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_name = node_resource->m_name;
|
||||||
node->m_node_type_name = node_resource->m_node_type_name;
|
node->m_node_type_name = node_resource->m_node_type_name;
|
||||||
result.m_nodes.push_back(node);
|
result.m_nodes.push_back(node);
|
||||||
|
@ -497,6 +509,7 @@ void AnimGraphResource::PrepareBlendTreeIOData(
|
||||||
AnimGraphBlendTree& instance) const {
|
AnimGraphBlendTree& instance) const {
|
||||||
instance.m_node_descriptor =
|
instance.m_node_descriptor =
|
||||||
AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]);
|
AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]);
|
||||||
|
|
||||||
instance.m_node_descriptor->m_outputs =
|
instance.m_node_descriptor->m_outputs =
|
||||||
m_blend_tree_resource.m_nodes[1]->m_socket_accessor->m_outputs;
|
m_blend_tree_resource.m_nodes[1]->m_socket_accessor->m_outputs;
|
||||||
instance.m_node_descriptor->m_inputs =
|
instance.m_node_descriptor->m_inputs =
|
||||||
|
@ -566,9 +579,16 @@ void AnimGraphResource::PrepareBlendTreeIOData(
|
||||||
m_blend_tree_resource.m_nodes.size(),
|
m_blend_tree_resource.m_nodes.size(),
|
||||||
nullptr);
|
nullptr);
|
||||||
for (int i = 0; i < m_blend_tree_resource.m_nodes.size(); i++) {
|
for (int i = 0; i < m_blend_tree_resource.m_nodes.size(); i++) {
|
||||||
instance_node_descriptors[i] = AnimNodeDescriptorFactory(
|
instance_node_descriptors[i] = AnimNodeDescriptorFactory(
|
||||||
m_blend_tree_resource.m_nodes[i]->m_node_type_name,
|
m_blend_tree_resource.m_nodes[i]->m_node_type_name,
|
||||||
instance.m_nodes[i]);
|
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;
|
instance_node_descriptors[0]->m_inputs = instance.m_node_descriptor->m_inputs;
|
||||||
|
|
|
@ -116,7 +116,6 @@ struct StateMachineResource {
|
||||||
|
|
||||||
struct AnimGraphResource: AnimNodeResource {
|
struct AnimGraphResource: AnimNodeResource {
|
||||||
std::string m_graph_type_name;
|
std::string m_graph_type_name;
|
||||||
std::string m_name;
|
|
||||||
|
|
||||||
BlendTreeResource m_blend_tree_resource;
|
BlendTreeResource m_blend_tree_resource;
|
||||||
StateMachineResource m_state_machine_resource;
|
StateMachineResource m_state_machine_resource;
|
||||||
|
|
|
@ -181,6 +181,7 @@ class EmbeddedBlendTreeGraphResource {
|
||||||
parent_blend_tree_resource->m_nodes.back());
|
parent_blend_tree_resource->m_nodes.back());
|
||||||
embedded_graph->m_name = "EmbeddedBlendTree";
|
embedded_graph->m_name = "EmbeddedBlendTree";
|
||||||
embedded_graph->m_node_type_name = "BlendTree";
|
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_blend_tree_resource = &embedded_graph->m_blend_tree_resource;
|
||||||
|
|
||||||
// Embedded: outputs
|
// Embedded: outputs
|
||||||
|
@ -202,6 +203,7 @@ class EmbeddedBlendTreeGraphResource {
|
||||||
AnimNodeResourceFactory("SpeedScale"));
|
AnimNodeResourceFactory("SpeedScale"));
|
||||||
AnimNodeResource* embedded_speed_scale_resource =
|
AnimNodeResource* embedded_speed_scale_resource =
|
||||||
embedded_blend_tree_resource->m_nodes.back();
|
embedded_blend_tree_resource->m_nodes.back();
|
||||||
|
embedded_speed_scale_resource->m_socket_accessor->SetInputValue("SpeedScale", 0.1f);
|
||||||
|
|
||||||
// Embedded: setup connections
|
// Embedded: setup connections
|
||||||
embedded_blend_tree_resource->ConnectSockets(
|
embedded_blend_tree_resource->ConnectSockets(
|
||||||
|
@ -1021,4 +1023,38 @@ TEST_CASE_METHOD(
|
||||||
embedded_connection.target_socket_name
|
embedded_connection.target_socket_name
|
||||||
== embedded_connection_loaded.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();
|
||||||
}
|
}
|
Loading…
Reference in New Issue