Parse and build all animation data and headers for write

Added functions for writing animation headers and data [NOT YET IMPLEMENTED]
This commit is contained in:
Xiao Qi 2022-11-16 17:28:55 +08:00
parent 03c17ca5d4
commit 7cc7c51fd9
4 changed files with 189 additions and 90 deletions

View File

@ -148,17 +148,42 @@ namespace SH_COMP
void MeshCompiler::BuildHeaders(ModelAsset& asset) noexcept void MeshCompiler::BuildHeaders(ModelAsset& asset) noexcept
{ {
for (auto const& mesh : asset.meshes) // Mesh Headers
asset.meshHeaders.resize(asset.meshes.size());
asset.header.meshCount = asset.meshes.size();
for (auto i{0}; i < asset.header.meshCount; ++i)
{ {
asset.headers.emplace_back(); auto const& mesh = asset.meshes[i];
auto& head = asset.headers.back(); auto& head = asset.meshHeaders[i];
head.charCount = mesh.name.size(); head.charCount = mesh.name.size();
head.indexCount = mesh.indices.size(); head.indexCount = mesh.indices.size();
head.vertexCount = mesh.vertexPosition.size(); head.vertexCount = mesh.vertexPosition.size();
head.boneCount = mesh.bonesInfo.size(); head.boneCount = mesh.bonesInfo.size();
}
asset.header.meshCount++; // Anim Headers
asset.animHeaders.resize(asset.anims.size());
asset.header.animCount = asset.anims.size();
for (auto i{0}; i < asset.header.animCount; ++i)
{
auto const& anim = asset.anims[i];
auto& head = asset.animHeaders[i];
head.charCount = anim.name.size();
head.animNodeCount = anim.nodeChannels.size();
head.nodeHeaders.resize(head.animNodeCount);
for (auto j{0}; i < head.animNodeCount; ++j)
{
auto const& animNode = anim.nodeChannels[j];
auto& nodeHeader = head.nodeHeaders[j];
nodeHeader.charCount = animNode.name.size();
nodeHeader.posKeyCount = animNode.positionKeys.size();
nodeHeader.rotKeyCount = animNode.rotationKeys.size();
nodeHeader.scaKeyCount = animNode.scaleKeys.size();
}
} }
} }
@ -206,89 +231,25 @@ namespace SH_COMP
); );
} }
void MeshCompiler::LoadFromFile(AssetPath path, ModelAsset& asset) noexcept void MeshCompiler::WriteAnimHeader(FileReference file, AnimDataHeader const& header)
{ {
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping
| aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...)
| aiProcess_FindInstances // search for instanced meshes and remove them by references to one master
| aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible
| aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
| aiProcess_ValidateDataStructure
);
if (!scene || !scene->HasMeshes())
{
std::cout << "ERROR in GLTF::ASSIMP: " << aiImporter.GetErrorString() << "\nFile: " << path.string() << std::endl;
return;
}
std::vector<AnimationAsset> anims;
ParseAnimations(*scene, anims);
ProcessNode(*scene->mRootNode, *scene, asset.meshes, asset.rig.root);
aiImporter.FreeScene();
} }
void MeshCompiler::CompileMeshBinary(AssetPath path, ModelAsset const& asset) noexcept void MeshCompiler::WriteAnimData(FileReference file, AnimDataHeader const& header, AnimData& data)
{ {
std::string newPath{ path.string().substr(0, path.string().find_last_of('.')) };
newPath += MODEL_EXTENSION;
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
{
std::cout << "Unable to open file for write: " << newPath << std::endl;
return;
}
file.write(
reinterpret_cast<char const*>(&asset.header),
sizeof(asset.header)
);
for (auto i {0}; i < asset.headers.size(); ++i)
{
WriteMeshHeader(file, asset.headers[i]);
WriteMeshData(file, asset.headers[i], asset.meshes[i]);
}
file.close();
} }
void MeshCompiler::BuildArmature(aiNode const& baseNode, RigNode*& root) noexcept void MeshCompiler::WriteHeaders(FileReference file, ModelConstRef asset)
{ {
RigNode* start = new RigNode();
CopyNode(baseNode, start);
root = start->children[0];
} }
void MeshCompiler::CopyNode(aiNode const& source, RigNode* parent) noexcept void MeshCompiler::WriteData(FileReference file, ModelConstRef asset)
{ {
RigNode* current = new RigNode();
current->name = source.mName.C_Str();
std::memcpy(&current->transform, &source.mTransformation, sizeof(SHMat4));
for (auto i {0}; i < source.mNumChildren; ++i)
{
CopyNode(*source.mChildren[i], current);
}
if (parent)
{
parent->children.push_back(current);
}
} }
void MeshCompiler::ParseAnimations(aiScene const& scene, std::vector<AnimationAsset>& anims) noexcept void MeshCompiler::ParseAnimations(aiScene const& scene, std::vector<AnimData>& anims) noexcept
{ {
// Size and read for number of animation clips // Size and read for number of animation clips
anims.resize(scene.mNumAnimations); anims.resize(scene.mNumAnimations);
for (auto i {0}; i < scene.mNumAnimations; ++i) for (auto i {0}; i < scene.mNumAnimations; ++i)
@ -352,6 +313,86 @@ namespace SH_COMP
} }
} }
void MeshCompiler::LoadFromFile(AssetPath path, ModelAsset& asset) noexcept
{
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping
| aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...)
| aiProcess_FindInstances // search for instanced meshes and remove them by references to one master
| aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible
| aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
| aiProcess_ValidateDataStructure
);
if (!scene || !scene->HasMeshes())
{
std::cout << "ERROR in GLTF::ASSIMP: " << aiImporter.GetErrorString() << "\nFile: " << path.string() << std::endl;
return;
}
ParseAnimations(*scene, asset.anims);
ProcessNode(*scene->mRootNode, *scene, asset.meshes, asset.rig.root);
aiImporter.FreeScene();
}
void MeshCompiler::CompileMeshBinary(AssetPath path, ModelAsset const& asset) noexcept
{
std::string newPath{ path.string().substr(0, path.string().find_last_of('.')) };
newPath += MODEL_EXTENSION;
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
{
std::cout << "Unable to open file for write: " << newPath << std::endl;
return;
}
file.write(
reinterpret_cast<char const*>(&asset.header),
sizeof(asset.header)
);
// Write Meshes
for (auto i {0}; i < asset.meshHeaders.size(); ++i)
{
WriteMeshHeader(file, asset.meshHeaders[i]);
WriteMeshData(file, asset.meshHeaders[i], asset.meshes[i]);
}
file.close();
}
void MeshCompiler::BuildArmature(aiNode const& baseNode, RigNode*& root) noexcept
{
RigNode* start = new RigNode();
CopyNode(baseNode, start);
root = start->children[0];
}
void MeshCompiler::CopyNode(aiNode const& source, RigNode* parent) noexcept
{
RigNode* current = new RigNode();
current->name = source.mName.C_Str();
std::memcpy(&current->transform, &source.mTransformation, sizeof(SHMat4));
for (auto i {0}; i < source.mNumChildren; ++i)
{
CopyNode(*source.mChildren[i], current);
}
if (parent)
{
parent->children.push_back(current);
}
}
void MeshCompiler::LoadAndCompile(AssetPath path) noexcept void MeshCompiler::LoadAndCompile(AssetPath path) noexcept
{ {
auto const asset = new ModelAsset(); auto const asset = new ModelAsset();

View File

@ -26,25 +26,35 @@ namespace SH_COMP
{ {
using MeshVectorRef = std::vector<MeshData>&; using MeshVectorRef = std::vector<MeshData>&;
using AnimVectorRef = std::vector<AnimationAsset>&; using AnimVectorRef = std::vector<AnimData>&;
using FileReference = std::ofstream&;
using ModelConstRef = ModelAsset const&;
using ModelRef = ModelAsset&;
static Assimp::Importer aiImporter; static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes, RigNode*& root) noexcept; static void ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes, RigNode*& root) noexcept;
//static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept; //static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept;
static void GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept; static void GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept;
static void BuildHeaders(ModelAsset& asset) noexcept; static void BuildHeaders(ModelRef asset) noexcept;
static void WriteMeshHeader(std::ofstream& file, MeshDataHeader const& header); static void WriteMeshHeader(FileReference file, MeshDataHeader const& header);
static void WriteMeshData(std::ofstream& file, MeshDataHeader const& header, MeshData const& asset); static void WriteMeshData(FileReference file, MeshDataHeader const& header, MeshData const& asset);
static void LoadFromFile(AssetPath path, ModelAsset& asset) noexcept; static void WriteAnimHeader(FileReference file, AnimDataHeader const& header);
static void CompileMeshBinary(AssetPath path, ModelAsset const& asset) noexcept; static void WriteAnimData(FileReference file, AnimDataHeader const& header, AnimData cosnt& data);
static void WriteHeaders(FileReference file, ModelConstRef asset);
static void WriteData(FileReference file, ModelConstRef asset);
static void LoadFromFile(AssetPath path, ModelRef asset) noexcept;
static void CompileMeshBinary(AssetPath path, ModelConstRef asset) noexcept;
static void BuildArmature(aiNode const& node, RigNode*& root) noexcept; static void BuildArmature(aiNode const& node, RigNode*& root) noexcept;
static void CopyNode(aiNode const& source, RigNode* parent) noexcept; static void CopyNode(aiNode const& source, RigNode* parent) noexcept;
static void ParseAnimations(aiScene const& scene, std::vector<AnimationAsset>& anims) noexcept; static void ParseAnimations(aiScene const& scene, std::vector<AnimData>& anims) noexcept;
public: public:
static void LoadAndCompile(AssetPath path) noexcept; static void LoadAndCompile(AssetPath path) noexcept;
}; };

