Added SkinnedMeshResource
parent
15871f349c
commit
7152fa74e1
|
@ -46,6 +46,8 @@ add_library(AnimTestbedCode OBJECT
|
||||||
src/Camera.c
|
src/Camera.c
|
||||||
src/SkinnedMesh.cc
|
src/SkinnedMesh.cc
|
||||||
src/SkinnedMesh.h
|
src/SkinnedMesh.h
|
||||||
|
src/SkinnedMeshResource.cc
|
||||||
|
src/SkinnedMeshResource.h
|
||||||
src/SyncTrack.cc
|
src/SyncTrack.cc
|
||||||
src/SyncTrack.h
|
src/SyncTrack.h
|
||||||
src/ozzutils.cc
|
src/ozzutils.cc
|
||||||
|
@ -59,7 +61,11 @@ add_library(AnimTestbedCode OBJECT
|
||||||
src/AnimGraph/AnimGraphEditor.cc
|
src/AnimGraph/AnimGraphEditor.cc
|
||||||
src/AnimGraph/AnimGraphEditor.h
|
src/AnimGraph/AnimGraphEditor.h
|
||||||
src/AnimGraph/AnimGraph.cc
|
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(
|
target_include_directories(
|
||||||
AnimTestbedCode
|
AnimTestbedCode
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
|
@ -17,8 +17,7 @@ SkinnedMesh::~SkinnedMesh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkinnedMesh::LoadSkeleton(const char* filename) {
|
bool SkinnedMesh::LoadSkeleton(const char* filename) {
|
||||||
// const char* skeleton_file = "../media/skeleton.ozz";
|
const char* skeleton_file = filename;
|
||||||
const char* skeleton_file = "../media/MixamoYBot-skeleton.ozz";
|
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
ozz::log::Out() << "Loading skeleton archive " << filename << "."
|
ozz::log::Out() << "Loading skeleton archive " << filename << "."
|
||||||
|
@ -103,7 +102,7 @@ void SkinnedMesh::DrawSkeleton() {}
|
||||||
void SkinnedMesh::DrawDebugUi() {
|
void SkinnedMesh::DrawDebugUi() {
|
||||||
if (ImGui::TreeNode("Bones")) {
|
if (ImGui::TreeNode("Bones")) {
|
||||||
for (int i = 0; i < m_skeleton.num_joints(); i++) {
|
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();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ struct SkinnedMesh {
|
||||||
|
|
||||||
bool LoadSkeleton(const char* filename);
|
bool LoadSkeleton(const char* filename);
|
||||||
bool LoadAnimation(const char* filename);
|
bool LoadAnimation(const char* filename);
|
||||||
//bool LoadMesh (const char* filename);
|
|
||||||
|
|
||||||
void SetCurrentAnimation(int index);
|
void SetCurrentAnimation(int index);
|
||||||
const ozz::animation::Animation* GetCurrentAnimation() {
|
const ozz::animation::Animation* GetCurrentAnimation() {
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
//
|
||||||
|
// Created by martin on 26.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SkinnedMeshResource.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#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<SyncTrack>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<SkinnedMeshResource>();
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
//
|
||||||
|
// Created by martin on 26.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ANIMTESTBED_SKINNEDMESHRESOURCE_H
|
||||||
|
#define ANIMTESTBED_SKINNEDMESHRESOURCE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "SyncTrack.h"
|
||||||
|
#include "SkinnedMesh.h"
|
||||||
|
|
||||||
|
struct SkinnedMeshResource {
|
||||||
|
std::string m_resource_file;
|
||||||
|
std::string m_skeleton_file;
|
||||||
|
std::vector<std::string> m_animation_files;
|
||||||
|
std::vector<SyncTrack> m_sync_tracks;
|
||||||
|
|
||||||
|
bool saveToFile(const char* filename) const;
|
||||||
|
bool loadFromFile(const char* filename);
|
||||||
|
|
||||||
|
void createInstance(SkinnedMesh& skinnedMesh) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //ANIMTESTBED_SKINNEDMESHRESOURCE_H
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
constexpr int cSyncTrackMaxIntervals = 8;
|
constexpr int cSyncTrackMaxIntervals = 8;
|
||||||
|
|
||||||
|
|
86
src/main.cc
86
src/main.cc
|
@ -19,6 +19,7 @@
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
#include "SkinnedMesh.h"
|
#include "SkinnedMesh.h"
|
||||||
|
#include "SkinnedMeshResource.h"
|
||||||
#include "src/AnimGraph/AnimGraphEditor.h"
|
#include "src/AnimGraph/AnimGraphEditor.h"
|
||||||
|
|
||||||
const int Width = 1024;
|
const int Width = 1024;
|
||||||
|
@ -350,57 +351,11 @@ int main() {
|
||||||
sgldesc.sample_count = 0;
|
sgldesc.sample_count = 0;
|
||||||
sgl_setup(&sgldesc);
|
sgl_setup(&sgldesc);
|
||||||
|
|
||||||
// Animation setup
|
SkinnedMeshResource skinned_mesh_resource;
|
||||||
|
skinned_mesh_resource.loadFromFile("../media/SampleSkinnedMesh.json");
|
||||||
|
|
||||||
SkinnedMesh skinned_mesh;
|
SkinnedMesh skinned_mesh;
|
||||||
skinned_mesh.LoadSkeleton("../media/MixamoYBot-skeleton.ozz");
|
skinned_mesh_resource.createInstance(skinned_mesh);
|
||||||
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.SetCurrentAnimation(0);
|
skinned_mesh.SetCurrentAnimation(0);
|
||||||
|
|
||||||
|
@ -776,37 +731,6 @@ bool LoadAnimation(
|
||||||
return true;
|
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) {
|
static void draw_vec(const ozz::math::SimdFloat4& vec) {
|
||||||
sgl_v3f(ozz::math::GetX(vec), ozz::math::GetY(vec), ozz::math::GetZ(vec));
|
sgl_v3f(ozz::math::GetX(vec), ozz::math::GetY(vec), ozz::math::GetZ(vec));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue