Simple time propagation works.
parent
87eb2ab7df
commit
af5d27db85
|
@ -355,10 +355,11 @@ void AnimGraph::UpdateOrderedNodes() {
|
||||||
std::vector<int> node_index_stack;
|
std::vector<int> node_index_stack;
|
||||||
node_index_stack.push_back(0);
|
node_index_stack.push_back(0);
|
||||||
|
|
||||||
m_ordered_nodes.clear();
|
m_eval_ordered_nodes.clear();
|
||||||
|
|
||||||
while (node_index_stack.size() > 0) {
|
while (node_index_stack.size() > 0) {
|
||||||
std::vector<AnimNodeInput>& node_inputs = m_node_inputs[node_index_stack.back()];
|
std::vector<AnimNodeInput>& node_inputs =
|
||||||
|
m_node_inputs[node_index_stack.back()];
|
||||||
node_index_stack.pop_back();
|
node_index_stack.pop_back();
|
||||||
|
|
||||||
for (size_t i = 0, n = node_inputs.size(); i < n; i++) {
|
for (size_t i = 0, n = node_inputs.size(); i < n; i++) {
|
||||||
|
@ -369,8 +370,8 @@ void AnimGraph::UpdateOrderedNodes() {
|
||||||
|
|
||||||
int input_node_index = getAnimNodeIndex(input_node);
|
int input_node_index = getAnimNodeIndex(input_node);
|
||||||
bool is_node_processed = false;
|
bool is_node_processed = false;
|
||||||
for (size_t j = 0, m = m_ordered_nodes.size(); j < m; j++) {
|
for (size_t j = 0, m = m_eval_ordered_nodes.size(); j < m; j++) {
|
||||||
if (m_ordered_nodes[j] == input_node) {
|
if (m_eval_ordered_nodes[j] == input_node) {
|
||||||
is_node_processed = true;
|
is_node_processed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -380,31 +381,61 @@ void AnimGraph::UpdateOrderedNodes() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ordered_nodes.push_back(input_node);
|
m_eval_ordered_nodes.push_back(input_node);
|
||||||
node_index_stack.push_back(input_node_index);
|
node_index_stack.push_back(input_node_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraph::MarkActiveNodes() {
|
void AnimGraph::MarkActiveNodes() {
|
||||||
m_frame_counter++;
|
for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
|
||||||
|
m_nodes[i]->m_state = AnimNodeEvalState::Deactivated;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<AnimNodeInput> graph_output_inputs = m_node_inputs[0];
|
const std::vector<AnimNodeInput> graph_output_inputs = m_node_inputs[0];
|
||||||
for (size_t i = 0, n = graph_output_inputs.size(); i < n; i++) {
|
for (size_t i = 0, n = graph_output_inputs.size(); i < n; i++) {
|
||||||
AnimNode* node = m_ordered_nodes[i];
|
AnimNode* node = m_eval_ordered_nodes[i];
|
||||||
if (node != nullptr) {
|
if (node != nullptr) {
|
||||||
node->m_frame_counter = m_frame_counter;
|
node->m_state = AnimNodeEvalState::Activated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0, n = m_ordered_nodes.size(); i < n; i++) {
|
for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) {
|
||||||
AnimNode* node = m_ordered_nodes[i];
|
AnimNode* node = m_eval_ordered_nodes[i];
|
||||||
if (CheckIsNodeActive(node)) {
|
if (CheckIsNodeActive(node)) {
|
||||||
int node_index = getAnimNodeIndex(node);
|
int node_index = getAnimNodeIndex(node);
|
||||||
node->UpdateActiveInputFrameCounters(m_node_inputs[node_index]);
|
node->MarkActiveInputs(m_node_inputs[node_index]);
|
||||||
} else {
|
}
|
||||||
// Avoid active frame counter overrun.
|
}
|
||||||
node->m_frame_counter = m_frame_counter - 1;
|
}
|
||||||
|
|
||||||
|
void AnimGraph::UpdateTime(float dt) {
|
||||||
|
const std::vector<AnimNodeInput> graph_output_inputs = m_node_inputs[0];
|
||||||
|
for (size_t i = 0, n = graph_output_inputs.size(); i < n; i++) {
|
||||||
|
AnimNode* node = m_eval_ordered_nodes[i];
|
||||||
|
if (node != nullptr) {
|
||||||
|
node->UpdateTime(node->m_time_now, node->m_time_now + dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) {
|
||||||
|
AnimNode* node = m_eval_ordered_nodes[i];
|
||||||
|
if (node->m_state != AnimNodeEvalState::TimeUpdated) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int node_index = getAnimNodeIndex(node);
|
||||||
|
const std::vector<AnimNodeInput> node_inputs = m_node_inputs[node_index];
|
||||||
|
float node_time_now = node->m_time_now;
|
||||||
|
float node_time_last = node->m_time_last;
|
||||||
|
|
||||||
|
for (size_t i = 0, n = node_inputs.size(); i < n; i++) {
|
||||||
|
AnimNode* input_node = node_inputs[i].m_node;
|
||||||
|
if (input_node != nullptr
|
||||||
|
&& input_node->m_state == AnimNodeEvalState::Activated
|
||||||
|
&& node_inputs[i].m_type == SocketType::SocketTypeAnimation) {
|
||||||
|
input_node->UpdateTime(node_time_last, node_time_now);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,4 +458,4 @@ void* AnimGraph::GetInput(const std::string& name) const {
|
||||||
return *(socket->m_value.ptr_ptr);
|
return *(socket->m_value.ptr_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace AnimGraphCode
|
|
@ -84,26 +84,42 @@ struct AnimNodeResource {
|
||||||
|
|
||||||
struct AnimNodeInput {
|
struct AnimNodeInput {
|
||||||
AnimNode* m_node;
|
AnimNode* m_node;
|
||||||
|
SocketType m_type = SocketType::SocketTypeUndefined;
|
||||||
std::string m_input_name;
|
std::string m_input_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class AnimNodeEvalState {
|
||||||
|
Undefined,
|
||||||
|
Deactivated,
|
||||||
|
Activated,
|
||||||
|
SyncTrackUpdated,
|
||||||
|
TimeUpdated,
|
||||||
|
Evaluated
|
||||||
|
};
|
||||||
|
|
||||||
struct AnimNode {
|
struct AnimNode {
|
||||||
virtual ~AnimNode(){};
|
virtual ~AnimNode(){};
|
||||||
|
|
||||||
virtual void UpdateActiveInputFrameCounters (const std::vector<AnimNodeInput>& inputs) {
|
virtual void MarkActiveInputs(const std::vector<AnimNodeInput>& inputs) {
|
||||||
for (size_t i = 0, n = inputs.size(); i < n; i++) {
|
for (size_t i = 0, n = inputs.size(); i < n; i++) {
|
||||||
if (inputs[i].m_node != nullptr) {
|
AnimNode* input_node = inputs[i].m_node;
|
||||||
inputs[i].m_node->m_frame_counter = m_frame_counter;
|
if (input_node != nullptr) {
|
||||||
|
input_node->m_state = AnimNodeEvalState::Activated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void UpdateTime(float time_last, float time_now) {
|
||||||
|
m_time_last = time_last;
|
||||||
|
m_time_now = time_now;
|
||||||
|
m_state = AnimNodeEvalState::TimeUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::string m_node_type_name;
|
std::string m_node_type_name;
|
||||||
bool m_is_time_synced;
|
float m_time_now = 0.f;
|
||||||
float m_time_now;
|
float m_time_last = 0.f;
|
||||||
float m_time_last;
|
AnimNodeEvalState m_state = AnimNodeEvalState::Undefined;
|
||||||
int m_frame_counter = 0;
|
|
||||||
SyncTrack m_sync_track;
|
SyncTrack m_sync_track;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -321,7 +337,7 @@ struct Blend2Node : public AnimNode {
|
||||||
bool m_sync_blend = false;
|
bool m_sync_blend = false;
|
||||||
|
|
||||||
|
|
||||||
virtual void UpdateActiveInputFrameCounters (const std::vector<AnimNodeInput>& inputs) override {
|
virtual void MarkActiveInputs(const std::vector<AnimNodeInput>& inputs) override {
|
||||||
for (size_t i = 0, n = inputs.size(); i < n; i++) {
|
for (size_t i = 0, n = inputs.size(); i < n; i++) {
|
||||||
AnimNode* input_node = inputs[i].m_node;
|
AnimNode* input_node = inputs[i].m_node;
|
||||||
if (input_node == nullptr) {
|
if (input_node == nullptr) {
|
||||||
|
@ -329,12 +345,33 @@ struct Blend2Node : public AnimNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputs[i].m_input_name == "Input0" && m_blend_weight < 0.999) {
|
if (inputs[i].m_input_name == "Input0" && m_blend_weight < 0.999) {
|
||||||
input_node->m_frame_counter = m_frame_counter;
|
input_node->m_state = AnimNodeEvalState::Activated;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputs[i].m_input_name == "Input1" && m_blend_weight > 0.001) {
|
if (inputs[i].m_input_name == "Input1" && m_blend_weight > 0.001) {
|
||||||
input_node->m_frame_counter = m_frame_counter;
|
input_node->m_state = AnimNodeEvalState::Activated;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void UpdateTime(float dt, std::vector<AnimNodeInput>& inputs) {
|
||||||
|
if (!m_sync_blend) {
|
||||||
|
m_time_now = m_time_now + dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0, n = inputs.size(); i < n; i++) {
|
||||||
|
AnimNode* input_node = inputs[i].m_node;
|
||||||
|
if (input_node == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input_node->m_state != AnimNodeEvalState::Deactivated) {
|
||||||
|
if (!m_sync_blend) {
|
||||||
|
input_node->m_time_now = m_time_now;
|
||||||
|
}
|
||||||
|
input_node->m_state = AnimNodeEvalState::TimeUpdated;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,6 +410,12 @@ struct SpeedScaleNode : public AnimNode {
|
||||||
AnimData m_input;
|
AnimData m_input;
|
||||||
AnimData* m_output = nullptr;
|
AnimData* m_output = nullptr;
|
||||||
float m_speed_scale = 0.f;
|
float m_speed_scale = 0.f;
|
||||||
|
|
||||||
|
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_state = AnimNodeEvalState::TimeUpdated;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -553,16 +596,22 @@ struct AnimGraph {
|
||||||
void UpdateOrderedNodes();
|
void UpdateOrderedNodes();
|
||||||
void MarkActiveNodes();
|
void MarkActiveNodes();
|
||||||
bool CheckIsNodeActive(AnimNode* node) {
|
bool CheckIsNodeActive(AnimNode* node) {
|
||||||
return node->m_frame_counter == m_frame_counter;
|
return node->m_state != AnimNodeEvalState::Deactivated;
|
||||||
}
|
}
|
||||||
void UpdateTime(float dt);
|
void UpdateTime(float dt);
|
||||||
void Evaluate();
|
void Evaluate();
|
||||||
|
void Reset() {
|
||||||
|
for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
|
||||||
|
m_nodes[i]->m_time_now = 0.f;
|
||||||
|
m_nodes[i]->m_time_last = 0.f;
|
||||||
|
m_nodes[i]->m_state = AnimNodeEvalState::Undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int m_frame_counter = 0;
|
|
||||||
AnimData m_local_transforms;
|
AnimData m_local_transforms;
|
||||||
|
|
||||||
std::vector<AnimNode*> m_nodes;
|
std::vector<AnimNode*> m_nodes;
|
||||||
std::vector<AnimNode*> m_ordered_nodes;
|
std::vector<AnimNode*> m_eval_ordered_nodes;
|
||||||
std::vector<std::vector<AnimNodeInput> > m_node_inputs;
|
std::vector<std::vector<AnimNodeInput> > m_node_inputs;
|
||||||
NodeSocketAccessorBase* m_socket_accessor;
|
NodeSocketAccessorBase* m_socket_accessor;
|
||||||
char* m_input_buffer = nullptr;
|
char* m_input_buffer = nullptr;
|
||||||
|
@ -574,9 +623,9 @@ struct AnimGraph {
|
||||||
void* GetOutput(const std::string& name) const;
|
void* GetOutput(const std::string& name) const;
|
||||||
void* GetInput(const std::string& name) const;
|
void* GetInput(const std::string& name) const;
|
||||||
|
|
||||||
int getAnimNodeOrderIndex(const AnimNode* node) {
|
int getNodeEvalOrderIndex(const AnimNode* node) {
|
||||||
for (size_t i = 0, n = m_ordered_nodes.size(); i < n; i++) {
|
for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) {
|
||||||
if (m_ordered_nodes[i] == node) {
|
if (m_eval_ordered_nodes[i] == node) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,6 +690,7 @@ struct AnimGraph {
|
||||||
node_resource.m_socket_accessor->m_inputs[j];
|
node_resource.m_socket_accessor->m_inputs[j];
|
||||||
AnimNodeInput input;
|
AnimNodeInput input;
|
||||||
input.m_node = nullptr;
|
input.m_node = nullptr;
|
||||||
|
input.m_type = input_socket.m_type;
|
||||||
input.m_input_name = input_socket.m_name;
|
input.m_input_name = input_socket.m_name;
|
||||||
|
|
||||||
node_inputs.push_back(input);
|
node_inputs.push_back(input);
|
||||||
|
@ -789,6 +839,7 @@ struct AnimGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
result.UpdateOrderedNodes();
|
result.UpdateOrderedNodes();
|
||||||
|
result.Reset();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,6 +247,9 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
|
||||||
graph_input_node.m_socket_accessor->RegisterOutput<float>(
|
graph_input_node.m_socket_accessor->RegisterOutput<float>(
|
||||||
"GraphFloatInput",
|
"GraphFloatInput",
|
||||||
nullptr);
|
nullptr);
|
||||||
|
graph_input_node.m_socket_accessor->RegisterOutput<float>(
|
||||||
|
"SpeedScaleInput",
|
||||||
|
nullptr);
|
||||||
graph_input_node.m_socket_accessor->RegisterOutput<AnimData>(
|
graph_input_node.m_socket_accessor->RegisterOutput<AnimData>(
|
||||||
"GraphAnimInput0",
|
"GraphAnimInput0",
|
||||||
nullptr);
|
nullptr);
|
||||||
|
@ -372,6 +375,12 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
|
||||||
blend2_node_resource,
|
blend2_node_resource,
|
||||||
"Weight"));
|
"Weight"));
|
||||||
|
|
||||||
|
REQUIRE(graph_resource.connectSockets(
|
||||||
|
graph_resource.getGraphInputNode(),
|
||||||
|
"SpeedScaleInput",
|
||||||
|
speed_scale_node_resource,
|
||||||
|
"SpeedScale"));
|
||||||
|
|
||||||
REQUIRE(graph_resource.connectSockets(
|
REQUIRE(graph_resource.connectSockets(
|
||||||
graph_resource.getGraphInputNode(),
|
graph_resource.getGraphInputNode(),
|
||||||
"GraphAnimInput0",
|
"GraphAnimInput0",
|
||||||
|
@ -440,14 +449,14 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
|
||||||
// check ordering
|
// check ordering
|
||||||
//
|
//
|
||||||
REQUIRE(
|
REQUIRE(
|
||||||
anim_graph.getAnimNodeOrderIndex(blend2_node)
|
anim_graph.getNodeEvalOrderIndex(blend2_node)
|
||||||
< anim_graph.getAnimNodeOrderIndex(sampler_node));
|
< anim_graph.getNodeEvalOrderIndex(sampler_node));
|
||||||
REQUIRE(
|
REQUIRE(
|
||||||
anim_graph.getAnimNodeOrderIndex(blend2_node)
|
anim_graph.getNodeEvalOrderIndex(blend2_node)
|
||||||
< anim_graph.getAnimNodeOrderIndex(speed_scale_node));
|
< anim_graph.getNodeEvalOrderIndex(speed_scale_node));
|
||||||
REQUIRE(
|
REQUIRE(
|
||||||
anim_graph.getAnimNodeOrderIndex(speed_scale_node)
|
anim_graph.getNodeEvalOrderIndex(speed_scale_node)
|
||||||
< anim_graph.getAnimNodeOrderIndex(sampler_node));
|
< anim_graph.getNodeEvalOrderIndex(sampler_node));
|
||||||
}
|
}
|
||||||
|
|
||||||
WHEN("Instantiating graph") {
|
WHEN("Instantiating graph") {
|
||||||
|
@ -491,6 +500,36 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
|
||||||
REQUIRE(anim_graph.CheckIsNodeActive(sampler_node) == true);
|
REQUIRE(anim_graph.CheckIsNodeActive(sampler_node) == true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WHEN("Updating time with dt = 0.3f and speed scale = 1.0f") {
|
||||||
|
float* speed_scale_input =
|
||||||
|
reinterpret_cast<float*>(anim_graph.GetInput("SpeedScaleInput"));
|
||||||
|
|
||||||
|
*blend_weight_input = 0.1;
|
||||||
|
*speed_scale_input = 1.0f;
|
||||||
|
|
||||||
|
anim_graph.MarkActiveNodes();
|
||||||
|
anim_graph.UpdateTime(0.3f);
|
||||||
|
|
||||||
|
THEN ("Anim sampler node time now must be 0.3f") {
|
||||||
|
REQUIRE(sampler_node->m_time_now == Approx(0.3f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("Updating time with dt = 0.3f and speed scale = 1.3f") {
|
||||||
|
float* speed_scale_input =
|
||||||
|
reinterpret_cast<float*>(anim_graph.GetInput("SpeedScaleInput"));
|
||||||
|
|
||||||
|
*blend_weight_input = 0.1;
|
||||||
|
*speed_scale_input = 1.3f;
|
||||||
|
|
||||||
|
anim_graph.MarkActiveNodes();
|
||||||
|
anim_graph.UpdateTime(0.3f);
|
||||||
|
|
||||||
|
THEN ("Anim sampler node time now must be 0.39f") {
|
||||||
|
REQUIRE(sampler_node->m_time_now == Approx(0.39f));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue