Added support of time updates for simple embedded graphs.
parent
0aebe44bd5
commit
76ea38f118
|
@ -32,8 +32,12 @@ void AnimGraphBlendTree::UpdateOrderedNodesRecursive(int node_index) {
|
||||||
const std::vector<AnimGraphConnection>& node_input_connections =
|
const std::vector<AnimGraphConnection>& node_input_connections =
|
||||||
m_node_input_connections[node_index];
|
m_node_input_connections[node_index];
|
||||||
for (size_t i = 0, n = node_input_connections.size(); i < n; i++) {
|
for (size_t i = 0, n = node_input_connections.size(); i < n; i++) {
|
||||||
|
if (node_input_connections[i].m_crosses_hierarchy) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int input_node_index =
|
int input_node_index =
|
||||||
GetAnimNodeIndex(node_input_connections.at(i).m_source_node);
|
GetAnimNodeIndex(node_input_connections[i].m_source_node);
|
||||||
|
|
||||||
if (input_node_index == 1) {
|
if (input_node_index == 1) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -58,9 +62,11 @@ void AnimGraphBlendTree::UpdateOrderedNodesRecursive(int node_index) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraphBlendTree::MarkActiveInputs() {
|
void AnimGraphBlendTree::MarkActiveInputs(const std::vector<AnimGraphConnection>& input_connections) {
|
||||||
for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
|
for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
|
||||||
m_nodes[i]->m_state = AnimNodeEvalState::Deactivated;
|
if (m_nodes[i]->m_tick_number != m_tick_number) {
|
||||||
|
m_nodes[i]->m_state = AnimNodeEvalState::Deactivated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<AnimGraphConnection>& graph_output_inputs =
|
const std::vector<AnimGraphConnection>& graph_output_inputs =
|
||||||
|
@ -69,15 +75,16 @@ void AnimGraphBlendTree::MarkActiveInputs() {
|
||||||
const AnimGraphConnection& graph_input = graph_output_inputs[i];
|
const AnimGraphConnection& graph_input = graph_output_inputs[i];
|
||||||
AnimNode* node = graph_input.m_source_node;
|
AnimNode* node = graph_input.m_source_node;
|
||||||
if (node != nullptr) {
|
if (node != nullptr) {
|
||||||
|
node->m_tick_number = m_tick_number;
|
||||||
node->m_state = AnimNodeEvalState::Activated;
|
node->m_state = AnimNodeEvalState::Activated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) {
|
for (int 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();
|
|
||||||
size_t node_index = GetAnimNodeIndex(node);
|
size_t node_index = GetAnimNodeIndex(node);
|
||||||
|
node->MarkActiveInputs(m_node_input_connections[node_index]);
|
||||||
|
|
||||||
// Non-animation data inputs are always active.
|
// Non-animation data inputs are always active.
|
||||||
for (size_t j = 0, nj = m_node_input_connections[node_index].size();
|
for (size_t j = 0, nj = m_node_input_connections[node_index].size();
|
||||||
|
@ -95,14 +102,14 @@ void AnimGraphBlendTree::MarkActiveInputs() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraphBlendTree::CalcSyncTrack() {
|
void AnimGraphBlendTree::CalcSyncTrack(const std::vector<AnimGraphConnection>& input_connections) {
|
||||||
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 (node->m_state == AnimNodeEvalState::Deactivated) {
|
if (node->m_state == AnimNodeEvalState::Deactivated) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->CalcSyncTrack();
|
node->CalcSyncTrack(m_node_input_connections[GetAnimNodeIndex(node)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,35 +120,21 @@ void AnimGraphBlendTree::UpdateTime(float time_last, float time_now) {
|
||||||
m_node_input_connections[0];
|
m_node_input_connections[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 = graph_output_inputs[i].m_source_node;
|
AnimNode* node = graph_output_inputs[i].m_source_node;
|
||||||
if (node != nullptr) {
|
if (node != nullptr && node->m_state != AnimNodeEvalState::TimeUpdated) {
|
||||||
node->UpdateTime(node->m_time_now, node->m_time_now + dt);
|
node->UpdateTime(time_last, time_now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = m_eval_ordered_nodes.size() - 1; i > 0; --i) {
|
for (int 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 (node->m_state != AnimNodeEvalState::TimeUpdated) {
|
if (node->m_state != AnimNodeEvalState::TimeUpdated) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t node_index = GetAnimNodeIndex(node);
|
PropagateTimeToNodeInputs(node);
|
||||||
float node_time_now = node->m_time_now;
|
|
||||||
float node_time_last = node->m_time_last;
|
|
||||||
|
|
||||||
const std::vector<AnimGraphConnection>& node_input_connections =
|
|
||||||
m_node_input_connections[node_index];
|
|
||||||
for (size_t i = 0, n = node_input_connections.size(); i < n; i++) {
|
|
||||||
AnimNode* input_node = node_input_connections[i].m_source_node;
|
|
||||||
|
|
||||||
// Only propagate time updates via animation sockets.
|
|
||||||
if (input_node != nullptr
|
|
||||||
&& node_input_connections[i].m_target_socket.m_type
|
|
||||||
== SocketType::SocketTypeAnimation
|
|
||||||
&& input_node->m_state == AnimNodeEvalState::Activated) {
|
|
||||||
input_node->UpdateTime(node_time_last, node_time_now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_state = AnimNodeEvalState::TimeUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraphBlendTree::Evaluate(AnimGraphContext& context) {
|
void AnimGraphBlendTree::Evaluate(AnimGraphContext& context) {
|
||||||
|
@ -156,6 +149,27 @@ void AnimGraphBlendTree::Evaluate(AnimGraphContext& context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimGraphBlendTree::PropagateTimeToNodeInputs(const AnimNode* node) {
|
||||||
|
size_t node_index = GetAnimNodeIndex(node);
|
||||||
|
|
||||||
|
float node_time_now = node->m_time_now;
|
||||||
|
float node_time_last = node->m_time_last;
|
||||||
|
|
||||||
|
const std::vector<AnimGraphConnection>& node_input_connections =
|
||||||
|
m_node_input_connections[node_index];
|
||||||
|
for (size_t i = 0, n = node_input_connections.size(); i < n; i++) {
|
||||||
|
AnimNode* input_node = node_input_connections[i].m_source_node;
|
||||||
|
|
||||||
|
// Only propagate time updates via animation sockets.
|
||||||
|
if (input_node != nullptr
|
||||||
|
&& node_input_connections[i].m_target_socket.m_type
|
||||||
|
== SocketType::SocketTypeAnimation
|
||||||
|
&& input_node->m_state == AnimNodeEvalState::Activated) {
|
||||||
|
input_node->UpdateTime(node_time_last, node_time_now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Socket* AnimGraphBlendTree::GetInputSocket(const std::string& name) {
|
Socket* AnimGraphBlendTree::GetInputSocket(const std::string& name) {
|
||||||
for (size_t i = 0, n = m_node_output_connections[1].size(); i < n; i++) {
|
for (size_t i = 0, n = m_node_output_connections[1].size(); i < n; i++) {
|
||||||
AnimGraphConnection& connection = m_node_output_connections[1][i];
|
AnimGraphConnection& connection = m_node_output_connections[1][i];
|
||||||
|
|
|
@ -31,13 +31,19 @@ struct AnimGraphBlendTree : public AnimNode {
|
||||||
|
|
||||||
~AnimGraphBlendTree() override { dealloc(); }
|
~AnimGraphBlendTree() override { dealloc(); }
|
||||||
|
|
||||||
|
void StartUpdateTick() { m_tick_number++; }
|
||||||
|
|
||||||
// AnimNode overrides
|
// AnimNode overrides
|
||||||
bool Init(AnimGraphContext& context) override;
|
bool Init(AnimGraphContext& context) override;
|
||||||
void MarkActiveInputs() override;
|
void MarkActiveInputs(
|
||||||
void CalcSyncTrack() override;
|
const std::vector<AnimGraphConnection>& input_connections) override;
|
||||||
|
void CalcSyncTrack(
|
||||||
|
const std::vector<AnimGraphConnection>& input_connections) override;
|
||||||
void UpdateTime(float time_last, float time_now) override;
|
void UpdateTime(float time_last, float time_now) override;
|
||||||
void Evaluate(AnimGraphContext& context) override;
|
void Evaluate(AnimGraphContext& context) override;
|
||||||
|
|
||||||
|
void PropagateTimeToNodeInputs(const AnimNode* node);
|
||||||
|
|
||||||
void dealloc() {
|
void dealloc() {
|
||||||
for (size_t i = 0; i < m_animdata_blocks.size(); i++) {
|
for (size_t i = 0; i < m_animdata_blocks.size(); i++) {
|
||||||
m_animdata_blocks[i]->m_local_matrices.vector::~vector();
|
m_animdata_blocks[i]->m_local_matrices.vector::~vector();
|
||||||
|
@ -62,8 +68,8 @@ struct AnimGraphBlendTree : public AnimNode {
|
||||||
|
|
||||||
void UpdateOrderedNodes();
|
void UpdateOrderedNodes();
|
||||||
void UpdateOrderedNodesRecursive(int node_index);
|
void UpdateOrderedNodesRecursive(int node_index);
|
||||||
bool checkIsNodeActive(AnimNode* node) {
|
bool CheckIsNodeActive(AnimNode* node) {
|
||||||
return node->m_state != AnimNodeEvalState::Deactivated;
|
return node->m_tick_number == m_tick_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetNodeStates() {
|
void ResetNodeStates() {
|
||||||
|
@ -117,9 +123,10 @@ struct AnimGraphBlendTree : public AnimNode {
|
||||||
if (graph_output_connection.m_target_socket.m_name == name) {
|
if (graph_output_connection.m_target_socket.m_name == name) {
|
||||||
if (graph_output_connection.m_source_node == m_nodes[1]
|
if (graph_output_connection.m_source_node == m_nodes[1]
|
||||||
&& graph_output_connection.m_target_node == m_nodes[0]) {
|
&& graph_output_connection.m_target_node == m_nodes[0]) {
|
||||||
std::cerr << "Error: cannot set output for direct graph input to graph "
|
std::cerr
|
||||||
"output connections. Use GetOutptPtr for output instead!"
|
<< "Error: cannot set output for direct graph input to graph "
|
||||||
<< std::endl;
|
"output connections. Use GetOutptPtr for output instead!"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -130,14 +137,18 @@ struct AnimGraphBlendTree : public AnimNode {
|
||||||
// Make sure all other output connections of this pin use the same output pointer
|
// Make sure all other output connections of this pin use the same output pointer
|
||||||
int source_node_index =
|
int source_node_index =
|
||||||
GetAnimNodeIndex(graph_output_connection.m_source_node);
|
GetAnimNodeIndex(graph_output_connection.m_source_node);
|
||||||
for (int j = 0; j < m_node_output_connections[source_node_index].size(); j++) {
|
for (int j = 0; j < m_node_output_connections[source_node_index].size();
|
||||||
const AnimGraphConnection& source_output_connection = m_node_output_connections[source_node_index][j];
|
j++) {
|
||||||
|
const AnimGraphConnection& source_output_connection =
|
||||||
|
m_node_output_connections[source_node_index][j];
|
||||||
if (source_output_connection.m_target_node == m_nodes[0]) {
|
if (source_output_connection.m_target_node == m_nodes[0]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source_output_connection.m_source_socket.m_name == graph_output_connection.m_source_socket.m_name) {
|
if (source_output_connection.m_source_socket.m_name
|
||||||
*source_output_connection.m_target_socket.m_reference.ptr_ptr = value_ptr;
|
== graph_output_connection.m_source_socket.m_name) {
|
||||||
|
*source_output_connection.m_target_socket.m_reference.ptr_ptr =
|
||||||
|
value_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +170,8 @@ struct AnimGraphBlendTree : public AnimNode {
|
||||||
const AnimGraphConnection& graph_output_connection =
|
const AnimGraphConnection& graph_output_connection =
|
||||||
m_node_input_connections[0][i];
|
m_node_input_connections[0][i];
|
||||||
if (graph_output_connection.m_target_socket.m_name == name) {
|
if (graph_output_connection.m_target_socket.m_name == name) {
|
||||||
return static_cast<float*>(*graph_output_connection.m_source_socket.m_reference.ptr_ptr);
|
return static_cast<float*>(
|
||||||
|
*graph_output_connection.m_source_socket.m_reference.ptr_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +231,7 @@ struct AnimGraphBlendTree : public AnimNode {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetAnimNodeIndex(AnimNode* node) {
|
size_t GetAnimNodeIndex(const AnimNode* node) const {
|
||||||
for (size_t i = 0; i < m_nodes.size(); i++) {
|
for (size_t i = 0; i < m_nodes.size(); i++) {
|
||||||
if (m_nodes[i] == node) {
|
if (m_nodes[i] == node) {
|
||||||
return i;
|
return i;
|
||||||
|
@ -230,5 +242,14 @@ struct AnimGraphBlendTree : public AnimNode {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// BlendTreeSocketNode
|
||||||
|
//
|
||||||
|
struct BlendTreeSocketNode : public AnimNode {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct NodeDescriptor<BlendTreeSocketNode> : public NodeDescriptorBase {
|
||||||
|
NodeDescriptor(BlendTreeSocketNode* node_) {}
|
||||||
|
};
|
||||||
|
|
||||||
#endif //ANIMTESTBED_ANIMGRAPHBLENDTREE_H
|
#endif //ANIMTESTBED_ANIMGRAPHBLENDTREE_H
|
||||||
|
|
|
@ -265,6 +265,7 @@ struct AnimGraphConnection {
|
||||||
Socket m_source_socket;
|
Socket m_source_socket;
|
||||||
AnimNode* m_target_node = nullptr;
|
AnimNode* m_target_node = nullptr;
|
||||||
Socket m_target_socket;
|
Socket m_target_socket;
|
||||||
|
bool m_crosses_hierarchy = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,14 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "3rdparty/imgui-node-editor/imgui_node_editor.h"
|
#include "3rdparty/imgui-node-editor/imgui_node_editor.h"
|
||||||
#include "AnimGraphBlendTreeResource.h"
|
#include "AnimGraphResource.h"
|
||||||
#include "SkinnedMesh.h"
|
#include "SkinnedMesh.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "imnodes.h"
|
#include "imnodes.h"
|
||||||
#include "misc/cpp/imgui_stdlib.h"
|
#include "misc/cpp/imgui_stdlib.h"
|
||||||
|
|
||||||
static AnimGraphBlendTreeResource sGraphGresource =
|
static AnimGraphResource sGraphGresource =
|
||||||
AnimGraphBlendTreeResource();
|
AnimGraphResource();
|
||||||
static bool sGraphLoadedThisFrame = false;
|
static bool sGraphLoadedThisFrame = false;
|
||||||
|
|
||||||
ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
|
ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
|
||||||
|
@ -59,13 +59,13 @@ void NodeSocketEditor(Socket& socket) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveConnectionsForSocket(
|
void RemoveConnectionsForSocket(
|
||||||
AnimGraphBlendTreeResource& graph_resource,
|
AnimGraphResource& graph_resource,
|
||||||
AnimNodeResource& node_resource,
|
AnimNodeResource& node_resource,
|
||||||
Socket& socket) {
|
Socket& socket) {
|
||||||
std::vector<AnimGraphConnectionResource>::iterator iter =
|
std::vector<BlendTreeConnectionResource>::iterator iter =
|
||||||
graph_resource.m_connections.begin();
|
graph_resource.m_blend_tree_resource.m_connections.begin();
|
||||||
|
|
||||||
while (iter != graph_resource.m_connections.end()) {
|
while (iter != graph_resource.m_blend_tree_resource.m_connections.end()) {
|
||||||
// TODO adjust for refactor
|
// TODO adjust for refactor
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "AnimGraphNodes.h"
|
#include "AnimGraphNodes.h"
|
||||||
#include "AnimGraphBlendTree.h"
|
|
||||||
|
|
||||||
#include "ozz/base/log.h"
|
#include "AnimGraphBlendTree.h"
|
||||||
#include "ozz/animation/runtime/blending_job.h"
|
|
||||||
#include "ozz/animation/runtime/animation.h"
|
#include "ozz/animation/runtime/animation.h"
|
||||||
|
#include "ozz/animation/runtime/blending_job.h"
|
||||||
#include "ozz/base/io/archive.h"
|
#include "ozz/base/io/archive.h"
|
||||||
#include "ozz/base/io/stream.h"
|
#include "ozz/base/io/stream.h"
|
||||||
|
#include "ozz/base/log.h"
|
||||||
|
|
||||||
AnimNode* AnimNodeFactory(const std::string& name) {
|
AnimNode* AnimNodeFactory(const std::string& name) {
|
||||||
AnimNode* result;
|
AnimNode* result;
|
||||||
|
@ -24,7 +24,7 @@ AnimNode* AnimNodeFactory(const std::string& name) {
|
||||||
} else if (name == "BlendTree") {
|
} else if (name == "BlendTree") {
|
||||||
result = new AnimGraphBlendTree;
|
result = new AnimGraphBlendTree;
|
||||||
} else if (name == "BlendTreeSockets") {
|
} else if (name == "BlendTreeSockets") {
|
||||||
result = new BlendTreeNode;
|
result = new BlendTreeSocketNode;
|
||||||
} else if (name == "MathAddNode") {
|
} else if (name == "MathAddNode") {
|
||||||
result = new MathAddNode;
|
result = new MathAddNode;
|
||||||
} else if (name == "MathFloatToVec3Node") {
|
} else if (name == "MathFloatToVec3Node") {
|
||||||
|
@ -42,12 +42,39 @@ AnimNode* AnimNodeFactory(const std::string& name) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeDescriptorBase* AnimNodeDescriptorFactory(
|
||||||
|
const std::string& node_type_name,
|
||||||
|
AnimNode* node) {
|
||||||
|
if (node_type_name == "Blend2") {
|
||||||
|
return CreateNodeDescriptor<Blend2Node>(node);
|
||||||
|
} else if (node_type_name == "SpeedScale") {
|
||||||
|
return CreateNodeDescriptor<SpeedScaleNode>(node);
|
||||||
|
} else if (node_type_name == "AnimSampler") {
|
||||||
|
return CreateNodeDescriptor<AnimSamplerNode>(node);
|
||||||
|
} else if (node_type_name == "LockTranslationNode") {
|
||||||
|
return CreateNodeDescriptor<LockTranslationNode>(node);
|
||||||
|
} else if (node_type_name == "BlendTree") {
|
||||||
|
return CreateNodeDescriptor<BlendTreeSocketNode>(node);
|
||||||
|
} else if (node_type_name == "BlendTreeSockets") {
|
||||||
|
return CreateNodeDescriptor<BlendTreeSocketNode>(node);
|
||||||
|
} else if (node_type_name == "MathAddNode") {
|
||||||
|
return CreateNodeDescriptor<MathAddNode>(node);
|
||||||
|
} else if (node_type_name == "MathFloatToVec3Node") {
|
||||||
|
return CreateNodeDescriptor<MathFloatToVec3Node>(node);
|
||||||
|
} else if (node_type_name == "ConstScalarNode") {
|
||||||
|
return CreateNodeDescriptor<ConstScalarNode>(node);
|
||||||
|
} else {
|
||||||
|
std::cerr << "Invalid node type name " << 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);
|
||||||
assert (i_blend_weight != nullptr);
|
assert(i_blend_weight != nullptr);
|
||||||
assert (o_output != nullptr);
|
assert(o_output != nullptr);
|
||||||
|
|
||||||
// perform blend
|
// perform blend
|
||||||
ozz::animation::BlendingJob::Layer layers[2];
|
ozz::animation::BlendingJob::Layer layers[2];
|
||||||
|
@ -71,12 +98,10 @@ void Blend2Node::Evaluate(AnimGraphContext& context) {
|
||||||
//
|
//
|
||||||
// AnimSamplerNode
|
// AnimSamplerNode
|
||||||
//
|
//
|
||||||
AnimSamplerNode::~AnimSamplerNode() noexcept {
|
AnimSamplerNode::~AnimSamplerNode() noexcept { m_animation = nullptr; }
|
||||||
m_animation = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AnimSamplerNode::Init(AnimGraphContext& context) {
|
bool AnimSamplerNode::Init(AnimGraphContext& context) {
|
||||||
assert (m_animation == nullptr);
|
assert(m_animation == nullptr);
|
||||||
assert(!m_filename.empty());
|
assert(!m_filename.empty());
|
||||||
|
|
||||||
AnimGraphContext::AnimationFileMap::const_iterator animation_map_iter;
|
AnimGraphContext::AnimationFileMap::const_iterator animation_map_iter;
|
||||||
|
@ -103,14 +128,14 @@ bool AnimSamplerNode::Init(AnimGraphContext& context) {
|
||||||
context.m_animation_map[m_filename] = m_animation;
|
context.m_animation_map[m_filename] = m_animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert (context.m_skeleton != nullptr);
|
assert(context.m_skeleton != nullptr);
|
||||||
m_sampling_context.Resize(context.m_skeleton->num_joints());
|
m_sampling_context.Resize(context.m_skeleton->num_joints());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimSamplerNode::Evaluate(AnimGraphContext& context) {
|
void AnimSamplerNode::Evaluate(AnimGraphContext& context) {
|
||||||
assert (o_output != nullptr);
|
assert(o_output != nullptr);
|
||||||
|
|
||||||
ozz::animation::SamplingJob sampling_job;
|
ozz::animation::SamplingJob sampling_job;
|
||||||
sampling_job.animation = m_animation;
|
sampling_job.animation = m_animation;
|
||||||
|
|
|
@ -7,23 +7,13 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "AnimNode.h"
|
|
||||||
#include "AnimGraphData.h"
|
#include "AnimGraphData.h"
|
||||||
|
#include "AnimNode.h"
|
||||||
#include "SyncTrack.h"
|
#include "SyncTrack.h"
|
||||||
#include "ozz/animation/runtime/sampling_job.h"
|
#include "ozz/animation/runtime/sampling_job.h"
|
||||||
|
|
||||||
struct AnimNode;
|
struct AnimNode;
|
||||||
|
|
||||||
//
|
|
||||||
// BlendTreeNode
|
|
||||||
//
|
|
||||||
struct BlendTreeNode : public AnimNode {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct NodeDescriptor<BlendTreeNode> : public NodeDescriptorBase {
|
|
||||||
NodeDescriptor(BlendTreeNode* node_) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Blend2Node
|
// Blend2Node
|
||||||
//
|
//
|
||||||
|
@ -34,8 +24,9 @@ struct Blend2Node : public AnimNode {
|
||||||
float* i_blend_weight = nullptr;
|
float* i_blend_weight = nullptr;
|
||||||
bool m_sync_blend = false;
|
bool m_sync_blend = false;
|
||||||
|
|
||||||
virtual void MarkActiveInputs() override {
|
void MarkActiveInputs(
|
||||||
for (const auto & input : m_inputs) {
|
const std::vector<AnimGraphConnection>& input_connections) override {
|
||||||
|
for (const auto& input : input_connections) {
|
||||||
AnimNode* input_node = input.m_source_node;
|
AnimNode* input_node = input.m_source_node;
|
||||||
if (input_node == nullptr) {
|
if (input_node == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -53,7 +44,7 @@ struct Blend2Node : public AnimNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Evaluate(AnimGraphContext& context) override;
|
void Evaluate(AnimGraphContext& context) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -80,7 +71,6 @@ struct NodeDescriptor<Blend2Node> : public NodeDescriptorBase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// SpeedScaleNode
|
// SpeedScaleNode
|
||||||
//
|
//
|
||||||
|
@ -96,8 +86,8 @@ struct SpeedScaleNode : public AnimNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Evaluate(AnimGraphContext& context) override {
|
void Evaluate(AnimGraphContext& context) override {
|
||||||
assert (i_input != nullptr);
|
assert(i_input != nullptr);
|
||||||
assert (o_output != nullptr);
|
assert(o_output != nullptr);
|
||||||
|
|
||||||
o_output->m_local_matrices = i_input->m_local_matrices;
|
o_output->m_local_matrices = i_input->m_local_matrices;
|
||||||
};
|
};
|
||||||
|
@ -116,7 +106,6 @@ struct NodeDescriptor<SpeedScaleNode> : public NodeDescriptorBase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// AnimSamplerNode
|
// AnimSamplerNode
|
||||||
//
|
//
|
||||||
|
@ -172,7 +161,6 @@ struct NodeDescriptor<LockTranslationNode> : public NodeDescriptorBase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// ConstScalarNode
|
// ConstScalarNode
|
||||||
//
|
//
|
||||||
|
@ -180,9 +168,7 @@ struct ConstScalarNode : public AnimNode {
|
||||||
float* o_value = nullptr;
|
float* o_value = nullptr;
|
||||||
float value = 0.f;
|
float value = 0.f;
|
||||||
|
|
||||||
virtual void Evaluate(AnimGraphContext& context){
|
virtual void Evaluate(AnimGraphContext& context) { *o_value = value; };
|
||||||
*o_value = value;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -193,7 +179,6 @@ struct NodeDescriptor<ConstScalarNode> : public NodeDescriptorBase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// MathAddNode
|
// MathAddNode
|
||||||
//
|
//
|
||||||
|
@ -203,8 +188,8 @@ struct MathAddNode : public AnimNode {
|
||||||
float* o_output = nullptr;
|
float* o_output = nullptr;
|
||||||
|
|
||||||
void Evaluate(AnimGraphContext& context) override {
|
void Evaluate(AnimGraphContext& context) override {
|
||||||
assert (i_input0 != nullptr);
|
assert(i_input0 != nullptr);
|
||||||
assert (i_input1 != nullptr);
|
assert(i_input1 != nullptr);
|
||||||
|
|
||||||
*o_output = *i_input0 + *i_input1;
|
*o_output = *i_input0 + *i_input1;
|
||||||
}
|
}
|
||||||
|
@ -229,9 +214,9 @@ struct MathFloatToVec3Node : public AnimNode {
|
||||||
Vec3* o_output = nullptr;
|
Vec3* o_output = nullptr;
|
||||||
|
|
||||||
void Evaluate(AnimGraphContext& context) override {
|
void Evaluate(AnimGraphContext& context) override {
|
||||||
assert (i_input0 != nullptr);
|
assert(i_input0 != nullptr);
|
||||||
assert (i_input1 != nullptr);
|
assert(i_input1 != nullptr);
|
||||||
assert (i_input2 != nullptr);
|
assert(i_input2 != nullptr);
|
||||||
|
|
||||||
o_output->v[0] = *i_input0;
|
o_output->v[0] = *i_input0;
|
||||||
o_output->v[1] = *i_input1;
|
o_output->v[1] = *i_input1;
|
||||||
|
@ -249,35 +234,10 @@ struct NodeDescriptor<MathFloatToVec3Node> : public NodeDescriptorBase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
AnimNode* AnimNodeFactory(const std::string& name);
|
AnimNode* AnimNodeFactory(const std::string& name);
|
||||||
|
|
||||||
static inline NodeDescriptorBase* AnimNodeDescriptorFactory(
|
NodeDescriptorBase* AnimNodeDescriptorFactory(
|
||||||
const std::string& node_type_name,
|
const std::string& node_type_name,
|
||||||
AnimNode* node) {
|
AnimNode* node);
|
||||||
if (node_type_name == "Blend2") {
|
|
||||||
return CreateNodeDescriptor<Blend2Node>(node);
|
|
||||||
} else if (node_type_name == "SpeedScale") {
|
|
||||||
return CreateNodeDescriptor<SpeedScaleNode>(node);
|
|
||||||
} else if (node_type_name == "AnimSampler") {
|
|
||||||
return CreateNodeDescriptor<AnimSamplerNode>(node);
|
|
||||||
} else if (node_type_name == "LockTranslationNode") {
|
|
||||||
return CreateNodeDescriptor<LockTranslationNode>(node);
|
|
||||||
} else if (node_type_name == "BlendTree") {
|
|
||||||
return CreateNodeDescriptor<BlendTreeNode>(node);
|
|
||||||
} else if (node_type_name == "BlendTreeSockets") {
|
|
||||||
return CreateNodeDescriptor<BlendTreeNode>(node);
|
|
||||||
} else if (node_type_name == "MathAddNode") {
|
|
||||||
return CreateNodeDescriptor<MathAddNode>(node);
|
|
||||||
} else if (node_type_name == "MathFloatToVec3Node") {
|
|
||||||
return CreateNodeDescriptor<MathFloatToVec3Node>(node);
|
|
||||||
} else if (node_type_name == "ConstScalarNode") {
|
|
||||||
return CreateNodeDescriptor<ConstScalarNode>(node);
|
|
||||||
} else {
|
|
||||||
std::cerr << "Invalid node type name " << node_type_name << "."
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //ANIMTESTBED_ANIMGRAPHNODES_H
|
#endif //ANIMTESTBED_ANIMGRAPHNODES_H
|
||||||
|
|
|
@ -8,15 +8,17 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "3rdparty/json/json.hpp"
|
#include "3rdparty/json/json.hpp"
|
||||||
|
|
||||||
#include "AnimGraphBlendTree.h"
|
#include "AnimGraphBlendTree.h"
|
||||||
#include "AnimGraphNodes.h"
|
#include "AnimGraphNodes.h"
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
// forward declarations
|
// forward declarations
|
||||||
static json sAnimGraphResourceBlendTreeToJson(const AnimGraphResource& anim_graph_resource);
|
static json sAnimGraphResourceBlendTreeToJson(
|
||||||
static bool sAnimGraphResourceBlendTreeFromJson(const json& json_data, AnimGraphResource* result_graph_resource);
|
const AnimGraphResource& anim_graph_resource);
|
||||||
|
static bool sAnimGraphResourceBlendTreeFromJson(
|
||||||
|
const json& json_data,
|
||||||
|
AnimGraphResource* result_graph_resource);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Socket <-> json
|
// Socket <-> json
|
||||||
|
@ -143,7 +145,6 @@ json sAnimGraphNodeToJson(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->m_node_type_name == "BlendTree") {
|
if (node->m_node_type_name == "BlendTree") {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& socket : node->m_socket_accessor->m_inputs) {
|
for (const auto& socket : node->m_socket_accessor->m_inputs) {
|
||||||
|
@ -175,7 +176,6 @@ json sAnimGraphNodeToJson(
|
||||||
AnimNodeResource* sAnimGraphNodeFromJson(
|
AnimNodeResource* sAnimGraphNodeFromJson(
|
||||||
const json& json_node,
|
const json& json_node,
|
||||||
size_t node_index) {
|
size_t node_index) {
|
||||||
|
|
||||||
std::string node_type = json_node["node_type"];
|
std::string node_type = json_node["node_type"];
|
||||||
|
|
||||||
if (node_type == "BlendTree") {
|
if (node_type == "BlendTree") {
|
||||||
|
@ -247,20 +247,23 @@ BlendTreeConnectionResource sAnimGraphConnectionFromJson(
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
static json sAnimGraphResourceBlendTreeToJson(const AnimGraphResource& anim_graph_resource) {
|
static json sAnimGraphResourceBlendTreeToJson(
|
||||||
|
const AnimGraphResource& anim_graph_resource) {
|
||||||
json result;
|
json result;
|
||||||
|
|
||||||
result["name"] = anim_graph_resource.m_name;
|
result["name"] = anim_graph_resource.m_name;
|
||||||
result["type"] = "AnimNodeResource";
|
result["type"] = "AnimNodeResource";
|
||||||
result["node_type"] = "BlendTree";
|
result["node_type"] = "BlendTree";
|
||||||
|
|
||||||
const BlendTreeResource& blend_tree_resource = anim_graph_resource.m_blend_tree_resource;
|
const BlendTreeResource& blend_tree_resource =
|
||||||
|
anim_graph_resource.m_blend_tree_resource;
|
||||||
|
|
||||||
for (size_t i = 0; i < blend_tree_resource.m_nodes.size(); i++) {
|
for (size_t i = 0; i < blend_tree_resource.m_nodes.size(); i++) {
|
||||||
const AnimNodeResource* node = blend_tree_resource.m_nodes[i];
|
const AnimNodeResource* node = blend_tree_resource.m_nodes[i];
|
||||||
|
|
||||||
if (node->m_node_type_name == "BlendTree") {
|
if (node->m_node_type_name == "BlendTree") {
|
||||||
const AnimGraphResource* graph_resource = dynamic_cast<const AnimGraphResource*>(node);
|
const AnimGraphResource* graph_resource =
|
||||||
|
dynamic_cast<const AnimGraphResource*>(node);
|
||||||
result["nodes"][i] = sAnimGraphResourceBlendTreeToJson(*graph_resource);
|
result["nodes"][i] = sAnimGraphResourceBlendTreeToJson(*graph_resource);
|
||||||
} else {
|
} else {
|
||||||
result["nodes"][i] =
|
result["nodes"][i] =
|
||||||
|
@ -276,8 +279,7 @@ static json sAnimGraphResourceBlendTreeToJson(const AnimGraphResource& anim_grap
|
||||||
|
|
||||||
// Graph inputs and outputs
|
// Graph inputs and outputs
|
||||||
{
|
{
|
||||||
const AnimNodeResource* graph_output_node =
|
const AnimNodeResource* graph_output_node = blend_tree_resource.m_nodes[0];
|
||||||
blend_tree_resource.m_nodes[0];
|
|
||||||
const std::vector<Socket> graph_inputs =
|
const std::vector<Socket> graph_inputs =
|
||||||
graph_output_node->m_socket_accessor->m_inputs;
|
graph_output_node->m_socket_accessor->m_inputs;
|
||||||
for (size_t i = 0; i < graph_inputs.size(); i++) {
|
for (size_t i = 0; i < graph_inputs.size(); i++) {
|
||||||
|
@ -294,8 +296,11 @@ static json sAnimGraphResourceBlendTreeToJson(const AnimGraphResource& anim_grap
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sAnimGraphResourceBlendTreeFromJson(const json& json_data, AnimGraphResource* result_graph_resource) {
|
static bool sAnimGraphResourceBlendTreeFromJson(
|
||||||
BlendTreeResource& blend_tree_resource = result_graph_resource->m_blend_tree_resource;
|
const json& json_data,
|
||||||
|
AnimGraphResource* result_graph_resource) {
|
||||||
|
BlendTreeResource& blend_tree_resource =
|
||||||
|
result_graph_resource->m_blend_tree_resource;
|
||||||
|
|
||||||
result_graph_resource->m_graph_type_name = "BlendTree";
|
result_graph_resource->m_graph_type_name = "BlendTree";
|
||||||
result_graph_resource->m_node_type_name = "BlendTree";
|
result_graph_resource->m_node_type_name = "BlendTree";
|
||||||
|
@ -351,14 +356,14 @@ static bool sAnimGraphResourceBlendTreeFromJson(const json& json_data, AnimGraph
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlendTreeResource::ConnectSockets (
|
bool BlendTreeResource::ConnectSockets(
|
||||||
const AnimNodeResource* source_node,
|
const AnimNodeResource* source_node,
|
||||||
const std::string& source_socket_name,
|
const std::string& source_socket_name,
|
||||||
const AnimNodeResource* target_node,
|
const AnimNodeResource* target_node,
|
||||||
const std::string& target_socket_name) {
|
const std::string& target_socket_name) {
|
||||||
size_t source_node_index = GetNodeIndex(source_node);
|
size_t source_node_index = GetNodeIndex(source_node);
|
||||||
size_t target_node_index = GetNodeIndex(target_node);
|
size_t target_node_index = GetNodeIndex(target_node);
|
||||||
|
|
||||||
if (source_node_index >= m_nodes.size()
|
if (source_node_index >= m_nodes.size()
|
||||||
|| target_node_index >= m_nodes.size()) {
|
|| target_node_index >= m_nodes.size()) {
|
||||||
std::cerr << "Cannot connect nodes: could not find nodes." << std::endl;
|
std::cerr << "Cannot connect nodes: could not find nodes." << std::endl;
|
||||||
|
@ -369,23 +374,29 @@ bool BlendTreeResource::ConnectSockets (
|
||||||
Socket* target_socket;
|
Socket* target_socket;
|
||||||
|
|
||||||
if (target_node->m_node_type_name == "BlendTree") {
|
if (target_node->m_node_type_name == "BlendTree") {
|
||||||
const AnimGraphResource* target_graph_resource = dynamic_cast<const AnimGraphResource*>(target_node);
|
const AnimGraphResource* target_graph_resource =
|
||||||
AnimNodeResource* graph_output_node = target_graph_resource->m_blend_tree_resource.GetGraphInputNode();
|
dynamic_cast<const AnimGraphResource*>(target_node);
|
||||||
target_socket = graph_output_node->m_socket_accessor->GetOutputSocket(target_socket_name.c_str());
|
AnimNodeResource* graph_output_node =
|
||||||
|
target_graph_resource->m_blend_tree_resource.GetGraphInputNode();
|
||||||
|
target_socket = graph_output_node->m_socket_accessor->GetOutputSocket(
|
||||||
|
target_socket_name.c_str());
|
||||||
} else {
|
} else {
|
||||||
target_socket =
|
target_socket = target_node->m_socket_accessor->GetInputSocket(
|
||||||
target_node->m_socket_accessor->GetInputSocket(target_socket_name.c_str());
|
target_socket_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source_node->m_node_type_name == "BlendTree") {
|
if (source_node->m_node_type_name == "BlendTree") {
|
||||||
const AnimGraphResource* source_graph_resource = dynamic_cast<const AnimGraphResource*>(source_node);
|
const AnimGraphResource* source_graph_resource =
|
||||||
AnimNodeResource* graph_output_node = source_graph_resource->m_blend_tree_resource.GetGraphOutputNode();
|
dynamic_cast<const AnimGraphResource*>(source_node);
|
||||||
source_socket = graph_output_node->m_socket_accessor->GetInputSocket(source_socket_name.c_str());
|
AnimNodeResource* graph_output_node =
|
||||||
|
source_graph_resource->m_blend_tree_resource.GetGraphOutputNode();
|
||||||
|
source_socket = graph_output_node->m_socket_accessor->GetInputSocket(
|
||||||
|
source_socket_name.c_str());
|
||||||
} else {
|
} else {
|
||||||
source_socket =
|
source_socket = source_node->m_socket_accessor->GetOutputSocket(
|
||||||
source_node->m_socket_accessor->GetOutputSocket(source_socket_name.c_str());
|
source_socket_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source_socket == nullptr || target_socket == nullptr) {
|
if (source_socket == nullptr || target_socket == nullptr) {
|
||||||
std::cerr << "Cannot connect nodes: could not find sockets." << std::endl;
|
std::cerr << "Cannot connect nodes: could not find sockets." << std::endl;
|
||||||
return false;
|
return false;
|
||||||
|
@ -443,7 +454,8 @@ bool AnimGraphResource::SaveToFile(const char* filename) const {
|
||||||
return SaveStateMachineResourceToFile(filename);
|
return SaveStateMachineResourceToFile(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Invalid AnimGraphResource type: " << m_graph_type_name << "." << std::endl;
|
std::cerr << "Invalid AnimGraphResource type: " << m_graph_type_name << "."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -452,8 +464,7 @@ bool AnimGraphResource::SaveBlendTreeResourceToFile(
|
||||||
const char* filename) const {
|
const char* filename) const {
|
||||||
json result;
|
json result;
|
||||||
|
|
||||||
result = sAnimGraphResourceBlendTreeToJson(
|
result = sAnimGraphResourceBlendTreeToJson(*this);
|
||||||
*this);
|
|
||||||
|
|
||||||
std::ofstream output_file;
|
std::ofstream output_file;
|
||||||
output_file.open(filename);
|
output_file.open(filename);
|
||||||
|
@ -466,14 +477,18 @@ bool AnimGraphResource::SaveBlendTreeResourceToFile(
|
||||||
void AnimGraphResource::CreateBlendTreeInstance(
|
void AnimGraphResource::CreateBlendTreeInstance(
|
||||||
AnimGraphBlendTree& result) const {
|
AnimGraphBlendTree& result) const {
|
||||||
if (m_node_type_name != "BlendTree") {
|
if (m_node_type_name != "BlendTree") {
|
||||||
std::cerr << "Invalid AnimGraphResource. Expected type 'BlendTree' but got '"
|
std::cerr
|
||||||
<< m_graph_type_name << "'." << std::endl;
|
<< "Invalid AnimGraphResource. Expected type 'BlendTree' but got '"
|
||||||
|
<< m_graph_type_name << "'." << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.m_name = m_name;
|
||||||
|
|
||||||
CreateBlendTreeRuntimeNodeInstances(result);
|
CreateBlendTreeRuntimeNodeInstances(result);
|
||||||
PrepareBlendTreeIOData(result);
|
PrepareBlendTreeIOData(result);
|
||||||
SetRuntimeNodeProperties(result);
|
SetRuntimeNodeProperties(result);
|
||||||
|
CreateBlendTreeConnectionInstances(result);
|
||||||
|
|
||||||
result.UpdateOrderedNodes();
|
result.UpdateOrderedNodes();
|
||||||
result.ResetNodeStates();
|
result.ResetNodeStates();
|
||||||
|
@ -485,14 +500,19 @@ void AnimGraphResource::CreateBlendTreeRuntimeNodeInstances(
|
||||||
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") {
|
if (node_resource->m_node_type_name == "BlendTree") {
|
||||||
AnimGraphResource* embedded_blend_tree_resource = dynamic_cast<AnimGraphResource*>(node_resource);
|
AnimGraphResource* embedded_blend_tree_resource =
|
||||||
|
dynamic_cast<AnimGraphResource*>(node_resource);
|
||||||
assert(embedded_blend_tree_resource != nullptr);
|
assert(embedded_blend_tree_resource != nullptr);
|
||||||
AnimGraphBlendTree* embedded_blend_tree = dynamic_cast<AnimGraphBlendTree*>(node);
|
AnimGraphBlendTree* embedded_blend_tree =
|
||||||
|
dynamic_cast<AnimGraphBlendTree*>(node);
|
||||||
assert(embedded_blend_tree != nullptr);
|
assert(embedded_blend_tree != nullptr);
|
||||||
|
|
||||||
embedded_blend_tree_resource->CreateBlendTreeInstance(*embedded_blend_tree);
|
embedded_blend_tree_resource->CreateBlendTreeInstance(
|
||||||
embedded_blend_tree_resource->m_socket_accessor->m_inputs = embedded_blend_tree->m_node_descriptor->m_outputs;
|
*embedded_blend_tree);
|
||||||
embedded_blend_tree_resource->m_socket_accessor->m_outputs = embedded_blend_tree->m_node_descriptor->m_inputs;
|
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;
|
||||||
|
@ -574,16 +594,20 @@ void AnimGraphResource::PrepareBlendTreeIOData(
|
||||||
instance.m_connection_data_storage = new char[connection_data_storage_size];
|
instance.m_connection_data_storage = new char[connection_data_storage_size];
|
||||||
memset(instance.m_connection_data_storage, 0, connection_data_storage_size);
|
memset(instance.m_connection_data_storage, 0, connection_data_storage_size);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimGraphResource::CreateBlendTreeConnectionInstances(
|
||||||
|
AnimGraphBlendTree& instance) const {
|
||||||
std::vector<NodeDescriptorBase*> instance_node_descriptors(
|
std::vector<NodeDescriptorBase*> instance_node_descriptors(
|
||||||
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") {
|
if (i > 1
|
||||||
|
&& m_blend_tree_resource.m_nodes[i]->m_node_type_name == "BlendTree") {
|
||||||
instance_node_descriptors[i]->m_inputs =
|
instance_node_descriptors[i]->m_inputs =
|
||||||
m_blend_tree_resource.m_nodes[i]->m_socket_accessor->m_inputs;
|
m_blend_tree_resource.m_nodes[i]->m_socket_accessor->m_inputs;
|
||||||
instance_node_descriptors[i]->m_outputs =
|
instance_node_descriptors[i]->m_outputs =
|
||||||
|
@ -611,6 +635,72 @@ void AnimGraphResource::PrepareBlendTreeIOData(
|
||||||
connection.target_socket_name.c_str());
|
connection.target_socket_name.c_str());
|
||||||
|
|
||||||
AnimGraphConnection instance_connection;
|
AnimGraphConnection instance_connection;
|
||||||
|
|
||||||
|
if (source_node->m_node_type_name == "BlendTree") {
|
||||||
|
// For embedded subgraphs we have to ensure two things:
|
||||||
|
// 1. The parent graph target node must activate the source node within
|
||||||
|
// the embedded subgraph.
|
||||||
|
// 2. The parent graph target node must activate the AnimNode of the
|
||||||
|
// parent graph which contains the embedded subgraph. Otherwise, the
|
||||||
|
// embedded graph does not get evaluated.
|
||||||
|
// For each case we have to add a connection here. First we insert the
|
||||||
|
// default connection within the graph (i.e. for case 2). Then we alter
|
||||||
|
// the source node such that it points to the node within the embedded
|
||||||
|
// subgraph.
|
||||||
|
AnimGraphConnection embedded_graph_activation_connection;
|
||||||
|
embedded_graph_activation_connection.m_source_node = source_node;
|
||||||
|
embedded_graph_activation_connection.m_source_socket = *source_socket;
|
||||||
|
embedded_graph_activation_connection.m_target_node = target_node;
|
||||||
|
embedded_graph_activation_connection.m_target_socket = *target_socket;
|
||||||
|
instance.m_node_input_connections[connection.target_node_index].push_back(
|
||||||
|
embedded_graph_activation_connection);
|
||||||
|
instance.m_node_output_connections[connection.source_node_index]
|
||||||
|
.push_back(embedded_graph_activation_connection);
|
||||||
|
|
||||||
|
AnimGraphResource* source_blend_tree_resource =
|
||||||
|
dynamic_cast<AnimGraphResource*>(
|
||||||
|
m_blend_tree_resource.m_nodes[connection.source_node_index]);
|
||||||
|
AnimGraphBlendTree* source_blend_tree =
|
||||||
|
dynamic_cast<AnimGraphBlendTree*>(source_node);
|
||||||
|
|
||||||
|
size_t source_blend_tree_output_node_index =
|
||||||
|
source_blend_tree_resource->m_blend_tree_resource
|
||||||
|
.GetNodeIndexForOutputSocket(connection.source_socket_name);
|
||||||
|
source_node =
|
||||||
|
source_blend_tree->m_nodes[source_blend_tree_output_node_index];
|
||||||
|
instance_connection.m_crosses_hierarchy = true;
|
||||||
|
} else if (target_node->m_node_type_name == "BlendTree") {
|
||||||
|
// When a connection points to an embedded blend tree we have to ensure
|
||||||
|
// that the embedded node knows about its connection partner in the parent
|
||||||
|
// tree. This allows the embedded node to properly activate the node in
|
||||||
|
// the parent graph.
|
||||||
|
AnimGraphResource* target_blend_tree_resource =
|
||||||
|
dynamic_cast<AnimGraphResource*>(
|
||||||
|
m_blend_tree_resource.m_nodes[connection.target_node_index]);
|
||||||
|
AnimGraphBlendTree* target_blend_tree =
|
||||||
|
dynamic_cast<AnimGraphBlendTree*>(target_node);
|
||||||
|
|
||||||
|
size_t target_blend_tree_output_node_index =
|
||||||
|
target_blend_tree_resource->m_blend_tree_resource
|
||||||
|
.GetNodeIndexForInputSocket(connection.target_socket_name);
|
||||||
|
target_node =
|
||||||
|
target_blend_tree->m_nodes[target_blend_tree_output_node_index];
|
||||||
|
|
||||||
|
// Make sure that the embedded node input activates the parent graph node.
|
||||||
|
std::vector<AnimGraphConnection>& embeded_target_node_inputs =
|
||||||
|
target_blend_tree
|
||||||
|
->m_node_input_connections[target_blend_tree_output_node_index];
|
||||||
|
for (size_t j = 0; j < embeded_target_node_inputs.size(); j++) {
|
||||||
|
AnimGraphConnection& embedded_target_connection =
|
||||||
|
embeded_target_node_inputs[j];
|
||||||
|
if (embedded_target_connection.m_source_socket.m_name
|
||||||
|
== target_socket->m_name) {
|
||||||
|
embedded_target_connection.m_source_node = source_node;
|
||||||
|
embedded_target_connection.m_crosses_hierarchy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
instance_connection.m_source_node = source_node;
|
instance_connection.m_source_node = source_node;
|
||||||
instance_connection.m_source_socket = *source_socket;
|
instance_connection.m_source_socket = *source_socket;
|
||||||
instance_connection.m_target_node = target_node;
|
instance_connection.m_target_node = target_node;
|
||||||
|
@ -685,8 +775,9 @@ void AnimGraphResource::SetRuntimeNodeProperties(
|
||||||
for (int i = 2; i < m_blend_tree_resource.m_nodes.size(); i++) {
|
for (int i = 2; i < m_blend_tree_resource.m_nodes.size(); i++) {
|
||||||
const AnimNodeResource* node_resource = m_blend_tree_resource.m_nodes[i];
|
const AnimNodeResource* node_resource = m_blend_tree_resource.m_nodes[i];
|
||||||
|
|
||||||
NodeDescriptorBase* node_instance_accessor =
|
NodeDescriptorBase* node_instance_accessor = AnimNodeDescriptorFactory(
|
||||||
AnimNodeDescriptorFactory(node_resource->m_node_type_name, result.m_nodes[i]);
|
node_resource->m_node_type_name,
|
||||||
|
result.m_nodes[i]);
|
||||||
|
|
||||||
std::vector<Socket>& resource_properties =
|
std::vector<Socket>& resource_properties =
|
||||||
node_resource->m_socket_accessor->m_properties;
|
node_resource->m_socket_accessor->m_properties;
|
||||||
|
@ -741,7 +832,8 @@ bool AnimGraphResource::SaveStateMachineResourceToFile(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnimGraphResource::LoadStateMachineResourceFromJson(nlohmann::json const& json_data) {
|
bool AnimGraphResource::LoadStateMachineResourceFromJson(
|
||||||
|
nlohmann::json const& json_data) {
|
||||||
assert(false && "Not yet implemented");
|
assert(false && "Not yet implemented");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -100,6 +100,32 @@ struct BlendTreeResource {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t GetNodeIndexForOutputSocket(const std::string& socket_name) const {
|
||||||
|
for (size_t i = 0; i < m_connections.size(); i++) {
|
||||||
|
const BlendTreeConnectionResource& connection = m_connections[i];
|
||||||
|
if (connection.target_node_index == 0 && connection.target_socket_name == socket_name) {
|
||||||
|
return connection.source_node_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: could not find a node connected to output '" << socket_name << "'." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetNodeIndexForInputSocket(const std::string& socket_name) const {
|
||||||
|
for (size_t i = 0; i < m_connections.size(); i++) {
|
||||||
|
const BlendTreeConnectionResource& connection = m_connections[i];
|
||||||
|
if (connection.source_node_index == 1 && connection.source_socket_name == socket_name) {
|
||||||
|
return connection.target_node_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: could not find a node connected to input '" << socket_name << "'." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StateMachineTransitionResources {
|
struct StateMachineTransitionResources {
|
||||||
|
@ -131,6 +157,7 @@ struct AnimGraphResource: AnimNodeResource {
|
||||||
bool SaveBlendTreeResourceToFile(const char* filename) const;
|
bool SaveBlendTreeResourceToFile(const char* filename) const;
|
||||||
void CreateBlendTreeRuntimeNodeInstances(AnimGraphBlendTree& result) const;
|
void CreateBlendTreeRuntimeNodeInstances(AnimGraphBlendTree& result) const;
|
||||||
void PrepareBlendTreeIOData(AnimGraphBlendTree& instance) const;
|
void PrepareBlendTreeIOData(AnimGraphBlendTree& instance) const;
|
||||||
|
void CreateBlendTreeConnectionInstances(AnimGraphBlendTree& instance) const;
|
||||||
void SetRuntimeNodeProperties(AnimGraphBlendTree& result) const;
|
void SetRuntimeNodeProperties(AnimGraphBlendTree& result) const;
|
||||||
|
|
||||||
bool SaveStateMachineResourceToFile(const char* filename) const;
|
bool SaveStateMachineResourceToFile(const char* filename) const;
|
||||||
|
|
|
@ -8,11 +8,11 @@ bool AnimGraphStateMachine::Init(AnimGraphContext& context) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraphStateMachine::MarkActiveInputs() {
|
void AnimGraphStateMachine::MarkActiveInputs(const std::vector<AnimGraphConnection>& input_connections) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraphStateMachine::CalcSyncTrack() {
|
void AnimGraphStateMachine::CalcSyncTrack(const std::vector<AnimGraphConnection>& input_connections) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ struct AnimGraphStateMachine : public AnimNode {
|
||||||
Transition* m_active_transition = nullptr;
|
Transition* m_active_transition = nullptr;
|
||||||
|
|
||||||
bool Init(AnimGraphContext& context);
|
bool Init(AnimGraphContext& context);
|
||||||
void MarkActiveInputs() override;
|
void MarkActiveInputs(const std::vector<AnimGraphConnection>& input_connections) override;
|
||||||
void CalcSyncTrack() override;
|
void CalcSyncTrack(const std::vector<AnimGraphConnection>& input_connections) override;
|
||||||
void UpdateTime(float time_last, float time_now) override;
|
void UpdateTime(float time_last, float time_now) override;
|
||||||
void Evaluate(AnimGraphContext& context) override;
|
void Evaluate(AnimGraphContext& context) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "SyncTrack.h"
|
|
||||||
#include "AnimGraphData.h"
|
#include "AnimGraphData.h"
|
||||||
|
#include "SyncTrack.h"
|
||||||
|
|
||||||
struct AnimNode;
|
struct AnimNode;
|
||||||
|
|
||||||
|
@ -25,29 +25,35 @@ enum class AnimNodeEvalState {
|
||||||
struct AnimNode {
|
struct AnimNode {
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::string m_node_type_name;
|
std::string m_node_type_name;
|
||||||
|
int m_tick_number = 0;
|
||||||
AnimNodeEvalState m_state = AnimNodeEvalState::Undefined;
|
AnimNodeEvalState m_state = AnimNodeEvalState::Undefined;
|
||||||
|
|
||||||
float m_time_now = 0.f;
|
float m_time_now = 0.f;
|
||||||
float m_time_last = 0.f;
|
float m_time_last = 0.f;
|
||||||
SyncTrack m_sync_track;
|
SyncTrack m_sync_track;
|
||||||
|
|
||||||
std::vector<AnimGraphConnection> m_inputs;
|
|
||||||
|
|
||||||
virtual ~AnimNode() = default;
|
virtual ~AnimNode() = default;
|
||||||
|
|
||||||
virtual bool Init(AnimGraphContext& context) { return true; };
|
virtual bool Init(AnimGraphContext& context) {
|
||||||
|
m_time_now = 0.f;
|
||||||
|
m_time_last = 0.f;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
virtual void MarkActiveInputs() {
|
virtual void MarkActiveInputs(
|
||||||
for (const auto & input : m_inputs) {
|
const std::vector<AnimGraphConnection>& input_connections) {
|
||||||
|
for (const auto& input : input_connections) {
|
||||||
AnimNode* input_node = input.m_source_node;
|
AnimNode* input_node = input.m_source_node;
|
||||||
if (input_node != nullptr) {
|
if (input_node != nullptr) {
|
||||||
|
input_node->m_tick_number = m_tick_number;
|
||||||
input_node->m_state = AnimNodeEvalState::Activated;
|
input_node->m_state = AnimNodeEvalState::Activated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void CalcSyncTrack() {
|
virtual void CalcSyncTrack(
|
||||||
for (const auto & input : m_inputs) {
|
const std::vector<AnimGraphConnection>& input_connections) {
|
||||||
|
for (const auto& input : input_connections) {
|
||||||
AnimNode* input_node = input.m_source_node;
|
AnimNode* input_node = input.m_source_node;
|
||||||
if (input_node != nullptr
|
if (input_node != nullptr
|
||||||
&& input.m_source_socket.m_type == SocketType::SocketTypeAnimation
|
&& input.m_source_socket.m_type == SocketType::SocketTypeAnimation
|
||||||
|
|
|
@ -140,7 +140,9 @@ class EmbeddedBlendTreeGraphResource {
|
||||||
BlendTreeResource* embedded_blend_tree_resource = nullptr;
|
BlendTreeResource* embedded_blend_tree_resource = nullptr;
|
||||||
|
|
||||||
size_t walk_node_index = -1;
|
size_t walk_node_index = -1;
|
||||||
AnimNodeResource* walk_node = nullptr;
|
AnimNodeResource* walk_node_resource = nullptr;
|
||||||
|
size_t embedded_blend_tree_node_index = -1;
|
||||||
|
size_t embedded_speed_scale_index = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EmbeddedBlendTreeGraphResource() {
|
EmbeddedBlendTreeGraphResource() {
|
||||||
|
@ -163,10 +165,11 @@ class EmbeddedBlendTreeGraphResource {
|
||||||
// Parent AnimSampler
|
// Parent AnimSampler
|
||||||
parent_blend_tree_resource->m_nodes.push_back(
|
parent_blend_tree_resource->m_nodes.push_back(
|
||||||
AnimNodeResourceFactory("AnimSampler"));
|
AnimNodeResourceFactory("AnimSampler"));
|
||||||
|
walk_node_index = parent_blend_tree_resource->m_nodes.size() - 1;
|
||||||
|
|
||||||
walk_node = parent_blend_tree_resource->m_nodes.back();
|
walk_node_resource = parent_blend_tree_resource->m_nodes[walk_node_index];
|
||||||
walk_node->m_name = "WalkAnim";
|
walk_node_resource->m_name = "WalkAnim";
|
||||||
walk_node->m_socket_accessor->SetPropertyValue(
|
walk_node_resource->m_socket_accessor->SetPropertyValue(
|
||||||
"Filename",
|
"Filename",
|
||||||
std::string("media/Walking-loop.ozz"));
|
std::string("media/Walking-loop.ozz"));
|
||||||
|
|
||||||
|
@ -175,7 +178,7 @@ class EmbeddedBlendTreeGraphResource {
|
||||||
//
|
//
|
||||||
parent_blend_tree_resource->m_nodes.push_back(
|
parent_blend_tree_resource->m_nodes.push_back(
|
||||||
AnimNodeResourceFactory("BlendTree"));
|
AnimNodeResourceFactory("BlendTree"));
|
||||||
size_t embedded_blend_tree_node_index =
|
embedded_blend_tree_node_index =
|
||||||
parent_blend_tree_resource->m_nodes.size() - 1;
|
parent_blend_tree_resource->m_nodes.size() - 1;
|
||||||
embedded_graph = dynamic_cast<AnimGraphResource*>(
|
embedded_graph = dynamic_cast<AnimGraphResource*>(
|
||||||
parent_blend_tree_resource->m_nodes.back());
|
parent_blend_tree_resource->m_nodes.back());
|
||||||
|
@ -201,9 +204,13 @@ class EmbeddedBlendTreeGraphResource {
|
||||||
// Embedded: SpeedScale node
|
// Embedded: SpeedScale node
|
||||||
embedded_blend_tree_resource->m_nodes.push_back(
|
embedded_blend_tree_resource->m_nodes.push_back(
|
||||||
AnimNodeResourceFactory("SpeedScale"));
|
AnimNodeResourceFactory("SpeedScale"));
|
||||||
|
embedded_speed_scale_index =
|
||||||
|
embedded_blend_tree_resource->m_nodes.size() - 1;
|
||||||
AnimNodeResource* embedded_speed_scale_resource =
|
AnimNodeResource* embedded_speed_scale_resource =
|
||||||
embedded_blend_tree_resource->m_nodes.back();
|
embedded_blend_tree_resource->m_nodes[embedded_speed_scale_index];
|
||||||
embedded_speed_scale_resource->m_socket_accessor->SetInputValue("SpeedScale", 0.1f);
|
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(
|
||||||
|
@ -219,7 +226,7 @@ class EmbeddedBlendTreeGraphResource {
|
||||||
|
|
||||||
// Parent: setup connections
|
// Parent: setup connections
|
||||||
REQUIRE(parent_blend_tree_resource->ConnectSockets(
|
REQUIRE(parent_blend_tree_resource->ConnectSockets(
|
||||||
walk_node,
|
walk_node_resource,
|
||||||
"Output",
|
"Output",
|
||||||
embedded_graph,
|
embedded_graph,
|
||||||
"AnimInput"));
|
"AnimInput"));
|
||||||
|
@ -346,8 +353,8 @@ TEST_CASE_METHOD(
|
||||||
AnimSamplerNode* anim_sampler_walk =
|
AnimSamplerNode* anim_sampler_walk =
|
||||||
dynamic_cast<AnimSamplerNode*>(anim_graph_blend_tree.m_nodes[2]);
|
dynamic_cast<AnimSamplerNode*>(anim_graph_blend_tree.m_nodes[2]);
|
||||||
|
|
||||||
BlendTreeNode* graph_output_node =
|
BlendTreeSocketNode* graph_output_node =
|
||||||
dynamic_cast<BlendTreeNode*>(anim_graph_blend_tree.m_nodes[0]);
|
dynamic_cast<BlendTreeSocketNode*>(anim_graph_blend_tree.m_nodes[0]);
|
||||||
|
|
||||||
// check node input dependencies
|
// check node input dependencies
|
||||||
size_t anim_sampler_index =
|
size_t anim_sampler_index =
|
||||||
|
@ -937,7 +944,8 @@ TEST_CASE_METHOD(
|
||||||
parent_blend_tree_resource->m_nodes.size()
|
parent_blend_tree_resource->m_nodes.size()
|
||||||
== parent_blend_tree_resource_loaded.m_nodes.size());
|
== parent_blend_tree_resource_loaded.m_nodes.size());
|
||||||
for (size_t i = 0; i < parent_blend_tree_resource->m_nodes.size(); i++) {
|
for (size_t i = 0; i < parent_blend_tree_resource->m_nodes.size(); i++) {
|
||||||
const AnimNodeResource* parent_node = parent_blend_tree_resource->m_nodes[i];
|
const AnimNodeResource* parent_node =
|
||||||
|
parent_blend_tree_resource->m_nodes[i];
|
||||||
const AnimNodeResource* parent_node_loaded =
|
const AnimNodeResource* parent_node_loaded =
|
||||||
parent_blend_tree_resource_loaded.m_nodes[i];
|
parent_blend_tree_resource_loaded.m_nodes[i];
|
||||||
|
|
||||||
|
@ -949,7 +957,8 @@ TEST_CASE_METHOD(
|
||||||
CHECK(
|
CHECK(
|
||||||
parent_blend_tree_resource->m_connections.size()
|
parent_blend_tree_resource->m_connections.size()
|
||||||
== parent_blend_tree_resource_loaded.m_connections.size());
|
== parent_blend_tree_resource_loaded.m_connections.size());
|
||||||
for (size_t i = 0; i < parent_blend_tree_resource->m_connections.size(); i++) {
|
for (size_t i = 0; i < parent_blend_tree_resource->m_connections.size();
|
||||||
|
i++) {
|
||||||
const BlendTreeConnectionResource& parent_connection =
|
const BlendTreeConnectionResource& parent_connection =
|
||||||
parent_blend_tree_resource->m_connections[i];
|
parent_blend_tree_resource->m_connections[i];
|
||||||
const BlendTreeConnectionResource& parent_connection_loaded =
|
const BlendTreeConnectionResource& parent_connection_loaded =
|
||||||
|
@ -1039,22 +1048,61 @@ TEST_CASE_METHOD(
|
||||||
graph_context.m_skeleton = &skeleton;
|
graph_context.m_skeleton = &skeleton;
|
||||||
|
|
||||||
blend_tree.Init(graph_context);
|
blend_tree.Init(graph_context);
|
||||||
// Marking of active inputs is not properly working as we do not properly
|
|
||||||
// populate AnimNode::m_inputs.
|
const AnimSamplerNode* walk_node =
|
||||||
//
|
dynamic_cast<AnimSamplerNode*>(blend_tree.m_nodes[walk_node_index]);
|
||||||
// Here comes an iffy problem: How to mark nodes in a parent blend tree
|
const AnimGraphBlendTree* embedded_blend_tree_node =
|
||||||
// as active?
|
dynamic_cast<AnimGraphBlendTree*>(
|
||||||
//
|
blend_tree.m_nodes[embedded_blend_tree_node_index]);
|
||||||
// - Simplest would be if the AnimNodes don't distinguish between nodes within
|
const SpeedScaleNode* speed_scale_node = dynamic_cast<SpeedScaleNode*>(
|
||||||
// the tree they are contained or in a possible parent (or nested) tree.
|
embedded_blend_tree_node->m_nodes[walk_node_index]);
|
||||||
// - But then how to propagate active connections across multiple layers?
|
|
||||||
// - Therefore probably better to have a blend tree store which sockets are
|
blend_tree.StartUpdateTick();
|
||||||
// active and use that within the graph.
|
blend_tree.MarkActiveInputs(std::vector<AnimGraphConnection>());
|
||||||
// - But then: AnimGraphConnection already stores raw AnimNode pointers of the
|
REQUIRE(embedded_blend_tree_node->m_state == AnimNodeEvalState::Activated);
|
||||||
// connected nodes. Still... populating them accross layers could be messy.
|
REQUIRE(speed_scale_node->m_state == AnimNodeEvalState::Activated);
|
||||||
blend_tree.MarkActiveInputs();
|
REQUIRE(walk_node->m_state == AnimNodeEvalState::Activated);
|
||||||
blend_tree.UpdateTime(0.f, 0.1f);
|
|
||||||
|
float time_last = 0.f;
|
||||||
|
float dt = 0.1f;
|
||||||
|
blend_tree.UpdateTime(time_last, time_last + dt);
|
||||||
|
CHECK(embedded_blend_tree_node->m_state == AnimNodeEvalState::TimeUpdated);
|
||||||
|
CHECK(speed_scale_node->m_state == AnimNodeEvalState::TimeUpdated);
|
||||||
|
CHECK(walk_node->m_state == AnimNodeEvalState::TimeUpdated);
|
||||||
|
|
||||||
|
CHECK_THAT(
|
||||||
|
walk_node->m_time_last,
|
||||||
|
Catch::Matchers::WithinAbs(time_last, 0.001));
|
||||||
|
CHECK_THAT(
|
||||||
|
walk_node->m_time_now,
|
||||||
|
Catch::Matchers::WithinAbs(
|
||||||
|
time_last + dt * (*speed_scale_node->i_speed_scale),
|
||||||
|
0.001));
|
||||||
|
|
||||||
blend_tree.Evaluate(graph_context);
|
blend_tree.Evaluate(graph_context);
|
||||||
|
|
||||||
|
WHEN("Updating the time a second time") {
|
||||||
|
// Perform another update
|
||||||
|
time_last = time_last + dt;
|
||||||
|
dt = 0.3f;
|
||||||
|
blend_tree.StartUpdateTick();
|
||||||
|
blend_tree.MarkActiveInputs(std::vector<AnimGraphConnection>());
|
||||||
|
blend_tree.UpdateTime(time_last, time_last + dt);
|
||||||
|
CHECK(embedded_blend_tree_node->m_state == AnimNodeEvalState::TimeUpdated);
|
||||||
|
CHECK(speed_scale_node->m_state == AnimNodeEvalState::TimeUpdated);
|
||||||
|
CHECK(walk_node->m_state == AnimNodeEvalState::TimeUpdated);
|
||||||
|
|
||||||
|
CHECK_THAT(
|
||||||
|
walk_node->m_time_last,
|
||||||
|
Catch::Matchers::WithinAbs(
|
||||||
|
time_last * (*speed_scale_node->i_speed_scale),
|
||||||
|
0.001));
|
||||||
|
CHECK_THAT(
|
||||||
|
walk_node->m_time_now,
|
||||||
|
Catch::Matchers::WithinAbs(
|
||||||
|
(time_last + dt) * (*speed_scale_node->i_speed_scale),
|
||||||
|
0.001));
|
||||||
|
}
|
||||||
|
|
||||||
graph_context.freeAnimations();
|
graph_context.freeAnimations();
|
||||||
}
|
}
|
Loading…
Reference in New Issue