AnimTestbed/tests/AnimGraphEvalTests.cc

218 lines
7.5 KiB
C++

//
// Created by martin on 04.02.22.
//
#include "AnimGraph/AnimGraph.h"
#include "AnimGraph/AnimGraphEditor.h"
#include "AnimGraph/AnimGraphResource.h"
#include "catch.hpp"
#include "ozz/animation/offline/animation_builder.h"
#include "ozz/animation/offline/raw_animation.h"
#include "ozz/animation/offline/raw_skeleton.h"
#include "ozz/animation/offline/skeleton_builder.h"
#include "ozz/animation/runtime/animation.h"
#include "ozz/base/io/archive.h"
#include "ozz/base/io/stream.h"
#include "ozz/base/log.h"
struct SimpleAnimFixture {
ozz::unique_ptr<ozz::animation::Skeleton> skeleton = nullptr;
ozz::animation::offline::RawAnimation raw_animation_translation_x;
ozz::unique_ptr<ozz::animation::Animation> animation_translate_x = nullptr;
ozz::animation::offline::RawAnimation raw_animation_translation_y;
ozz::unique_ptr<ozz::animation::Animation> animation_translate_y = nullptr;
ozz::vector<ozz::math::SoaTransform> animation_output;
ozz::animation::SamplingJob::Context sampling_context;
SimpleAnimFixture() {
createSkeleton();
createAnimations();
animation_output.resize(skeleton->num_soa_joints());
sampling_context.Resize(skeleton->num_joints());
}
void createSkeleton() {
using namespace ozz::animation::offline;
RawSkeleton raw_skeleton;
RawSkeleton::Joint raw_joint;
raw_joint.name = "Bone0";
raw_joint.transform.translation.x = 1.f;
raw_joint.transform.translation.y = 2.f;
raw_joint.transform.translation.z = 3.f;
raw_skeleton.roots.push_back(raw_joint);
SkeletonBuilder skeleton_builder;
skeleton = skeleton_builder(raw_skeleton);
}
void createAnimations() {
using namespace ozz::animation::offline;
raw_animation_translation_x.name = "TranslationX";
RawAnimation::JointTrack bone0_track;
RawAnimation::JointTrack::Translations bone0_translations;
// animation_translate_x
RawAnimation::TranslationKey translation_key;
translation_key.time = 0.f;
translation_key.value = ozz::math::Float3(0.f, 0.f, 0.f);
bone0_translations.push_back(translation_key);
translation_key.time = 1.f;
translation_key.value = ozz::math::Float3(1.f, 0.f, 9.f);
bone0_translations.push_back(translation_key);
bone0_track.translations = bone0_translations;
raw_animation_translation_x.tracks.push_back(bone0_track);
raw_animation_translation_x.duration = 1.f;
REQUIRE(raw_animation_translation_x.Validate());
AnimationBuilder animation_builder;
animation_translate_x = animation_builder(raw_animation_translation_x);
// animation_translate_y
raw_animation_translation_y.name = "TranslationY";
bone0_translations.clear();
translation_key.time = 0.f;
translation_key.value = ozz::math::Float3(0.f, 0.f, 0.f);
bone0_translations.push_back(translation_key);
translation_key.time = 1.f;
translation_key.value = ozz::math::Float3(0.f, 1.f, 0.f);
bone0_translations.push_back(translation_key);
bone0_track.translations = bone0_translations;
raw_animation_translation_y.tracks.push_back(bone0_track);
raw_animation_translation_y.duration = 1.f;
REQUIRE(raw_animation_translation_y.Validate());
animation_translate_y = animation_builder(raw_animation_translation_y);
}
};
TEST_CASE_METHOD(
SimpleAnimFixture,
"Create Animations",
"[AnimGraphEvalTests]") {
using namespace ozz::animation::offline;
ozz::animation::SamplingJob sampling_job;
sampling_job.animation = animation_translate_x.get();
sampling_job.context = &sampling_context;
sampling_job.ratio = 1.f;
sampling_job.output = make_span(animation_output);
REQUIRE(sampling_job.Run());
RawAnimation::TranslationKey& translation_key =
raw_animation_translation_x.tracks[0].translations.back();
ozz::math::SoaFloat3& sampled_translation = animation_output[0].translation;
CHECK(
sampled_translation.x[0] == Approx(translation_key.value.x).margin(0.01));
CHECK(
sampled_translation.y[0] == Approx(translation_key.value.y).margin(0.01));
CHECK(
sampled_translation.z[0] == Approx(translation_key.value.z).margin(0.01));
}
TEST_CASE("AnimDataPlacementNew", "[AnimGraphEval]") {
int anim_data_size = sizeof(AnimData);
char* buf = new char[anim_data_size];
AnimData* anim_data_newed = new AnimData;
anim_data_newed->m_local_matrices.resize(2);
delete anim_data_newed;
AnimData* anim_data_ptr = new (buf) AnimData;
anim_data_ptr->m_local_matrices.resize(4);
anim_data_ptr->m_local_matrices.resize(0);
anim_data_ptr->m_local_matrices.vector::~vector();
delete[] buf;
}
TEST_CASE_METHOD(
SimpleAnimFixture,
"AnimGraphSimpleEval",
"[AnimGraphEvalTests]") {
AnimGraphResource graph_resource;
// Add nodes
size_t trans_x_node_index =
graph_resource.addNode(AnimNodeResourceFactory("AnimSampler"));
size_t trans_y_node_index =
graph_resource.addNode(AnimNodeResourceFactory("AnimSampler"));
size_t blend_node_index =
graph_resource.addNode(AnimNodeResourceFactory("Blend2"));
// Setup nodes
AnimNodeResource& trans_x_node = graph_resource.m_nodes[trans_x_node_index];
trans_x_node.m_socket_accessor->SetPropertyValue("Filename", std::string("trans_x"));
trans_x_node.m_name = "trans_x";
AnimNodeResource& trans_y_node = graph_resource.m_nodes[trans_y_node_index];
trans_y_node.m_socket_accessor->SetPropertyValue("Filename", std::string("trans_y"));
trans_y_node.m_name = "trans_y";
AnimNodeResource& blend_node = graph_resource.m_nodes[blend_node_index];
blend_node.m_name = "BlendWalkRun";
// Setup graph outputs and inputs
AnimNodeResource& graph_output_node = graph_resource.getGraphOutputNode();
graph_output_node.m_socket_accessor->RegisterInput<AnimData>("GraphOutput", nullptr);
AnimNodeResource& graph_input_node =
graph_resource.getGraphInputNode();
graph_input_node.m_socket_accessor->RegisterOutput<float>(
"GraphFloatInput",
nullptr);
// Wire up nodes
graph_resource.connectSockets(trans_x_node, "Output", blend_node, "Input0");
graph_resource.connectSockets(trans_y_node, "Output", blend_node, "Input1");
graph_resource.connectSockets(
blend_node,
"Output",
graph_resource.getGraphOutputNode(),
"GraphOutput");
REQUIRE(graph_resource.connectSockets(graph_input_node, "GraphFloatInput", blend_node, "Weight"));
// Prepare animation maps
AnimGraphContext graph_context;
graph_context.m_skeleton = skeleton.get();
graph_context.m_animation_map["trans_x"] = animation_translate_x.get();
graph_context.m_animation_map["trans_y"] = animation_translate_y.get();
// Instantiate graph
AnimGraph graph;
graph_resource.createInstance(graph);
graph.init(graph_context);
// Get runtime graph inputs and outputs
float graph_float_input = 0.f;
graph.SetInput("GraphFloatInput", &graph_float_input);
AnimData graph_anim_output;
graph_anim_output.m_local_matrices.resize(skeleton->num_joints());
graph.SetOutput("GraphOutput", &graph_anim_output);
// Evaluate graph
graph_float_input = 0.1f;
graph.markActiveNodes();
CHECK(graph.m_nodes[trans_x_node_index]->m_state == AnimNodeEvalState::Activated);
CHECK(graph.m_nodes[trans_y_node_index]->m_state == AnimNodeEvalState::Activated);
CHECK(graph.m_nodes[blend_node_index]->m_state == AnimNodeEvalState::Activated);
graph.updateTime(0.5f);
graph.evaluate(graph_context);
CHECK(graph_anim_output.m_local_matrices[0].translation.x[0] == Approx(0.5).margin(0.1));
CHECK(graph_anim_output.m_local_matrices[0].translation.y[0] == Approx(0.05).margin(0.01));
}