View File

@ -16,24 +16,66 @@
namespace SH_COMP namespace SH_COMP
{ {
struct AnimationKey enum class AnimationBehaviour : uint8_t
{
DEFAULT = 0x0,
CONSTNAT = 0x1,
LINEAR = 0x2,
REPEAT = 0x3
};
// Smallest data containers
struct PositionKey
{
float time;
SHVec3 value;
};
struct RotationKey
{ {
float time; float time;
SHVec4 value; SHVec4 value;
}; };
struct AnimationNode
struct ScaleKey
{ {
std::string name; float time;
std::vector<AnimationKey> positionKeys; SHVec3 value;
std::vector<AnimationKey> rotationKeys;
std::vector<AnimationKey> scaleKeys;
}; };
struct AnimationAsset // Headers for read/write
struct AnimNodeInfo
{
uint32_t charCount;
uint32_t posKeyCount;
uint32_t rotKeyCount;
uint32_t scaKeyCount;
};
struct AnimDataHeader
{
uint32_t charCount;
uint32_t animNodeCount;
std::vector<AnimNodeInfo> nodeHeaders;
};
// Main data containers
struct AnimNode
{
std::string name;
std::vector<PositionKey> positionKeys;
std::vector<RotationKey> rotationKeys;
std::vector<ScaleKey> scaleKeys;
AnimationBehaviour pre;
AnimationBehaviour post;
};
struct AnimData
{ {
std::string name; std::string name;
std::vector<AnimationNode> nodeChannels; std::vector<AnimNode> nodeChannels;
//std::vector<aiMeshAnim*> meshChannels; //std::vector<aiMeshAnim*> meshChannels;
//std::vector<aiMeshMorphAnim*> morphMeshChannels; //std::vector<aiMeshMorphAnim*> morphMeshChannels;

View File

@ -16,6 +16,7 @@
#include <string> #include <string>
#include "MeshAsset.h" #include "MeshAsset.h"
#include "AnimationAsset.h"
namespace SH_COMP namespace SH_COMP
{ {
@ -35,13 +36,18 @@ namespace SH_COMP
struct ModelAssetHeader struct ModelAssetHeader
{ {
size_t meshCount; size_t meshCount;
size_t animCount;
}; };
struct ModelAsset struct ModelAsset
{ {
ModelAssetHeader header; ModelAssetHeader header;
RigData rig; RigData rig;
std::vector<MeshDataHeader> headers;
std::vector<MeshDataHeader> meshHeaders;
std::vector<AnimDataHeader> animHeaders;
std::vector<MeshData> meshes; std::vector<MeshData> meshes;
std::vector<AnimData> anims;
}; };
} }