Compare commits

..

No commits in common. "86ea476881cd6043f177ac527a9da94435137560" and "1870a9d214fab1520bbce7f64230a7cbb4afc2f4" have entirely different histories.

11 changed files with 169 additions and 286 deletions

View File

@ -15,9 +15,9 @@ bool AnimGraphBlendTree::Init(AnimGraphContext& context) {
} }
} }
for (size_t i = 0; i < m_pose_blocks.size(); i++) { for (size_t i = 0; i < m_animdata_blocks.size(); i++) {
int num_soa_joints = context.m_skeleton->num_soa_joints(); int num_soa_joints = context.m_skeleton->num_soa_joints();
m_pose_blocks[i]->m_local_matrices.resize(num_soa_joints); m_animdata_blocks[i]->m_local_matrices.resize(num_soa_joints);
} }
return true; return true;

View File

@ -13,6 +13,8 @@
// AnimGraph (Runtime) // AnimGraph (Runtime)
// //
struct AnimGraphBlendTree : public AnimNode { struct AnimGraphBlendTree : public AnimNode {
AnimData m_local_transforms;
std::vector<AnimNode*> m_nodes; std::vector<AnimNode*> m_nodes;
std::vector<AnimNode*> m_eval_ordered_nodes; std::vector<AnimNode*> m_eval_ordered_nodes;
std::vector<std::vector<AnimGraphConnection> > m_node_input_connections; std::vector<std::vector<AnimGraphConnection> > m_node_input_connections;
@ -28,17 +30,15 @@ struct AnimGraphBlendTree : public AnimNode {
return m_node_input_connections[0]; return m_node_input_connections[0];
} }
std::vector<Pose*> m_pose_blocks; std::vector<AnimData*> m_animdata_blocks;
NodeDescriptorBase* m_node_descriptor = nullptr; NodeDescriptorBase* m_node_descriptor = nullptr;
char* m_input_buffer = nullptr; char* m_input_buffer = nullptr;
char* m_output_buffer = nullptr; char* m_output_buffer = nullptr;
char* m_connection_data_storage = nullptr; char* m_connection_data_storage = nullptr;
char* m_const_node_inputs = nullptr; char* m_const_node_inputs = nullptr;
std::vector<Socket>& GetGraphOutputs() { std::vector<Socket>& GetGraphOutputs() { return m_node_descriptor->m_inputs; }
return m_node_descriptor->m_outputs; std::vector<Socket>& GetGraphInputs() { return m_node_descriptor->m_outputs; }
}
std::vector<Socket>& GetGraphInputs() { return m_node_descriptor->m_inputs; }
AnimDataAllocator m_anim_data_allocator; AnimDataAllocator m_anim_data_allocator;
@ -48,13 +48,6 @@ struct AnimGraphBlendTree : public AnimNode {
// AnimNode overrides // AnimNode overrides
bool Init(AnimGraphContext& context) override; bool Init(AnimGraphContext& context) override;
/// Determines which nodes in the BlendTree are active.
///
/// Note: this does not use the provided input_connections, instead it marks
/// all nodes directly connected to the BlendTree outputs as active and then
/// propagates the node state throught the tree. For this each active node's
/// AnimNode::MarkActiveInputs() gets called.
void MarkActiveInputs( void MarkActiveInputs(
const std::vector<AnimGraphConnection>& input_connections) override; const std::vector<AnimGraphConnection>& input_connections) override;
void CalcSyncTrack( void CalcSyncTrack(
@ -65,10 +58,10 @@ struct AnimGraphBlendTree : public AnimNode {
void PropagateTimeToNodeInputs(const AnimNode* node); void PropagateTimeToNodeInputs(const AnimNode* node);
void dealloc() { void dealloc() {
for (size_t i = 0; i < m_pose_blocks.size(); i++) { for (size_t i = 0; i < m_animdata_blocks.size(); i++) {
m_pose_blocks[i]->m_local_matrices.vector::~vector(); m_animdata_blocks[i]->m_local_matrices.vector::~vector();
} }
m_pose_blocks.clear(); m_animdata_blocks.clear();
m_node_input_connections.clear(); m_node_input_connections.clear();
m_node_output_connections.clear(); m_node_output_connections.clear();
@ -100,7 +93,7 @@ struct AnimGraphBlendTree : public AnimNode {
} }
} }
/** Sets the address that is used for the specified BlendTree input Socket. /** Sets the address that is used for the specified AnimGraph input Socket.
* *
* @tparam T Type of the Socket. * @tparam T Type of the Socket.
* @param name Name of the Socket. * @param name Name of the Socket.
@ -108,7 +101,7 @@ struct AnimGraphBlendTree : public AnimNode {
*/ */
template <typename T> template <typename T>
void SetInput(const char* name, T* value_ptr) { void SetInput(const char* name, T* value_ptr) {
m_node_descriptor->SetInput(name, value_ptr); m_node_descriptor->SetOutput(name, value_ptr);
std::vector<size_t> connected_node_indices; std::vector<size_t> connected_node_indices;
@ -122,7 +115,7 @@ struct AnimGraphBlendTree : public AnimNode {
} }
} }
/** Sets the address that is used for the specified BlendTree output Socket. /** Sets the address that is used for the specified AnimGraph output Socket.
* *
* We update the pointer of the outputting node. We also have to ensure that * We update the pointer of the outputting node. We also have to ensure that
* all usages of that output use the same pointer. * all usages of that output use the same pointer.
@ -155,7 +148,6 @@ struct AnimGraphBlendTree : public AnimNode {
return; return;
} }
// Ensure that all connections that consume the output use the updated address.
size_t output_node_index = size_t output_node_index =
GetAnimNodeIndex(graph_output_connection->m_source_node); GetAnimNodeIndex(graph_output_connection->m_source_node);
@ -169,12 +161,6 @@ struct AnimGraphBlendTree : public AnimNode {
} }
*graph_output_connection->m_socket.m_reference.ptr_ptr = value_ptr; *graph_output_connection->m_socket.m_reference.ptr_ptr = value_ptr;
// And additionally update the BlendTree's node descriptor:
Socket* blend_tree_output_socket = m_node_descriptor->GetOutputSocket(name);
assert(blend_tree_output_socket != nullptr);
*blend_tree_output_socket->m_reference.ptr_ptr = value_ptr;
} }
/** Returns the address that is used for the specified AnimGraph output Socket. /** Returns the address that is used for the specified AnimGraph output Socket.

View File

@ -25,26 +25,26 @@
struct AnimGraph; struct AnimGraph;
struct AnimNode; struct AnimNode;
struct Pose { struct AnimData {
ozz::vector<ozz::math::SoaTransform> m_local_matrices; ozz::vector<ozz::math::SoaTransform> m_local_matrices;
}; };
struct AnimDataRef { struct AnimDataRef {
Pose* ptr = nullptr; AnimData* ptr = nullptr;
}; };
struct AnimDataAllocator { struct AnimDataAllocator {
struct PoseList { struct AnimDataList {
Pose* m_anim_data = nullptr; AnimData* m_anim_data = nullptr;
PoseList* next = nullptr; AnimDataList* next = nullptr;
}; };
std::list<Pose*> m_anim_data_list; std::list<AnimData*> m_anim_data_list;
size_t m_num_allocations = 0; size_t m_num_allocations = 0;
~AnimDataAllocator() { ~AnimDataAllocator() {
while (!m_anim_data_list.empty()) { while (!m_anim_data_list.empty()) {
Pose* front = m_anim_data_list.front(); AnimData* front = m_anim_data_list.front();
#ifdef ANIM_DATA_ALLOCATOR_DEBUG #ifdef ANIM_DATA_ALLOCATOR_DEBUG
std::cout << "about to delete with size " std::cout << "about to delete with size "
<< front->m_anim_data->m_local_matrices.size() << front->m_anim_data->m_local_matrices.size()
@ -55,9 +55,9 @@ struct AnimDataAllocator {
} }
} }
Pose* allocate(ozz::animation::Skeleton* skeleton) { AnimData* allocate(ozz::animation::Skeleton* skeleton) {
if (m_anim_data_list.empty()) { if (m_anim_data_list.empty()) {
Pose* result = new Pose(); AnimData* result = new AnimData();
result->m_local_matrices.resize(skeleton->num_soa_joints()); result->m_local_matrices.resize(skeleton->num_soa_joints());
#ifdef ANIM_DATA_ALLOCATOR_DEBUG #ifdef ANIM_DATA_ALLOCATOR_DEBUG
std::cout << "Allocated with size " << result->m_local_matrices.size() std::cout << "Allocated with size " << result->m_local_matrices.size()
@ -67,7 +67,7 @@ struct AnimDataAllocator {
return result; return result;
} }
Pose* result = m_anim_data_list.front(); AnimData* result = m_anim_data_list.front();
m_anim_data_list.pop_front(); m_anim_data_list.pop_front();
#ifdef ANIM_DATA_ALLOCATOR_DEBUG #ifdef ANIM_DATA_ALLOCATOR_DEBUG
@ -78,7 +78,7 @@ struct AnimDataAllocator {
return result; return result;
} }
void free(Pose* anim_data) { void free(AnimData* anim_data) {
#ifdef ANIM_DATA_ALLOCATOR_DEBUG #ifdef ANIM_DATA_ALLOCATOR_DEBUG
std::cout << "Storing buffer with size " std::cout << "Storing buffer with size "
<< anim_data->m_local_matrices.size() << " " << anim_data << anim_data->m_local_matrices.size() << " " << anim_data
@ -238,7 +238,7 @@ SocketType GetSocketType() {
return SocketType::SocketTypeBool; return SocketType::SocketTypeBool;
} }
if constexpr (std::is_same<T, Pose>::value) { if constexpr (std::is_same<T, AnimData>::value) {
return SocketType::SocketTypeAnimation; return SocketType::SocketTypeAnimation;
} }

View File

@ -18,9 +18,9 @@ struct AnimNode;
// Blend2Node // Blend2Node
// //
struct Blend2Node : public AnimNode { struct Blend2Node : public AnimNode {
Pose* i_input0 = nullptr; AnimData* i_input0 = nullptr;
Pose* i_input1 = nullptr; AnimData* i_input1 = nullptr;
Pose* o_output = nullptr; AnimData* o_output = nullptr;
float* i_blend_weight = nullptr; float* i_blend_weight = nullptr;
bool m_sync_blend = false; bool m_sync_blend = false;
@ -33,12 +33,12 @@ struct Blend2Node : public AnimNode {
} }
if (input.m_target_socket_name == "Input0" && *i_blend_weight < 0.999) { if (input.m_target_socket_name == "Input0" && *i_blend_weight < 0.999) {
input_node->Activate(m_tick_number); input_node->m_state = AnimNodeEvalState::Activated;
continue; continue;
} }
if (input.m_target_socket_name == "Input1" && *i_blend_weight > 0.001) { if (input.m_target_socket_name == "Input1" && *i_blend_weight > 0.001) {
input_node->Activate(m_tick_number); input_node->m_state = AnimNodeEvalState::Activated;
continue; continue;
} }
} }
@ -59,8 +59,6 @@ struct NodeDescriptor<Blend2Node> : public NodeDescriptorBase {
RegisterProperty("Sync", &node->m_sync_blend); RegisterProperty("Sync", &node->m_sync_blend);
} }
virtual ~NodeDescriptor() = default;
void UpdateFlags() override { void UpdateFlags() override {
Socket* weight_input_socket = FindSocket("Weight", m_inputs); Socket* weight_input_socket = FindSocket("Weight", m_inputs);
assert(weight_input_socket != nullptr); assert(weight_input_socket != nullptr);
@ -77,8 +75,8 @@ struct NodeDescriptor<Blend2Node> : public NodeDescriptorBase {
// SpeedScaleNode // SpeedScaleNode
// //
struct SpeedScaleNode : public AnimNode { struct SpeedScaleNode : public AnimNode {
Pose* i_input = nullptr; AnimData* i_input = nullptr;
Pose* o_output = nullptr; AnimData* o_output = nullptr;
float* i_speed_scale = nullptr; float* i_speed_scale = nullptr;
void UpdateTime(float time_last, float time_now) override { void UpdateTime(float time_last, float time_now) override {
@ -106,15 +104,13 @@ struct NodeDescriptor<SpeedScaleNode> : public NodeDescriptorBase {
RegisterOutput("Output", &node->o_output); RegisterOutput("Output", &node->o_output);
} }
virtual ~NodeDescriptor() = default;
}; };
// //
// AnimSamplerNode // AnimSamplerNode
// //
struct AnimSamplerNode : public AnimNode { struct AnimSamplerNode : public AnimNode {
Pose* o_output = nullptr; AnimData* o_output = nullptr;
std::string m_filename; std::string m_filename;
ozz::animation::SamplingJob::Context m_sampling_context; ozz::animation::SamplingJob::Context m_sampling_context;
ozz::animation::Animation* m_animation = nullptr; ozz::animation::Animation* m_animation = nullptr;
@ -136,16 +132,14 @@ struct NodeDescriptor<AnimSamplerNode> : public NodeDescriptorBase {
RegisterProperty("Filename", &node->m_filename); RegisterProperty("Filename", &node->m_filename);
} }
virtual ~NodeDescriptor() = default;
}; };
// //
// LockTranslationNode // LockTranslationNode
// //
struct LockTranslationNode : public AnimNode { struct LockTranslationNode : public AnimNode {
Pose* i_input = nullptr; AnimData* i_input = nullptr;
Pose* o_output = nullptr; AnimData* o_output = nullptr;
int m_locked_bone_index = 0; int m_locked_bone_index = 0;
bool m_lock_x = false; bool m_lock_x = false;
bool m_lock_y = false; bool m_lock_y = false;
@ -165,8 +159,6 @@ struct NodeDescriptor<LockTranslationNode> : public NodeDescriptorBase {
RegisterProperty("LockAxisY", &node->m_lock_y); RegisterProperty("LockAxisY", &node->m_lock_y);
RegisterProperty("LockAxisZ", &node->m_lock_z); RegisterProperty("LockAxisZ", &node->m_lock_z);
} }
virtual ~NodeDescriptor() = default;
}; };
// //
@ -185,8 +177,6 @@ struct NodeDescriptor<ConstScalarNode> : public NodeDescriptorBase {
RegisterOutput("ScalarOutput", &node->o_value); RegisterOutput("ScalarOutput", &node->o_value);
RegisterProperty("ScalarValue", &node->value); RegisterProperty("ScalarValue", &node->value);
} }
virtual ~NodeDescriptor() = default;
}; };
// //
@ -212,8 +202,6 @@ struct NodeDescriptor<MathAddNode> : public NodeDescriptorBase {
RegisterInput("Input1", &node->i_input1); RegisterInput("Input1", &node->i_input1);
RegisterOutput("Output", &node->o_output); RegisterOutput("Output", &node->o_output);
} }
virtual ~NodeDescriptor() = default;
}; };
// //
@ -244,8 +232,6 @@ struct NodeDescriptor<MathFloatToVec3Node> : public NodeDescriptorBase {
RegisterInput("Input2", &node->i_input2); RegisterInput("Input2", &node->i_input2);
RegisterOutput("Output", &node->o_output); RegisterOutput("Output", &node->o_output);
} }
virtual ~NodeDescriptor() = default;
}; };
AnimNode* AnimNodeFactory(const std::string& name); AnimNode* AnimNodeFactory(const std::string& name);

View File

@ -86,7 +86,7 @@ Socket sJsonToSocket(const json& json_data) {
} }
} else if (type_string == "Animation") { } else if (type_string == "Animation") {
result.m_type = SocketType::SocketTypeAnimation; result.m_type = SocketType::SocketTypeAnimation;
result.m_type_size = sizeof(Pose); result.m_type_size = sizeof(AnimData);
} else if (type_string == "Int") { } else if (type_string == "Int") {
result.m_type = SocketType::SocketTypeInt; result.m_type = SocketType::SocketTypeInt;
result.m_type_size = sizeof(int); result.m_type_size = sizeof(int);
@ -933,9 +933,9 @@ void BlendTreeResource::CreateBlendTreeRuntimeNodeInstances(
embedded_blend_tree_resource->CreateBlendTreeInstance( embedded_blend_tree_resource->CreateBlendTreeInstance(
*embedded_blend_tree); *embedded_blend_tree);
embedded_blend_tree_resource->m_virtual_socket_accessor->m_inputs = embedded_blend_tree_resource->m_virtual_socket_accessor->m_inputs =
embedded_blend_tree->m_node_descriptor->m_inputs;
embedded_blend_tree_resource->m_virtual_socket_accessor->m_outputs =
embedded_blend_tree->m_node_descriptor->m_outputs; embedded_blend_tree->m_node_descriptor->m_outputs;
embedded_blend_tree_resource->m_virtual_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;
@ -955,9 +955,9 @@ void BlendTreeResource::PrepareBlendTreeIOData(
AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]); AnimNodeDescriptorFactory("BlendTree", instance.m_nodes[0]);
instance.m_node_descriptor->m_outputs = instance.m_node_descriptor->m_outputs =
GetGraphOutputNode()->m_virtual_socket_accessor->m_inputs;
instance.m_node_descriptor->m_inputs =
GetGraphInputNode()->m_virtual_socket_accessor->m_outputs; GetGraphInputNode()->m_virtual_socket_accessor->m_outputs;
instance.m_node_descriptor->m_inputs =
GetGraphOutputNode()->m_virtual_socket_accessor->m_inputs;
// //
// graph inputs // graph inputs
@ -977,7 +977,7 @@ void BlendTreeResource::PrepareBlendTreeIOData(
for (int i = 0; i < graph_inputs.size(); i++) { for (int i = 0; i < graph_inputs.size(); i++) {
graph_inputs[i].m_reference.ptr = graph_inputs[i].m_reference.ptr =
(void*)&instance.m_input_buffer[input_block_offset]; (void*)&instance.m_input_buffer[input_block_offset];
instance.m_node_descriptor->m_inputs[i].m_reference.ptr = instance.m_node_descriptor->m_outputs[i].m_reference.ptr =
&instance.m_input_buffer[input_block_offset]; &instance.m_input_buffer[input_block_offset];
input_block_offset += sizeof(void*); input_block_offset += sizeof(void*);
} }
@ -998,18 +998,13 @@ void BlendTreeResource::PrepareBlendTreeIOData(
int output_block_offset = 0; int output_block_offset = 0;
for (int i = 0; i < graph_outputs.size(); i++) { for (int i = 0; i < graph_outputs.size(); i++) {
instance.m_node_descriptor->m_outputs[i].m_reference.ptr = instance.m_node_descriptor->m_inputs[i].m_reference.ptr =
&instance.m_output_buffer[output_block_offset]; &instance.m_output_buffer[output_block_offset];
output_block_offset += sizeof(void*); output_block_offset += sizeof(void*);
} }
// //
// connection data storage: we reserve memory for the used outputs of all // connecton data storage
// nodes:
// * If a node output does not get used: we do not reserve a memory block.
// * If a node output gets used by multiple nodes: we only reserve a single
// memory block.
// The resulting memory offsets are stored in the node_offset_map.
// //
size_t connection_data_storage_size = 0; size_t connection_data_storage_size = 0;
for (const BlendTreeConnectionResource& connection : GetConnections()) { for (const BlendTreeConnectionResource& connection : GetConnections()) {
@ -1033,61 +1028,6 @@ void BlendTreeResource::PrepareBlendTreeIOData(
} }
} }
void BlendTreeResource::SetRuntimeNodeProperties(
AnimGraphBlendTree& result) const {
for (int i = 2; i < GetNumNodes(); i++) {
const AnimNodeResource* node_resource = GetNode(i);
NodeDescriptorBase* node_instance_accessor = AnimNodeDescriptorFactory(
node_resource->m_node_type_name,
result.m_nodes[i]);
std::vector<Socket>& resource_properties =
node_resource->m_virtual_socket_accessor->m_properties;
for (const auto& property : resource_properties) {
const std::string& name = property.m_name;
switch (property.m_type) {
case SocketType::SocketTypeBool:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value.flag);
break;
case SocketType::SocketTypeInt:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value.int_value);
break;
case SocketType::SocketTypeFloat:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value.float_value);
break;
case SocketType::SocketTypeVec3:
node_instance_accessor->SetProperty<Vec3>(
name.c_str(),
property.m_value.vec3);
break;
case SocketType::SocketTypeQuat:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value.quat);
break;
case SocketType::SocketTypeString:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value_string);
break;
default:
std::cerr << "Invalid socket type "
<< static_cast<int>(property.m_type) << std::endl;
}
}
delete node_instance_accessor;
}
}
void BlendTreeResource::CreateBlendTreeConnectionInstances( void BlendTreeResource::CreateBlendTreeConnectionInstances(
AnimGraphBlendTree& instance, AnimGraphBlendTree& instance,
NodeSocketDataOffsetMap& node_offset_map) const { NodeSocketDataOffsetMap& node_offset_map) const {
@ -1107,10 +1047,9 @@ void BlendTreeResource::CreateBlendTreeConnectionInstances(
} }
} }
instance_node_descriptors[0]->m_inputs = instance_node_descriptors[0]->m_inputs = instance.m_node_descriptor->m_inputs;
instance.m_node_descriptor->m_outputs;
instance_node_descriptors[1]->m_outputs = instance_node_descriptors[1]->m_outputs =
instance.m_node_descriptor->m_inputs; instance.m_node_descriptor->m_outputs;
for (const BlendTreeConnectionResource& connection : GetConnections()) { for (const BlendTreeConnectionResource& connection : GetConnections()) {
NodeDescriptorBase* source_node_descriptor = NodeDescriptorBase* source_node_descriptor =
@ -1242,8 +1181,9 @@ void BlendTreeResource::CreateBlendTreeConnectionInstances(
&instance.m_connection_data_storage[socket_data_offset]; &instance.m_connection_data_storage[socket_data_offset];
if (source_socket->m_type == SocketType::SocketTypeAnimation) { if (source_socket->m_type == SocketType::SocketTypeAnimation) {
instance.m_pose_blocks.push_back( instance.m_animdata_blocks.push_back(
(Pose*)(&instance.m_connection_data_storage[socket_data_offset])); (AnimData*)(&instance
.m_connection_data_storage[socket_data_offset]));
} }
} }
@ -1296,4 +1236,59 @@ void BlendTreeResource::CreateBlendTreeConnectionInstances(
} }
} }
void BlendTreeResource::SetRuntimeNodeProperties(
AnimGraphBlendTree& result) const {
for (int i = 2; i < GetNumNodes(); i++) {
const AnimNodeResource* node_resource = GetNode(i);
NodeDescriptorBase* node_instance_accessor = AnimNodeDescriptorFactory(
node_resource->m_node_type_name,
result.m_nodes[i]);
std::vector<Socket>& resource_properties =
node_resource->m_virtual_socket_accessor->m_properties;
for (const auto& property : resource_properties) {
const std::string& name = property.m_name;
switch (property.m_type) {
case SocketType::SocketTypeBool:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value.flag);
break;
case SocketType::SocketTypeInt:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value.int_value);
break;
case SocketType::SocketTypeFloat:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value.float_value);
break;
case SocketType::SocketTypeVec3:
node_instance_accessor->SetProperty<Vec3>(
name.c_str(),
property.m_value.vec3);
break;
case SocketType::SocketTypeQuat:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value.quat);
break;
case SocketType::SocketTypeString:
node_instance_accessor->SetProperty(
name.c_str(),
property.m_value_string);
break;
default:
std::cerr << "Invalid socket type "
<< static_cast<int>(property.m_type) << std::endl;
}
}
delete node_instance_accessor;
}
}
#pragma clang diagnostic pop #pragma clang diagnostic pop

View File

@ -75,7 +75,8 @@ struct BlendTreeResource : AnimGraphResource {
m_virtual_socket_accessor = VirtualAnimNodeDescriptorFactory("BlendTree"); m_virtual_socket_accessor = VirtualAnimNodeDescriptorFactory("BlendTree");
InitGraphConnectors(); InitGraphConnectors();
RegisterBlendTreeOutputSocket<Pose>(AnimGraphResource::DefaultAnimOutput); RegisterBlendTreeOutputSocket<AnimData>(
AnimGraphResource::DefaultAnimOutput);
} }
~BlendTreeResource() { ClearAllNodes(); } ~BlendTreeResource() { ClearAllNodes(); }
@ -374,12 +375,12 @@ struct BlendTreeResource : AnimGraphResource {
AnimGraphBlendTree& instance, AnimGraphBlendTree& instance,
NodeSocketDataOffsetMap& node_offset_map) const; NodeSocketDataOffsetMap& node_offset_map) const;
void SetRuntimeNodeProperties(AnimGraphBlendTree& result) const;
void CreateBlendTreeConnectionInstances( void CreateBlendTreeConnectionInstances(
AnimGraphBlendTree& instance, AnimGraphBlendTree& instance,
NodeSocketDataOffsetMap& node_offset_map) const; NodeSocketDataOffsetMap& node_offset_map) const;
void SetRuntimeNodeProperties(AnimGraphBlendTree& result) const;
void InitGraphConnectors() { void InitGraphConnectors() {
AddNode(AnimNodeResourceFactory("BlendTreeSockets")); AddNode(AnimNodeResourceFactory("BlendTreeSockets"));
AnimNodeResource* output_node = GetGraphOutputNode(); AnimNodeResource* output_node = GetGraphOutputNode();

View File

@ -45,7 +45,8 @@ struct AnimNode {
for (const auto& input : 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->Activate(m_tick_number); input_node->m_tick_number = m_tick_number;
input_node->m_state = AnimNodeEvalState::Activated;
} }
} }
} }
@ -63,18 +64,13 @@ struct AnimNode {
} }
} }
virtual void UpdateTime(const float time_last, const float time_now) { virtual void UpdateTime(float time_last, float time_now) {
m_time_last = time_last; m_time_last = time_last;
m_time_now = time_now; m_time_now = time_now;
m_state = AnimNodeEvalState::TimeUpdated; m_state = AnimNodeEvalState::TimeUpdated;
} }
virtual void Evaluate(AnimGraphContext& context){}; virtual void Evaluate(AnimGraphContext& context){};
void Activate(const int tick_number) {
m_tick_number = tick_number;
m_state = AnimNodeEvalState::Activated;
}
}; };
#endif //ANIMTESTBED_ANIMNODE_H #endif //ANIMTESTBED_ANIMNODE_H

View File

@ -491,7 +491,7 @@ int main() {
AnimGraphBlendTree anim_graph; AnimGraphBlendTree anim_graph;
AnimGraphContext anim_graph_context; AnimGraphContext anim_graph_context;
Pose anim_graph_output; AnimData anim_graph_output;
anim_graph_output.m_local_matrices.resize( anim_graph_output.m_local_matrices.resize(
skinned_mesh.m_skeleton.num_soa_joints()); skinned_mesh.m_skeleton.num_soa_joints());
AnimGraphEditorClear(); AnimGraphEditorClear();

View File

@ -4,6 +4,7 @@
#include "AnimGraph/AnimGraphBlendTree.h" #include "AnimGraph/AnimGraphBlendTree.h"
#include "AnimGraph/AnimGraphResource.h" #include "AnimGraph/AnimGraphResource.h"
#include "AnimGraphEditor/AnimGraphEditor.h"
#include "catch.hpp" #include "catch.hpp"
#include "ozz/animation/offline/animation_builder.h" #include "ozz/animation/offline/animation_builder.h"
#include "ozz/animation/offline/raw_animation.h" #include "ozz/animation/offline/raw_animation.h"
@ -13,6 +14,7 @@
#include "ozz/animation/runtime/sampling_job.h" #include "ozz/animation/runtime/sampling_job.h"
#include "ozz/animation/runtime/skeleton.h" #include "ozz/animation/runtime/skeleton.h"
#include "ozz/base/io/archive.h" #include "ozz/base/io/archive.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/log.h" #include "ozz/base/log.h"
#include "ozz/base/maths/soa_transform.h" #include "ozz/base/maths/soa_transform.h"
@ -64,7 +66,7 @@ struct SimpleAnimFixture {
bone0_translations.push_back(translation_key); bone0_translations.push_back(translation_key);
translation_key.time = 1.f; translation_key.time = 1.f;
translation_key.value = ozz::math::Float3(1.f, 0.f, 0.f); translation_key.value = ozz::math::Float3(1.f, 0.f, 9.f);
bone0_translations.push_back(translation_key); bone0_translations.push_back(translation_key);
bone0_track.translations = bone0_translations; bone0_track.translations = bone0_translations;
@ -121,18 +123,18 @@ TEST_CASE_METHOD(
sampled_translation.z[0] == Approx(translation_key.value.z).margin(0.01)); sampled_translation.z[0] == Approx(translation_key.value.z).margin(0.01));
} }
TEST_CASE("PosePlacementNew", "[AnimGraphEval]") { TEST_CASE("AnimDataPlacementNew", "[AnimGraphEval]") {
int pose_size = sizeof(Pose); int anim_data_size = sizeof(AnimData);
char* buf = new char[pose_size]; char* buf = new char[anim_data_size];
Pose* pose_newed = new Pose; AnimData* anim_data_newed = new AnimData;
pose_newed->m_local_matrices.resize(2); anim_data_newed->m_local_matrices.resize(2);
delete pose_newed; delete anim_data_newed;
Pose* pose_ptr = new (buf) Pose; AnimData* anim_data_ptr = new (buf) AnimData;
pose_ptr->m_local_matrices.resize(4); anim_data_ptr->m_local_matrices.resize(4);
pose_ptr->m_local_matrices.resize(0); anim_data_ptr->m_local_matrices.resize(0);
pose_ptr->m_local_matrices.vector::~vector(); anim_data_ptr->m_local_matrices.vector::~vector();
delete[] buf; delete[] buf;
} }
@ -209,58 +211,17 @@ TEST_CASE_METHOD(
// Get runtime graph inputs and outputs // Get runtime graph inputs and outputs
float graph_float_input = 0.f; float graph_float_input = 0.f;
blend_tree.SetInput("GraphFloatInput", &graph_float_input); blend_tree.SetInput("GraphFloatInput", &graph_float_input);
CHECK(blend_tree.GetGraphInputs().size() == 1);
CHECK(
*blend_tree.GetGraphInputs()[0].m_reference.ptr_ptr
== &graph_float_input);
Pose graph_anim_output; AnimData graph_anim_output;
graph_anim_output.m_local_matrices.resize(skeleton->num_joints()); graph_anim_output.m_local_matrices.resize(skeleton->num_joints());
blend_tree.SetOutput("Output", &graph_anim_output); blend_tree.SetOutput("GraphOutput", &graph_anim_output);
CHECK(blend_tree.GetGraphOutputs().size() == 1);
CHECK(
*blend_tree.GetGraphOutputs()[0].m_reference.ptr_ptr
== &graph_anim_output);
WHEN("Blend Weight == 0.") {
// Evaluate graph
graph_float_input = 0.f;
blend_tree.StartUpdateTick();
blend_tree.MarkActiveInputs({});
THEN("Only Blend2 and first input of Blend2 node is active.") {
CHECK(
blend_tree.m_nodes[trans_x_node_index]->m_state
== AnimNodeEvalState::Activated);
CHECK(
blend_tree.m_nodes[trans_y_node_index]->m_state
== AnimNodeEvalState::Deactivated);
CHECK(
blend_tree.m_nodes[blend_node_index]->m_state
== AnimNodeEvalState::Activated);
}
blend_tree.UpdateTime(0.0, 0.5f);
blend_tree.Evaluate(graph_context);
CHECK(
graph_anim_output.m_local_matrices[0].translation.x[0]
== Approx(0.5).margin(0.01));
CHECK(
graph_anim_output.m_local_matrices[0].translation.y[0]
== Approx(0.0).margin(0.01));
}
WHEN("Blend Weight 0.1") {
// Evaluate graph // Evaluate graph
graph_float_input = 0.1f; graph_float_input = 0.1f;
blend_tree.StartUpdateTick(); blend_tree.StartUpdateTick();
blend_tree.MarkActiveInputs({}); blend_tree.MarkActiveInputs(blend_tree.GetGraphOutputConnections());
THEN("All nodes are active.") {
CHECK( CHECK(
blend_tree.m_nodes[trans_x_node_index]->m_state blend_tree.m_nodes[trans_x_node_index]->m_state
== AnimNodeEvalState::Activated); == AnimNodeEvalState::Activated);
@ -270,48 +231,14 @@ TEST_CASE_METHOD(
CHECK( CHECK(
blend_tree.m_nodes[blend_node_index]->m_state blend_tree.m_nodes[blend_node_index]->m_state
== AnimNodeEvalState::Activated); == AnimNodeEvalState::Activated);
}
blend_tree.UpdateTime(0.0, 0.5f); blend_tree.UpdateTime(0.0, 0.5f);
blend_tree.Evaluate(graph_context); blend_tree.Evaluate(graph_context);
CHECK( CHECK(
graph_anim_output.m_local_matrices[0].translation.x[0] graph_anim_output.m_local_matrices[0].translation.x[0]
== Approx(0.45).margin(0.01)); == Approx(0.5).margin(0.1));
CHECK( CHECK(
graph_anim_output.m_local_matrices[0].translation.y[0] graph_anim_output.m_local_matrices[0].translation.y[0]
== Approx(0.05).margin(0.01)); == Approx(0.05).margin(0.01));
} }
WHEN("Blend Weight 1.") {
// Evaluate graph
graph_float_input = 1.f;
blend_tree.StartUpdateTick();
blend_tree.MarkActiveInputs({});
THEN("Only Blend2 and second input of Blend2 are active.") {
CHECK(
blend_tree.m_nodes[trans_x_node_index]->m_state
== AnimNodeEvalState::Deactivated);
CHECK(
blend_tree.m_nodes[trans_y_node_index]->m_state
== AnimNodeEvalState::Activated);
CHECK(
blend_tree.m_nodes[blend_node_index]->m_state
== AnimNodeEvalState::Activated);
}
blend_tree.UpdateTime(0.0, 0.5f);
blend_tree.Evaluate(graph_context);
CHECK(
graph_anim_output.m_local_matrices[0].translation.x[0]
== Approx(0.).margin(0.01));
CHECK(
graph_anim_output.m_local_matrices[0].translation.y[0]
== Approx(0.5).margin(0.01));
}
delete blend_tree_resource;
}

View File

@ -41,7 +41,7 @@ class SimpleAnimSamplerBlendTreeResourceFixture
std::string("media/Walking-loop.ozz")); std::string("media/Walking-loop.ozz"));
AnimNodeResource* graph_node = blend_tree_resource->GetGraphOutputNode(); AnimNodeResource* graph_node = blend_tree_resource->GetGraphOutputNode();
graph_node->m_virtual_socket_accessor->RegisterInput<Pose>( graph_node->m_virtual_socket_accessor->RegisterInput<AnimData>(
"GraphOutput", "GraphOutput",
nullptr); nullptr);
@ -161,14 +161,14 @@ class EmbeddedBlendTreeGraphResource : public BlendTreeResourceFixture {
// Embedded: outputs // Embedded: outputs
AnimNodeResource* embedded_outputs = AnimNodeResource* embedded_outputs =
embedded_blend_tree_resource->GetGraphOutputNode(); embedded_blend_tree_resource->GetGraphOutputNode();
embedded_outputs->m_virtual_socket_accessor->RegisterInput<Pose>( embedded_outputs->m_virtual_socket_accessor->RegisterInput<AnimData>(
"AnimOutput", "AnimOutput",
nullptr); nullptr);
// Embedded: inputs // Embedded: inputs
AnimNodeResource* embedded_inputs = AnimNodeResource* embedded_inputs =
embedded_blend_tree_resource->GetGraphInputNode(); embedded_blend_tree_resource->GetGraphInputNode();
embedded_inputs->m_virtual_socket_accessor->RegisterOutput<Pose>( embedded_inputs->m_virtual_socket_accessor->RegisterOutput<AnimData>(
"AnimInput", "AnimInput",
nullptr); nullptr);
@ -267,7 +267,7 @@ class EmbeddedTreeBlend2GraphResource : public BlendTreeResourceFixture {
embedded_blend_tree_resource->m_name = "EmbeddedTreeBlend2GraphResource"; embedded_blend_tree_resource->m_name = "EmbeddedTreeBlend2GraphResource";
// Embedded: inputs // Embedded: inputs
embedded_blend_tree_resource->RegisterBlendTreeInputSocket<Pose>( embedded_blend_tree_resource->RegisterBlendTreeInputSocket<AnimData>(
"AnimInput"); "AnimInput");
embedded_blend_tree_resource->RegisterBlendTreeInputSocket<float>( embedded_blend_tree_resource->RegisterBlendTreeInputSocket<float>(
"BlendWeight"); "BlendWeight");
@ -482,7 +482,7 @@ TEST_CASE_METHOD(
REQUIRE(anim_sampler_walk->m_animation != nullptr); REQUIRE(anim_sampler_walk->m_animation != nullptr);
// Ensure that outputs are properly propagated. // Ensure that outputs are properly propagated.
Pose output; AnimData output;
output.m_local_matrices.resize(skeleton.num_soa_joints()); output.m_local_matrices.resize(skeleton.num_soa_joints());
anim_graph_blend_tree.SetOutput( anim_graph_blend_tree.SetOutput(
AnimGraphResource::DefaultAnimOutput, AnimGraphResource::DefaultAnimOutput,
@ -764,8 +764,9 @@ TEST_CASE_METHOD(
CHECK(blend2_instance->i_input0 == anim_sampler_walk->o_output); CHECK(blend2_instance->i_input0 == anim_sampler_walk->o_output);
CHECK(blend2_instance->i_input1 == anim_sampler_run->o_output); CHECK(blend2_instance->i_input1 == anim_sampler_run->o_output);
Pose* graph_output = blend_tree_graph.GetOutputPtr<Pose>( AnimData* graph_output =
AnimGraphResource::DefaultAnimOutput); static_cast<AnimData*>(blend_tree_graph.GetOutputPtr<AnimData>(
AnimGraphResource::DefaultAnimOutput));
CHECK( CHECK(
graph_output->m_local_matrices.size() graph_output->m_local_matrices.size()

View File

@ -10,32 +10,24 @@ TEST_CASE("Descriptor Access", "[NodeDescriptorTests]") {
Blend2Node blend2Node; Blend2Node blend2Node;
NodeDescriptor<Blend2Node> blend2Descriptor (&blend2Node); NodeDescriptor<Blend2Node> blend2Descriptor (&blend2Node);
CHECK(blend2Descriptor.m_inputs.size() == 3); CHECK(blend2Descriptor.m_inputs.size() == 3);
CHECK( CHECK(*blend2Descriptor.m_inputs[0].m_reference.ptr_ptr == blend2Node.i_input0);
*blend2Descriptor.m_inputs[0].m_reference.ptr_ptr == blend2Node.i_input0); CHECK(*blend2Descriptor.m_inputs[1].m_reference.ptr_ptr == blend2Node.i_input1);
CHECK( CHECK(*blend2Descriptor.m_inputs[2].m_reference.ptr_ptr == blend2Node.i_blend_weight);
*blend2Descriptor.m_inputs[1].m_reference.ptr_ptr == blend2Node.i_input1);
CHECK(
*blend2Descriptor.m_inputs[2].m_reference.ptr_ptr
== blend2Node.i_blend_weight);
CHECK(blend2Descriptor.m_inputs[0].m_type_size == sizeof(Pose)); CHECK(blend2Descriptor.m_inputs[0].m_type_size == sizeof(AnimData));
CHECK(blend2Descriptor.m_inputs[2].m_type_size == 4); CHECK(blend2Descriptor.m_inputs[2].m_type_size == 4);
CHECK(blend2Descriptor.m_outputs.size() == 1); CHECK(blend2Descriptor.m_outputs.size() == 1);
CHECK( CHECK(*blend2Descriptor.m_outputs[0].m_reference.ptr_ptr == blend2Node.o_output);
*blend2Descriptor.m_outputs[0].m_reference.ptr_ptr
== blend2Node.o_output);
CHECK(blend2Descriptor.m_properties.size() == 1); CHECK(blend2Descriptor.m_properties.size() == 1);
CHECK( CHECK(blend2Descriptor.m_properties[0].m_reference.ptr == &blend2Node.m_sync_blend);
blend2Descriptor.m_properties[0].m_reference.ptr
== &blend2Node.m_sync_blend);
// Check we can properly update inputs // Check we can properly update inputs
CHECK(blend2Node.i_input0 == nullptr); CHECK(blend2Node.i_input0 == nullptr);
Pose pose; AnimData some_anim_data;
blend2Descriptor.SetInput("Input0", &pose); blend2Descriptor.SetInput("Input0", &some_anim_data);
CHECK(blend2Node.i_input0 == &pose); CHECK(blend2Node.i_input0 == &some_anim_data);
// Check we properly can set properties // Check we properly can set properties
CHECK(blend2Node.m_sync_blend == false); CHECK(blend2Node.m_sync_blend == false);
@ -49,7 +41,6 @@ TEST_CASE("Descriptor Access", "[NodeDescriptorTests]") {
blend2Descriptor.UpdateFlags(); blend2Descriptor.UpdateFlags();
Socket* weight_input_socket = blend2Descriptor.GetInputSocket("Weight"); Socket* weight_input_socket = blend2Descriptor.GetInputSocket("Weight");
CHECK(weight_input_socket != nullptr); CHECK(weight_input_socket != nullptr);
CHECK( CHECK(weight_input_socket->m_flags & SocketFlagAffectsTime == SocketFlagAffectsTime);
weight_input_socket->m_flags
& SocketFlagAffectsTime == SocketFlagAffectsTime);
} }