Rewrote comping to write all meshes into one file instead of multiple files for meshes

This commit is contained in:
Xiao Qi 2022-11-01 20:09:27 +08:00
parent d194ca68fe
commit 48c3ed823b
8 changed files with 141 additions and 104 deletions

2
.gitignore vendored
View File

@ -356,3 +356,5 @@ MigrationBackup/
Premake/ Premake/
*.sln *.sln
Dependencies/

View File

@ -9,13 +9,6 @@ project "ModelCompileLibrary"
systemversion "latest" systemversion "latest"
configurations
{
"Debug",
"Release",
"Publish"
}
files files
{ {
"%{prj.location}/src/**.h", "%{prj.location}/src/**.h",

View File

@ -1,8 +1,8 @@
/*************************************************************************//** /*************************************************************************//**
* \file SHMeshCompiler.cpp * \file MeshCompiler.cpp
* \author Loh Xiao Qi * \author Loh Xiao Qi
* \date 30 September 2022 * \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster * \brief Library to write data in MeshAsset into binary file for faster
* loading in the future * loading in the future
* *
* *
@ -10,23 +10,24 @@
* disclosure of this file or its contents without the prior written consent * disclosure of this file or its contents without the prior written consent
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#include "SHMeshCompiler.h" #include "MeshCompiler.h"
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
namespace SHADE namespace SH_COMP
{ {
Assimp::Importer SHMeshCompiler::aiImporter; Assimp::Importer MeshCompiler::aiImporter;
void SHMeshCompiler::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept void MeshCompiler::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept
{ {
for (size_t i{ 0 }; i < node.mNumMeshes; ++i) for (size_t i{ 0 }; i < node.mNumMeshes; ++i)
{ {
aiMesh* mesh = scene.mMeshes[node.mMeshes[i]]; aiMesh* mesh = scene.mMeshes[node.mMeshes[i]];
meshes.push_back(ProcessMesh(*mesh)); meshes.emplace_back();
GetMesh(*mesh, meshes.back());
} }
for (size_t i{ 0 }; i < node.mNumChildren; ++i) for (size_t i{ 0 }; i < node.mNumChildren; ++i)
@ -35,11 +36,11 @@ namespace SHADE
} }
} }
void SHMeshCompiler::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept void MeshCompiler::ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept
{ {
if (scene.HasAnimations()) if (scene.HasAnimations())
{ {
std::vector<SHAnimationAsset> anims(scene.mNumAnimations); std::vector<AnimationAsset> anims(scene.mNumAnimations);
for (auto i{ 0 }; i < scene.mNumAnimations; ++i) for (auto i{ 0 }; i < scene.mNumAnimations; ++i)
{ {
auto const& anim{ *scene.mAnimations[i] }; auto const& anim{ *scene.mAnimations[i] };
@ -56,11 +57,12 @@ namespace SHADE
} }
} }
SHMeshAsset* SHMeshCompiler::ProcessMesh(aiMesh const& mesh) noexcept void MeshCompiler::GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept
{ {
SHMeshAsset* result = new SHMeshAsset(); meshData.vertexPosition.reserve(mesh.mNumVertices);
result->compiled = false; meshData.vertexNormal.reserve(mesh.mNumVertices);
result->changed = false; meshData.vertexTangent.reserve(mesh.mNumVertices);
meshData.texCoords.reserve(mesh.mNumVertices);
for (size_t i{ 0 }; i < mesh.mNumVertices; ++i) for (size_t i{ 0 }; i < mesh.mNumVertices; ++i)
{ {
@ -69,7 +71,7 @@ namespace SHADE
vertex.x = mesh.mVertices[i].x; vertex.x = mesh.mVertices[i].x;
vertex.y = mesh.mVertices[i].y; vertex.y = mesh.mVertices[i].y;
vertex.z = mesh.mVertices[i].z; vertex.z = mesh.mVertices[i].z;
result->vertexPosition.push_back(vertex); meshData.vertexPosition.push_back(vertex);
// Tex coords // Tex coords
SHVec2 texCoord{ 0.f, 0.f }; SHVec2 texCoord{ 0.f, 0.f };
@ -78,7 +80,7 @@ namespace SHADE
texCoord.x = mesh.mTextureCoords[0][i].x; texCoord.x = mesh.mTextureCoords[0][i].x;
texCoord.y = mesh.mTextureCoords[0][i].y; texCoord.y = mesh.mTextureCoords[0][i].y;
} }
result->texCoords.push_back(texCoord); meshData.texCoords.push_back(texCoord);
// Normals // Normals
SHVec3 normal{ 0.f, 0.f, 0.f }; SHVec3 normal{ 0.f, 0.f, 0.f };
@ -88,7 +90,7 @@ namespace SHADE
normal.y = mesh.mNormals[i].y; normal.y = mesh.mNormals[i].y;
normal.z = mesh.mNormals[i].z; normal.z = mesh.mNormals[i].z;
} }
result->vertexNormal.push_back(normal); meshData.vertexNormal.push_back(normal);
// Tangent // Tangent
SHVec3 tangent{ 0.f, 0.f, 0.f }; SHVec3 tangent{ 0.f, 0.f, 0.f };
@ -98,7 +100,7 @@ namespace SHADE
tangent.y = mesh.mTangents[i].y; tangent.y = mesh.mTangents[i].y;
tangent.z = mesh.mTangents[i].z; tangent.z = mesh.mTangents[i].z;
} }
result->vertexTangent.push_back(tangent); meshData.vertexTangent.push_back(tangent);
} }
for (size_t i{ 0 }; i < mesh.mNumFaces; ++i) for (size_t i{ 0 }; i < mesh.mNumFaces; ++i)
@ -106,68 +108,46 @@ namespace SHADE
aiFace face = mesh.mFaces[i]; aiFace face = mesh.mFaces[i];
for (size_t j{ 0 }; j < face.mNumIndices; ++j) for (size_t j{ 0 }; j < face.mNumIndices; ++j)
{ {
result->indices.push_back(face.mIndices[j]); meshData.indices.push_back(face.mIndices[j]);
} }
} }
result->header.vertexCount = static_cast<uint32_t>(result->vertexPosition.size()); meshData.name = mesh.mName.C_Str();
result->header.indexCount = static_cast<uint32_t>(result->indices.size());
result->header.name = mesh.mName.C_Str();
return result;
} }
void SHMeshCompiler::LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept void MeshCompiler::BuildHeaders(MeshAsset& asset) noexcept
{ {
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(), for (auto const& mesh : asset.meshes)
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_RemoveRedundantMaterials // remove redundant materials
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
);
if (!scene || !scene->HasMeshes())
{ {
std::cout << "ERROR in GLTF::ASSIMP: " << aiImporter.GetErrorString() << "\nFile: " << path.string() << std::endl; asset.headers.emplace_back();
return; auto& head = asset.headers.back();
head.charCount = mesh.name.size();
head.indexCount = mesh.indices.size();
head.vertexCount = mesh.vertexPosition.size();
asset.header.meshCount++;
} }
//ExtractAnimations(*scene, anims);
ProcessNode(*scene->mRootNode, *scene, meshes);
aiImporter.FreeScene();
} }
std::optional<AssetPath> SHMeshCompiler::CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept void MeshCompiler::WriteMeshHeader(std::ofstream& file, MeshDataHeader const& header)
{ {
std::string newPath{ path.string() + asset.header.name + MESH_EXTENSION.data() }; file.write(
reinterpret_cast<char const*>(&header),
sizeof(MeshDataHeader)
);
}
std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc }; void MeshCompiler::WriteMeshData(std::ofstream& file, MeshDataHeader const& header, MeshData const& asset)
if (!file.is_open()) {
{ auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount };
std::cout << "Unable to open file for write: " << newPath << std::endl; auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount };
return {};
}
file.write( file.write(
reinterpret_cast<char const*>(&(asset.header.vertexCount)), asset.name.c_str(),
sizeof(uint32_t) header.charCount
); );
file.write(
reinterpret_cast<const char*>(&(asset.header.indexCount)),
sizeof(uint32_t)
);
auto const vertexVec3Byte{ sizeof(SHVec3) * asset.header.vertexCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * asset.header.vertexCount };
file.write( file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()), reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte vertexVec3Byte
@ -190,24 +170,71 @@ namespace SHADE
file.write( file.write(
reinterpret_cast<char const*>(asset.indices.data()), reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * asset.header.indexCount sizeof(uint32_t) * header.indexCount
);
}
void MeshCompiler::LoadFromFile(AssetPath path, MeshAsset& 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_RemoveRedundantMaterials // remove redundant materials
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
); );
file.close(); if (!scene || !scene->HasMeshes())
{
std::cout << "ERROR in GLTF::ASSIMP: " << aiImporter.GetErrorString() << "\nFile: " << path.string() << std::endl;
return;
}
return newPath; //ExtractAnimations(*scene, anims);
ProcessNode(*scene->mRootNode, *scene, asset.meshes);
aiImporter.FreeScene();
} }
void SHMeshCompiler::LoadAndCompile(AssetPath path) noexcept void MeshCompiler::CompileMeshBinary(AssetPath path, MeshAsset const& asset) noexcept
{ {
std::vector<SHMeshAsset*> meshes; std::string newPath{ path.string().substr(0, path.string().find_last_of('.')) };
std::vector<SHAnimationAsset*> anims; newPath += MESH_EXTENSION;
LoadFromFile(path, meshes, anims); std::ofstream file{ newPath, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
for (auto const& mesh : meshes)
{ {
CompileMeshBinary(*mesh, path.parent_path().string() + '/'); 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::LoadAndCompile(AssetPath path) noexcept
{
auto const asset = new MeshAsset();
LoadFromFile(path, *asset);
BuildHeaders(*asset);
CompileMeshBinary(path, *asset);
delete asset;
} }
} }

View File

@ -2,7 +2,7 @@
* \file SHMeshCompiler.h * \file SHMeshCompiler.h
* \author Loh Xiao Qi * \author Loh Xiao Qi
* \date 30 September 2022 * \date 30 September 2022
* \brief Library to write data in SHMeshAsset into binary file for faster * \brief Library to write data in MeshAsset into binary file for faster
* loading in the future * loading in the future
* *
* *
@ -16,24 +16,30 @@
#include <assimp/scene.h> #include <assimp/scene.h>
#include <vector> #include <vector>
#include "Types/SHAnimationAsset.h" #include "Types/AnimationAsset.h"
#include "Types/SHMeshAsset.h" #include "Types/MeshAsset.h"
#include "SHAssetMacros.h" #include "AssetMacros.h"
namespace SHADE namespace SH_COMP
{ {
class SHMeshCompiler class MeshCompiler
{ {
using MeshVectorRef = std::vector<SHMeshAsset*>&; using MeshVectorRef = std::vector<MeshData>&;
using AnimVectorRef = std::vector<SHAnimationAsset*>&; using AnimVectorRef = std::vector<AnimationAsset>&;
static Assimp::Importer aiImporter; static Assimp::Importer aiImporter;
static void ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept; static void ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes) noexcept;
static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept; static void ExtractAnimations(aiScene const& scene, AnimVectorRef anims) noexcept;
static SHMeshAsset* ProcessMesh(aiMesh const& mesh) noexcept; static void GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept;
static void LoadFromFile(AssetPath path, MeshVectorRef meshes, AnimVectorRef anims) noexcept; static void BuildHeaders(MeshAsset& asset) noexcept;
static std::optional<AssetPath> CompileMeshBinary(SHMeshAsset const& asset, AssetPath path) noexcept;
static void WriteMeshHeader(std::ofstream& file, MeshDataHeader const& header);
static void WriteMeshData(std::ofstream& file, MeshDataHeader const& header, MeshData const& data);
static void LoadFromFile(AssetPath path, MeshAsset& asset) noexcept;
static void CompileMeshBinary(AssetPath path, MeshAsset const& asset) noexcept;
public: public:
static void LoadAndCompile(AssetPath path) noexcept; static void LoadAndCompile(AssetPath path) noexcept;

View File

@ -13,9 +13,9 @@
#include <vector> #include <vector>
#include <assimp/anim.h> #include <assimp/anim.h>
namespace SHADE namespace SH_COMP
{ {
struct SHAnimationAsset struct AnimationAsset
{ {
std::string name; std::string name;

View File

@ -13,8 +13,9 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <string>
namespace SHADE namespace SH_COMP
{ {
struct SHVec2 struct SHVec2
@ -27,24 +28,32 @@ namespace SHADE
float x, y, z; float x, y, z;
}; };
struct SHMeshAssetHeader struct MeshDataHeader
{ {
uint32_t vertexCount; uint32_t vertexCount;
uint32_t indexCount; uint32_t indexCount;
std::string name; uint32_t charCount;
}; };
struct SHMeshAsset struct MeshData
{ {
bool compiled; std::string name;
bool changed;
SHMeshAssetHeader header;
std::vector<SHVec3> vertexPosition; std::vector<SHVec3> vertexPosition;
std::vector<SHVec3> vertexTangent; std::vector<SHVec3> vertexTangent;
std::vector<SHVec3> vertexNormal; std::vector<SHVec3> vertexNormal;
std::vector<SHVec2> texCoords; std::vector<SHVec2> texCoords;
std::vector<uint32_t> indices; std::vector<uint32_t> indices;
}; };
struct MeshAssetHeader
{
size_t meshCount;
};
struct MeshAsset
{
MeshAssetHeader header;
std::vector<MeshDataHeader> headers;
std::vector<MeshData> meshes;
};
} }

View File

@ -8,7 +8,7 @@
* or disclosure of this file or its contents without the prior * or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited. * written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/ ******************************************************************************/
#include "Libraries/SHMeshCompiler.h" #include "Libraries/MeshCompiler.h"
#include <vector> #include <vector>
#include <filesystem> #include <filesystem>