New evaluation scheme.

- Animation Data are always referenced via a pointer in nodes.
- Animation Data storage pointers are injected from graph when node is evaluated.
- Node value outputs always stored in node.
- Node value inputs always referenced via pointer. References are created when instantiating the graph.
This commit is contained in:
Martin Felis
2022-04-01 13:19:54 +02:00
parent abddbea62b
commit 08ae84fcb4
8 changed files with 559 additions and 431 deletions
+60 -26
View File
@@ -15,6 +15,7 @@ struct AnimNode;
struct NodeInput {
AnimNode* m_node;
SocketType m_type = SocketType::SocketTypeUndefined;
Socket* m_node_output_socket;
std::string m_input_name;
};
@@ -27,6 +28,13 @@ enum class AnimNodeEvalState {
Evaluated
};
struct AnimGraphConnection {
AnimNode* m_source_node = nullptr;
Socket m_source_socket;
AnimNode* m_target_node = nullptr;
Socket m_target_socket;
};
struct AnimNode {
std::string m_name;
std::string m_node_type_name;
@@ -38,20 +46,20 @@ struct AnimNode {
virtual ~AnimNode(){};
virtual void MarkActiveInputs(const std::vector<NodeInput>& inputs) {
virtual void MarkActiveInputs(const std::vector<AnimGraphConnection>& inputs) {
for (size_t i = 0, n = inputs.size(); i < n; i++) {
AnimNode* input_node = inputs[i].m_node;
AnimNode* input_node = inputs[i].m_source_node;
if (input_node != nullptr) {
input_node->m_state = AnimNodeEvalState::Activated;
}
}
}
virtual void CalcSyncTrack(const std::vector<NodeInput>& inputs) {
virtual void CalcSyncTrack(const std::vector<AnimGraphConnection>& inputs) {
for (size_t i = 0, n = inputs.size(); i < n; i++) {
AnimNode* input_node = inputs[i].m_node;
AnimNode* input_node = inputs[i].m_source_node;
if (input_node != nullptr
&& inputs[i].m_type == SocketType::SocketTypeAnimation
&& inputs[i].m_source_socket.m_type == SocketType::SocketTypeAnimation
&& input_node->m_state != AnimNodeEvalState::Deactivated) {
m_sync_track = input_node->m_sync_track;
return;
@@ -83,25 +91,25 @@ struct NodeSocketAccessor<BlendTreeNode> : public NodeSocketAccessorBase {
// Blend2Node
//
struct Blend2Node : public AnimNode {
AnimData m_input0;
AnimData m_input1;
AnimData* m_output = nullptr;
float m_blend_weight = 0.f;
AnimData* i_input0 = nullptr;
AnimData* i_input1 = nullptr;
AnimData* o_output = nullptr;
float* i_blend_weight = nullptr;
bool m_sync_blend = false;
virtual void MarkActiveInputs(const std::vector<NodeInput>& inputs) override {
virtual void MarkActiveInputs(const std::vector<AnimGraphConnection>& inputs) override {
for (size_t i = 0, n = inputs.size(); i < n; i++) {
AnimNode* input_node = inputs[i].m_node;
AnimNode* input_node = inputs[i].m_source_node;
if (input_node == nullptr) {
continue;
}
if (inputs[i].m_input_name == "Input0" && m_blend_weight < 0.999) {
if (inputs[i].m_target_socket.m_name == "Input0" && *i_blend_weight < 0.999) {
input_node->m_state = AnimNodeEvalState::Activated;
continue;
}
if (inputs[i].m_input_name == "Input1" && m_blend_weight > 0.001) {
if (inputs[i].m_target_socket.m_name == "Input1" && *i_blend_weight > 0.001) {
input_node->m_state = AnimNodeEvalState::Activated;
continue;
}
@@ -134,14 +142,14 @@ template <>
struct NodeSocketAccessor<Blend2Node> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) {
Blend2Node* node = dynamic_cast<Blend2Node*>(node_);
RegisterInput("Input0", &node->m_input0);
RegisterInput("Input1", &node->m_input1);
RegisterInput("Input0", &node->i_input0);
RegisterInput("Input1", &node->i_input1);
RegisterInput(
"Weight",
&node->m_blend_weight,
&node->i_blend_weight,
SocketFlags::SocketFlagAffectsTime);
RegisterOutput("Output", &node->m_output);
RegisterOutput("Output", &node->o_output);
RegisterProperty("Sync", &node->m_sync_blend);
}
@@ -162,13 +170,13 @@ struct NodeSocketAccessor<Blend2Node> : public NodeSocketAccessorBase {
// SpeedScaleNode
//
struct SpeedScaleNode : public AnimNode {
AnimData m_input;
AnimData* m_output = nullptr;
float m_speed_scale = 0.f;
AnimData* i_input = nullptr;
AnimData* i_output = nullptr;
float* i_speed_scale = nullptr;
virtual void UpdateTime(float time_last, float time_now) {
m_time_last = time_last;
m_time_now = time_last + (time_now - time_last) * m_speed_scale;
m_time_now = time_last + (time_now - time_last) * (*i_speed_scale);
m_state = AnimNodeEvalState::TimeUpdated;
}
};
@@ -179,11 +187,11 @@ struct NodeSocketAccessor<SpeedScaleNode> : public NodeSocketAccessorBase {
SpeedScaleNode* node = dynamic_cast<SpeedScaleNode*>(node_);
RegisterInput(
"SpeedScale",
&node->m_speed_scale,
&node->i_speed_scale,
SocketFlags::SocketFlagAffectsTime);
RegisterInput("Input", &node->m_input);
RegisterInput("Input", &node->i_input);
RegisterOutput("Output", &node->m_output);
RegisterOutput("Output", &node->i_output);
}
};
@@ -191,7 +199,7 @@ struct NodeSocketAccessor<SpeedScaleNode> : public NodeSocketAccessorBase {
// AnimSamplerNode
//
struct AnimSamplerNode : public AnimNode {
AnimData* m_output = nullptr;
AnimData* o_output = nullptr;
std::string m_filename;
};
@@ -199,12 +207,38 @@ template <>
struct NodeSocketAccessor<AnimSamplerNode> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) {
AnimSamplerNode* node = dynamic_cast<AnimSamplerNode*>(node_);
RegisterOutput("Output", &node->m_output);
RegisterOutput("Output", &node->o_output);
RegisterProperty("Filename", &node->m_filename);
}
};
//
// MathAddNode
//
struct MathAddNode : public AnimNode {
float* i_input0 = nullptr;
float* i_input1 = nullptr;
float o_output = 0.f;
void Evaluate() override {
assert (i_input0 != nullptr);
assert (i_input1 != nullptr);
o_output = *i_input0 + *i_input1;
}
};
template <>
struct NodeSocketAccessor<MathAddNode> : public NodeSocketAccessorBase {
NodeSocketAccessor(AnimNode* node_) {
MathAddNode* node = dynamic_cast<MathAddNode*>(node_);
RegisterInput("Input0", &node->i_input0);
RegisterInput("Input1", &node->i_input1);
RegisterOutput("Output", &node->o_output);
}
};
static inline AnimNode* AnimNodeFactory(const std::string& name) {
AnimNode* result;