// // Created by martin on 12.11.21. // #include "SkinnedMesh.h" #include #include SkinnedMesh::~SkinnedMesh() { while (m_animations.size() > 0) { ozz::animation::Animation* animation_ptr = m_animations[m_animations.size() - 1]; delete animation_ptr; m_animations.pop_back(); } } bool SkinnedMesh::LoadSkeleton(const char* filename) { // const char* skeleton_file = "../media/skeleton.ozz"; const char* skeleton_file = "../media/MixamoYBot-skeleton.ozz"; assert(filename); ozz::log::Out() << "Loading skeleton archive " << filename << "." << std::endl; ozz::io::File file(filename, "rb"); if (!file.opened()) { ozz::log::Err() << "Failed to open skeleton file " << filename << "." << std::endl; return false; } ozz::io::IArchive archive(&file); if (!archive.TestTag()) { ozz::log::Err() << "Failed to load skeleton instance from file " << filename << "." << std::endl; return false; } // Once the tag is validated, reading cannot fail. archive >> m_skeleton; const int num_soa_joints = m_skeleton.num_soa_joints(); const int num_joints = m_skeleton.num_joints(); m_local_matrices.resize(num_soa_joints); m_model_matrices.resize(num_joints); m_cache.Resize(num_joints); std::cout << "Successfully loaded " << skeleton_file << " (soa: " << num_soa_joints << ", joints: " << num_joints << ")" << std::endl; return true; } bool SkinnedMesh::LoadAnimation(const char* filename) { ozz::animation::Animation* animation_ptr = new ozz::animation::Animation(); assert(filename); ozz::log::Out() << "Loading animation archive: " << filename << "." << std::endl; ozz::io::File file(filename, "rb"); if (!file.opened()) { ozz::log::Err() << "Failed to open animation file " << filename << "." << std::endl; return false; } ozz::io::IArchive archive(&file); if (!archive.TestTag()) { ozz::log::Err() << "Failed to load animation instance from file " << filename << "." << std::endl; return false; } // Once the tag is validated, reading cannot fail. archive >> *animation_ptr; m_animations.push_back(animation_ptr); m_animation_names.push_back(filename); m_animation_sync_track.push_back(SyncTrack()); return true; } void SkinnedMesh::SetCurrentAnimation(int index) { if (index < 0 || index >= m_animations.size()) { ozz::log::Err() << "Invalid animation index " << index << " valid range: [" << 0 << ", " << m_animations.size() << "]'" << std::endl; } m_current_animation = m_animations[index]; } void SkinnedMesh::CalcModelMatrices() { // convert joint matrices from local to model space ozz::animation::LocalToModelJob ltm_job; ltm_job.skeleton = &m_skeleton; ltm_job.input = make_span(m_local_matrices); ltm_job.output = make_span(m_model_matrices); ltm_job.Run(); } void SkinnedMesh::DrawSkeleton() {} void SkinnedMesh::DrawDebugUi() { ImGui::Begin("SkinnedMesh"); ImGui::Text("Animations"); const char* items[255] = {0}; static int selected = -1; for (int i = 0; i < m_animations.size(); i++) { items[i] = m_animation_names[i].c_str(); } ImGui::Combo("Animation", &selected, items, m_animations.size()); ImGui::Text("Sync Track"); if (selected >= 0 && selected < m_animations.size()) { m_animation_sync_track[selected].DrawDebugUi(); m_override_anim = selected; ImGui::Checkbox("Override Animation", &m_sync_track_override); if (m_sync_track_override) { ImGui::SliderFloat("Ratio", &m_override_ratio, 0.f, 1.f); ozz::animation::SamplingJob sampling_job; sampling_job.animation = m_animations[selected]; sampling_job.cache = &m_cache; sampling_job.ratio = m_override_ratio; sampling_job.output = make_span(m_local_matrices); if (!sampling_job.Run()) { ozz::log::Err() << "Error sampling animation." << std::endl; } } } ImGui::End(); }