From 7152fa74e197bf0bf74cae9b0e4224e767a1497e Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Sun, 26 Mar 2023 13:25:44 +0200 Subject: [PATCH] Added SkinnedMeshResource --- CMakeLists.txt | 8 ++- media/SampleSkinnedMesh.json | 74 +++++++++++++++++++++++ src/SkinnedMesh.cc | 5 +- src/SkinnedMesh.h | 1 - src/SkinnedMeshResource.cc | 112 +++++++++++++++++++++++++++++++++++ src/SkinnedMeshResource.h | 26 ++++++++ src/SyncTrack.h | 1 + src/main.cc | 86 ++------------------------- 8 files changed, 227 insertions(+), 86 deletions(-) create mode 100644 media/SampleSkinnedMesh.json create mode 100644 src/SkinnedMeshResource.cc create mode 100644 src/SkinnedMeshResource.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 09baef8..e72cef3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,8 @@ add_library(AnimTestbedCode OBJECT src/Camera.c src/SkinnedMesh.cc src/SkinnedMesh.h + src/SkinnedMeshResource.cc + src/SkinnedMeshResource.h src/SyncTrack.cc src/SyncTrack.h src/ozzutils.cc @@ -59,7 +61,11 @@ add_library(AnimTestbedCode OBJECT src/AnimGraph/AnimGraphEditor.cc src/AnimGraph/AnimGraphEditor.h src/AnimGraph/AnimGraph.cc - src/AnimGraph/AnimGraph.h src/AnimGraph/AnimGraphNodes.cc src/AnimGraph/AnimGraphNodes.h src/AnimGraph/AnimGraphData.cc src/AnimGraph/AnimGraphData.h) + src/AnimGraph/AnimGraph.h + src/AnimGraph/AnimGraphNodes.cc + src/AnimGraph/AnimGraphNodes.h + src/AnimGraph/AnimGraphData.cc + src/AnimGraph/AnimGraphData.h) target_include_directories( AnimTestbedCode diff --git a/media/SampleSkinnedMesh.json b/media/SampleSkinnedMesh.json new file mode 100644 index 0000000..7a3399f --- /dev/null +++ b/media/SampleSkinnedMesh.json @@ -0,0 +1,74 @@ +{ + "animations": [ + { + "file": "../media/Idle-loop.ozz", + "sync_track": { + "duration": 8.233333587646484, + "markers": [ + 0.0, + 0.5 + ], + "type": "SyncTrack" + } + }, + { + "file": "../media/Walking-loop.ozz", + "sync_track": { + "duration": 1.0666667222976685, + "markers": [ + 0.2930000126361847, + 0.7620000243186951 + ], + "type": "SyncTrack" + } + }, + { + "file": "../media/RunningSlow-loop.ozz", + "sync_track": { + "duration": 0.8333333134651184, + "markers": [ + 0.3149999976158142, + 0.8339999914169312 + ], + "type": "SyncTrack" + } + }, + { + "file": "../media/RunningFast-loop.ozz", + "sync_track": { + "duration": 0.5333333611488342, + "markers": [ + 0.40299999713897705, + 0.8180000185966492 + ], + "type": "SyncTrack" + } + }, + { + "file": "../media/Limping-loop.ozz", + "sync_track": { + "duration": 1.6666666269302368, + "markers": [ + 0.7570000290870667, + 0.04399999976158142 + ], + "type": "SyncTrack" + } + }, + { + "file": "../media/ZombieWalk-loop.ozz", + "sync_track": { + "duration": 1.5666667222976685, + "markers": [ + 0.6190000176429749, + 0.0 + ], + "type": "SyncTrack" + } + } + ], + "skeleton": { + "file": "../media/MixamoYBot-skeleton.ozz" + }, + "type": "SkinnedMeshResource" +} diff --git a/src/SkinnedMesh.cc b/src/SkinnedMesh.cc index 5f6ec03..0f91e36 100644 --- a/src/SkinnedMesh.cc +++ b/src/SkinnedMesh.cc @@ -17,8 +17,7 @@ SkinnedMesh::~SkinnedMesh() { } bool SkinnedMesh::LoadSkeleton(const char* filename) { - // const char* skeleton_file = "../media/skeleton.ozz"; - const char* skeleton_file = "../media/MixamoYBot-skeleton.ozz"; + const char* skeleton_file = filename; assert(filename); ozz::log::Out() << "Loading skeleton archive " << filename << "." @@ -103,7 +102,7 @@ void SkinnedMesh::DrawSkeleton() {} void SkinnedMesh::DrawDebugUi() { if (ImGui::TreeNode("Bones")) { for (int i = 0; i < m_skeleton.num_joints(); i++) { - ImGui::Text(m_skeleton.joint_names()[i]); + ImGui::Text("%s", m_skeleton.joint_names()[i]); } ImGui::TreePop(); } diff --git a/src/SkinnedMesh.h b/src/SkinnedMesh.h index db20900..77236b2 100644 --- a/src/SkinnedMesh.h +++ b/src/SkinnedMesh.h @@ -27,7 +27,6 @@ struct SkinnedMesh { bool LoadSkeleton(const char* filename); bool LoadAnimation(const char* filename); - //bool LoadMesh (const char* filename); void SetCurrentAnimation(int index); const ozz::animation::Animation* GetCurrentAnimation() { diff --git a/src/SkinnedMeshResource.cc b/src/SkinnedMeshResource.cc new file mode 100644 index 0000000..141cec4 --- /dev/null +++ b/src/SkinnedMeshResource.cc @@ -0,0 +1,112 @@ +// +// Created by martin on 26.03.23. +// + +#include "SkinnedMeshResource.h" + +#include + +#include "3rdparty/json/json.hpp" + +inline void to_json(nlohmann::json& j, const SyncTrack& syncTrack) { + j["type"] = "SyncTrack"; + j["duration"] = syncTrack.m_duration; + for (int i = 0; i < syncTrack.m_num_intervals; i++) { + j["markers"][i] = syncTrack.m_sync_markers[i]; + } +} + +inline void from_json(const nlohmann::json& j, SyncTrack& syncTrack) { + if (!j.contains("type") || j["type"] != "SyncTrack") { + std::cerr << "Unable to parse SyncTrack: wrong json type!" << std::endl; + return; + } + + syncTrack.m_duration = j["duration"]; + syncTrack.m_num_intervals = j["markers"].size(); + + if (syncTrack.m_num_intervals > cSyncTrackMaxIntervals) { + std::cerr << "Invalid number of sync intervals: found " << syncTrack.m_num_intervals << " maximum is " << cSyncTrackMaxIntervals << "." << std::endl; + syncTrack = SyncTrack(); + } + + for (int i = 0; i < syncTrack.m_num_intervals; i++) { + syncTrack.m_sync_markers[i] = j["markers"].at(i); + } +} + +inline void to_json(nlohmann::json& j, const SkinnedMeshResource& skinnedMeshResource) { + j["type"] = "SkinnedMeshResource"; + j["skeleton"]["file"] = skinnedMeshResource.m_skeleton_file; + for (int i = 0; i < skinnedMeshResource.m_animation_files.size(); i++) { + j["animations"][i]["file"] = skinnedMeshResource.m_animation_files[i]; + j["animations"][i]["sync_track"] = skinnedMeshResource.m_sync_tracks[i]; + } +} + +inline void from_json(const nlohmann::json& j, SkinnedMeshResource& skinnedMeshResource) { + if (!j.contains("type") || j["type"] != "SkinnedMeshResource") { + std::cerr << "Unable to parse SkinnedMeshResource: wrong json type!" << std::endl; + return; + } + + if (!j.contains("skeleton") || !j["skeleton"].contains("file")) { + std::cerr << "Unable to parse SkinnedMeshResource: no skeleton file found!" << std::endl; + + } + + skinnedMeshResource.m_skeleton_file = j["skeleton"]["file"]; + + if (j.contains("animations")) { + int num_animations = j["animations"].size(); + + for (int i = 0; i < num_animations; i++) { + if (!j["animations"][i].contains("file") || !j["animations"][i].contains("sync_track")) { + std::cerr << "Unable to parse SkinnedMeshResource: invalid animation definition" << std::endl; + return; + } + + skinnedMeshResource.m_animation_files.push_back(j["animations"][i]["file"]); + skinnedMeshResource.m_sync_tracks.push_back(j["animations"][i]["sync_track"].get()); + } + } +} + +bool SkinnedMeshResource::saveToFile(const char* filename) const { + nlohmann::json j = *this; + + std::ofstream output_file(filename); + output_file << j.dump(4, ' ') << std::endl; + output_file.close(); + + return true; +} + +bool SkinnedMeshResource::loadFromFile(const char* filename) { + if (!std::filesystem::exists(filename)) { + std::cerr << "Error: file " << filename << " does not exist!" << std::endl; + return false; + } + + m_resource_file = filename; + std::ifstream input_file; + input_file.open(filename); + std::stringstream buffer; + buffer << input_file.rdbuf(); + + nlohmann::json j = nlohmann::json::parse(buffer.str(), nullptr, false); + + *this = j.get(); + + return true; +} + +void SkinnedMeshResource::createInstance(SkinnedMesh& skinnedMesh) const { + skinnedMesh.LoadSkeleton(m_skeleton_file.c_str()); + for (int i = 0; i < m_animation_files.size(); i++) { + skinnedMesh.LoadAnimation(m_animation_files[i].c_str()); + skinnedMesh.m_animation_sync_track.push_back(m_sync_tracks[i]); + } +} + + diff --git a/src/SkinnedMeshResource.h b/src/SkinnedMeshResource.h new file mode 100644 index 0000000..31d4c71 --- /dev/null +++ b/src/SkinnedMeshResource.h @@ -0,0 +1,26 @@ +// +// Created by martin on 26.03.23. +// + +#ifndef ANIMTESTBED_SKINNEDMESHRESOURCE_H +#define ANIMTESTBED_SKINNEDMESHRESOURCE_H + +#include +#include + +#include "SyncTrack.h" +#include "SkinnedMesh.h" + +struct SkinnedMeshResource { + std::string m_resource_file; + std::string m_skeleton_file; + std::vector m_animation_files; + std::vector m_sync_tracks; + + bool saveToFile(const char* filename) const; + bool loadFromFile(const char* filename); + + void createInstance(SkinnedMesh& skinnedMesh) const; +}; + +#endif //ANIMTESTBED_SKINNEDMESHRESOURCE_H diff --git a/src/SyncTrack.h b/src/SyncTrack.h index 00fd44f..35e62ad 100644 --- a/src/SyncTrack.h +++ b/src/SyncTrack.h @@ -7,6 +7,7 @@ #include #include +#include constexpr int cSyncTrackMaxIntervals = 8; diff --git a/src/main.cc b/src/main.cc index 2a3a3ea..9cde157 100644 --- a/src/main.cc +++ b/src/main.cc @@ -19,6 +19,7 @@ #include "Camera.h" #include "GLFW/glfw3.h" #include "SkinnedMesh.h" +#include "SkinnedMeshResource.h" #include "src/AnimGraph/AnimGraphEditor.h" const int Width = 1024; @@ -350,57 +351,11 @@ int main() { sgldesc.sample_count = 0; sgl_setup(&sgldesc); - // Animation setup + SkinnedMeshResource skinned_mesh_resource; + skinned_mesh_resource.loadFromFile("../media/SampleSkinnedMesh.json"); + SkinnedMesh skinned_mesh; - skinned_mesh.LoadSkeleton("../media/MixamoYBot-skeleton.ozz"); - skinned_mesh.LoadAnimation("../media/Idle-loop.ozz"); - - int anim_idx = 0; - float idle_markers[] = {0.f, 0.5}; - skinned_mesh.m_animation_sync_track[anim_idx] = SyncTrack::CreateFromMarkers( - skinned_mesh.m_animations[anim_idx]->duration(), - 2, - idle_markers); - - anim_idx = 1; - skinned_mesh.LoadAnimation("../media/Walking-loop.ozz"); - float walking_markers[] = {0.293, 0.762}; - skinned_mesh.m_animation_sync_track[anim_idx] = SyncTrack::CreateFromMarkers( - skinned_mesh.m_animations[anim_idx]->duration(), - 2, - walking_markers); - - anim_idx = 2; - skinned_mesh.LoadAnimation("../media/RunningSlow-loop.ozz"); - float running_slow_markers[] = {0.315, 0.834}; - skinned_mesh.m_animation_sync_track[anim_idx] = SyncTrack::CreateFromMarkers( - skinned_mesh.m_animations[anim_idx]->duration(), - 2, - running_slow_markers); - - anim_idx = 3; - skinned_mesh.LoadAnimation("../media/RunningFast-loop.ozz"); - float running_fast_markers[] = {0.403, 0.818}; - skinned_mesh.m_animation_sync_track[anim_idx] = SyncTrack::CreateFromMarkers( - skinned_mesh.m_animations[anim_idx]->duration(), - 2, - running_fast_markers); - - anim_idx = 4; - skinned_mesh.LoadAnimation("../media/Limping-loop.ozz"); - float limping_markers[] = {0.757, 0.044}; - skinned_mesh.m_animation_sync_track[anim_idx] = SyncTrack::CreateFromMarkers( - skinned_mesh.m_animations[anim_idx]->duration(), - 2, - limping_markers); - - anim_idx = 5; - skinned_mesh.LoadAnimation("../media/ZombieWalk-loop.ozz"); - float zombiewalk_markers[] = {0.619, 0.}; - skinned_mesh.m_animation_sync_track[anim_idx] = SyncTrack::CreateFromMarkers( - skinned_mesh.m_animations[anim_idx]->duration(), - 2, - zombiewalk_markers); + skinned_mesh_resource.createInstance(skinned_mesh); skinned_mesh.SetCurrentAnimation(0); @@ -776,37 +731,6 @@ bool LoadAnimation( return true; } -static void load_skeleton(void) { - // const char* skeleton_file = "../media/skeleton.ozz"; - const char* skeleton_file = "../media/MixamoYBot-skeleton.ozz"; - if (!LoadSkeleton(skeleton_file, &state.ozz->skeleton)) { - std::cerr << "Could not load skeleton " << skeleton_file << std::endl; - return; - } - - const int num_soa_joints = state.ozz->skeleton.num_soa_joints(); - const int num_joints = state.ozz->skeleton.num_joints(); - state.ozz->local_matrices.resize(num_soa_joints); - state.ozz->model_matrices.resize(num_joints); - state.ozz->cache.Resize(num_joints); - state.loaded.skeleton = true; - std::cout << "Successfully loaded " << skeleton_file - << " (soa: " << num_soa_joints << ", joints: " << num_joints << ")" - << std::endl; -} - -static void load_animation(void) { - // const char* anim_file = "../media/animation1.ozz"; - const char* anim_file = "../media/RunningSlow-loop.ozz"; - if (!LoadAnimation(anim_file, &state.ozz->animation)) { - std::cerr << "Could not load animation " << anim_file << std::endl; - return; - } - - state.loaded.animation = true; - std::cout << "Successfully loade " << anim_file << std::endl; -} - static void draw_vec(const ozz::math::SimdFloat4& vec) { sgl_v3f(ozz::math::GetX(vec), ozz::math::GetY(vec), ozz::math::GetZ(vec)); }