Changed structure for program, segregated asset types structs

This commit is contained in:
Xiao Qi 2022-11-19 23:02:59 +08:00
parent 456167e9f0
commit c5f7b22515
11 changed files with 3308 additions and 5223 deletions

2
.gitignore vendored
View File

@ -358,3 +358,5 @@ Premake/
*.sln *.sln
Dependencies/ Dependencies/
*.shmodel

3009
Raccoon.gltf Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -11,12 +11,13 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#include "MeshCompiler.h" #include "MeshCompiler.h"
#include "MeshWriter.h"
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <queue> #include <stack>
namespace SH_COMP namespace SH_COMP
{ {
@ -26,23 +27,20 @@ namespace SH_COMP
void MeshCompiler::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes, RigData& rig) noexcept void MeshCompiler::ProcessNode(aiNode const& node, aiScene const& scene, MeshVectorRef meshes, RigData& rig) noexcept
{ {
for (size_t i{ 0 }; i < node.mNumMeshes; ++i) for (auto i{0}; i < node.mNumChildren; ++i)
{ {
aiMesh* mesh = scene.mMeshes[node.mMeshes[i]]; auto const& child {*node.mChildren[i]};
meshes.emplace_back();
GetMesh(*mesh, meshes.back());
meshes.back().name = node.mName.C_Str();
}
if (std::strcmp(node.mName.C_Str(), "Armature") == 0) if (child.mNumMeshes > 0)
{
BuildArmature(node, rig.root);
}
else
{
for (size_t i{ 0 }; i < node.mNumChildren; ++i)
{ {
ProcessNode(*node.mChildren[i], scene, meshes, rig); aiMesh* mesh = scene.mMeshes[child.mMeshes[0]];
meshes.emplace_back();
GetMesh(*mesh, meshes.back());
meshes.back().name = child.mName.C_Str();
}
else
{
BuildArmature(child, rig);
} }
} }
} }
@ -167,150 +165,18 @@ namespace SH_COMP
} }
} }
void MeshCompiler::WriteMeshHeader(std::ofstream& file, MeshDataHeader const& header) uint32_t MeshCompiler::RegisterNewNode(aiNode const& node, RigData& rig) noexcept
{ {
file.write( auto const result = rigNodeIDCounter++;
reinterpret_cast<char const*>(&header),
sizeof(MeshDataHeader)
);
}
void MeshCompiler::WriteMeshData(std::ofstream& file, MeshDataHeader const& header, MeshData const& asset) rig.nodeDataCollection[result].name = node.mName.C_Str();
{ std::memcpy(
auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount }; &rig.nodeDataCollection[result].transform,
auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount }; &node.mTransformation,
sizeof(SHMat4)
file.write(
asset.name.c_str(),
header.charCount
); );
file.write( return result;
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.write(
reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * header.indexCount
);
}
void MeshCompiler::WriteAnimHeader(FileReference file, AnimDataHeader const& header)
{
auto constexpr intSize = sizeof(uint32_t);
file.write(
reinterpret_cast<char const*>(&header.charCount),
intSize
);
file.write(
reinterpret_cast<char const*>(&header.animNodeCount),
intSize
);
file.write(
reinterpret_cast<char const*>(header.nodeHeaders.data()),
sizeof(AnimNodeInfo) * header.nodeHeaders.size()
);
}
void MeshCompiler::WriteAnimData(FileReference file, AnimDataHeader const& header, AnimData const& data)
{
file.write(
data.name.data(),
header.charCount
);
file.write(
reinterpret_cast<char const*>(&data.duration),
sizeof(double)
);
file.write(
reinterpret_cast<char const*>(&data.ticksPerSecond),
sizeof(double)
);
for (auto i{0}; i < header.animNodeCount; ++i)
{
WriteAnimNode(file, header.nodeHeaders[i], data.nodeChannels[i]);
}
}
void MeshCompiler::WriteAnimNode(FileReference file, AnimNodeInfo const& info, AnimNode const& node)
{
file.write(
node.name.data(),
info.charCount
);
file.write(
reinterpret_cast<char const*>(&node.pre),
sizeof(AnimationBehaviour)
);
file.write(
reinterpret_cast<char const*>(&node.post),
sizeof(AnimationBehaviour)
);
file.write(
reinterpret_cast<char const*>(node.positionKeys.data()),
sizeof(PositionKey) * node.positionKeys.size()
);
file.write(
reinterpret_cast<char const*>(node.rotationKeys.data()),
sizeof(RotationKey) * node.rotationKeys.size()
);
file.write(
reinterpret_cast<char const*>(node.scaleKeys.data()),
sizeof(ScaleKey) * node.scaleKeys.size()
);
}
void MeshCompiler::WriteHeaders(FileReference file, ModelConstRef asset)
{
for (auto const& header : asset.meshHeaders)
{
WriteMeshHeader(file, header);
}
for (auto const& header : asset.animHeaders)
{
WriteAnimHeader(file, header);
}
}
void MeshCompiler::WriteData(FileReference file, ModelConstRef asset)
{
for (auto i {0}; i < asset.meshes.size(); ++i)
{
WriteMeshData(file, asset.meshHeaders[i], asset.meshes[i]);
}
for (auto i {0}; i < asset.anims.size(); ++i)
{
WriteAnimData(file, asset.animHeaders[i], asset.anims[i]);
}
} }
void MeshCompiler::ParseAnimations(aiScene const& scene, std::vector<AnimData>& anims) noexcept void MeshCompiler::ParseAnimations(aiScene const& scene, std::vector<AnimData>& anims) noexcept
@ -352,27 +218,27 @@ namespace SH_COMP
node.rotationKeys.resize(channelData.mNumRotationKeys); node.rotationKeys.resize(channelData.mNumRotationKeys);
for (auto k{0}; k < channelData.mNumRotationKeys; ++k) for (auto k{0}; k < channelData.mNumRotationKeys; ++k)
{ {
auto const& posKeyData = channelData.mRotationKeys[k]; auto const& rotKeyData = channelData.mRotationKeys[k];
auto& posKey = node.rotationKeys[k]; auto& rotKey = node.rotationKeys[k];
posKey.time = posKeyData.mTime; rotKey.time = rotKeyData.mTime;
posKey.value.x = posKeyData.mValue.x; rotKey.value.x = rotKeyData.mValue.x;
posKey.value.y = posKeyData.mValue.y; rotKey.value.y = rotKeyData.mValue.y;
posKey.value.z = posKeyData.mValue.z; rotKey.value.z = rotKeyData.mValue.z;
posKey.value.w = posKeyData.mValue.w; rotKey.value.w = rotKeyData.mValue.w;
} }
// Scale Keys // Scale Keys
node.scaleKeys.resize(channelData.mNumScalingKeys); node.scaleKeys.resize(channelData.mNumScalingKeys);
for (auto k{0}; k < channelData.mNumScalingKeys; ++k) for (auto k{0}; k < channelData.mNumScalingKeys; ++k)
{ {
auto const& posKeyData = channelData.mScalingKeys[k]; auto const& scaKeyData = channelData.mScalingKeys[k];
auto& posKey = node.scaleKeys[k]; auto& scaKey = node.scaleKeys[k];
posKey.time = posKeyData.mTime; scaKey.time = scaKeyData.mTime;
posKey.value.x = posKeyData.mValue.x; scaKey.value.x = scaKeyData.mValue.x;
posKey.value.y = posKeyData.mValue.y; scaKey.value.y = scaKeyData.mValue.y;
posKey.value.z = posKeyData.mValue.z; scaKey.value.z = scaKeyData.mValue.z;
} }
} }
} }
@ -380,16 +246,17 @@ namespace SH_COMP
void MeshCompiler::LoadFromFile(AssetPath path, ModelAsset& asset) noexcept void MeshCompiler::LoadFromFile(AssetPath path, ModelAsset& asset) noexcept
{ {
const aiScene* scene = aiImporter.ReadFile(path.string().c_str(), const aiScene* scene = aiImporter.ReadFile(path.string().c_str(),0
aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons //aiProcess_Triangulate // Make sure we get triangles rather than nvert polygons
| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping //| aiProcess_GenUVCoords // Convert any type of mapping to uv mapping
| aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...) //| aiProcess_TransformUVCoords // preprocess UV transformations (scaling, translation ...)
| aiProcess_FindInstances // search for instanced meshes and remove them by references to one master //| aiProcess_FindInstances // search for instanced meshes and remove them by references to one master
| aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible //| aiProcess_CalcTangentSpace // calculate tangents and bitangents if possible
| aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing //| aiProcess_JoinIdenticalVertices // join identical vertices/ optimize indexing
| aiProcess_FindInvalidData // detect invalid model data, such as invalid normal vectors //| 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_FlipUVs // flip the V to match the Vulkans way of doing UVs
| aiProcess_ValidateDataStructure //| aiProcess_ValidateDataStructure // checks all bones, animations and vertices are linked correctly
//| aiProcess_LimitBoneWeights // Limit number of bones effect vertices to 4
); );
if (!scene || !scene->HasMeshes()) if (!scene || !scene->HasMeshes())
@ -398,46 +265,36 @@ namespace SH_COMP
return; return;
} }
ParseAnimations(*scene, asset.anims);
ProcessNode(*scene->mRootNode, *scene, asset.meshes, asset.rig); ProcessNode(*scene->mRootNode, *scene, asset.meshes, asset.rig);
ParseAnimations(*scene, asset.anims);
aiImporter.FreeScene(); 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)
);
WriteHeaders(file, asset);
WriteData(file, asset);
file.close();
}
void MeshCompiler::BuildArmature(aiNode const& baseNode, RigData& rig) noexcept void MeshCompiler::BuildArmature(aiNode const& baseNode, RigData& rig) noexcept
{ {
std::queue<aiNode const*> nodesQueue; std::stack<std::pair<RigNode*, aiNode const*>> nodesQueue;
nodesQueue.push(&baseNode); rig.root = new RigNode();
rig.root->idRef = RegisterNewNode(**baseNode.mChildren, rig);
RigNode* parent = nullptr; nodesQueue.push({rig.root, *baseNode.mChildren});
while(!nodesQueue.empty()) while(!nodesQueue.empty())
{ {
auto& rigNode { *nodesQueue.top().first };
auto const& dataNode { *nodesQueue.top().second };
nodesQueue.pop();
for (auto i{ 0 }; i < dataNode.mNumChildren; ++i)
{
rigNode.children.push_back(new RigNode());
rigNode.children[i]->idRef = RegisterNewNode(*dataNode.mChildren[i], rig);
nodesQueue.push({
rigNode.children[i],
dataNode.mChildren[i]
});
}
} }
} }
@ -447,7 +304,7 @@ namespace SH_COMP
LoadFromFile(path, *asset); LoadFromFile(path, *asset);
BuildHeaders(*asset); BuildHeaders(*asset);
CompileMeshBinary(path, *asset); MeshWriter::CompileMeshBinary(path, *asset);
delete asset; delete asset;
} }

View File

@ -1,5 +1,5 @@
/*************************************************************************//** /*************************************************************************//**
* \file SHMeshCompiler.h * \file MeshCompiler.h
* \author Loh Xiao Qi * \author Loh Xiao Qi
* \date 30 September 2022 * \date 30 September 2022
* \brief Library to write data in MeshAsset into binary file for faster * \brief Library to write data in MeshAsset into binary file for faster
@ -28,8 +28,6 @@ namespace SH_COMP
using MeshVectorRef = std::vector<MeshData>&; using MeshVectorRef = std::vector<MeshData>&;
using AnimVectorRef = std::vector<AnimData>&; using AnimVectorRef = std::vector<AnimData>&;
using FileReference = std::ofstream&;
using ModelConstRef = ModelAsset const&;
using ModelRef = ModelAsset&; using ModelRef = ModelAsset&;
static Assimp::Importer aiImporter; static Assimp::Importer aiImporter;
@ -39,22 +37,12 @@ namespace SH_COMP
static void GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept; static void GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept;
static void BuildHeaders(ModelRef asset) noexcept; static void BuildHeaders(ModelRef asset) noexcept;
static void WriteMeshHeader(FileReference file, MeshDataHeader const& header); static void BuildArmature(aiNode const& node, RigData& rig) noexcept;
static void WriteMeshData(FileReference file, MeshDataHeader const& header, MeshData const& asset); static uint32_t RegisterNewNode(aiNode const& node, RigData& rig) noexcept;
static void WriteAnimHeader(FileReference file, AnimDataHeader const& header);
static void WriteAnimData(FileReference file, AnimDataHeader const& header, AnimData const& data);
static void WriteAnimNode(FileReference file, AnimNodeInfo const& info, AnimNode const& node);
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, RigData& rig) noexcept;
static void ParseAnimations(aiScene const& scene, std::vector<AnimData>& anims) noexcept; static void ParseAnimations(aiScene const& scene, std::vector<AnimData>& anims) noexcept;
static void LoadFromFile(AssetPath path, ModelRef asset) noexcept;
public: public:
static void LoadAndCompile(AssetPath path) noexcept; static void LoadAndCompile(AssetPath path) noexcept;
}; };

View File

@ -0,0 +1,187 @@
/******************************************************************************
* \file MeshWriter.cpp
* \author Loh Xiao Qi
* \date 19 November 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#include "MeshWriter.h"
#include <fstream>
#include <iostream>
namespace SH_COMP
{
void MeshWriter::WriteMeshHeader(std::ofstream& file, MeshDataHeader const& header)
{
file.write(
reinterpret_cast<char const*>(&header),
sizeof(MeshDataHeader)
);
}
void MeshWriter::WriteMeshData(std::ofstream& file, MeshDataHeader const& header, MeshData const& asset)
{
auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount };
file.write(
asset.name.c_str(),
header.charCount
);
file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.write(
reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * header.indexCount
);
}
void MeshWriter::WriteAnimHeader(FileReference file, AnimDataHeader const& header)
{
auto constexpr intSize = sizeof(uint32_t);
file.write(
reinterpret_cast<char const*>(&header.charCount),
intSize
);
file.write(
reinterpret_cast<char const*>(&header.animNodeCount),
intSize
);
file.write(
reinterpret_cast<char const*>(header.nodeHeaders.data()),
sizeof(AnimNodeInfo) * header.nodeHeaders.size()
);
}
void MeshWriter::WriteAnimData(FileReference file, AnimDataHeader const& header, AnimData const& data)
{
file.write(
data.name.data(),
header.charCount
);
file.write(
reinterpret_cast<char const*>(&data.duration),
sizeof(double)
);
file.write(
reinterpret_cast<char const*>(&data.ticksPerSecond),
sizeof(double)
);
for (auto i{0}; i < header.animNodeCount; ++i)
{
WriteAnimNode(file, header.nodeHeaders[i], data.nodeChannels[i]);
}
}
void MeshWriter::WriteAnimNode(FileReference file, AnimNodeInfo const& info, AnimNode const& node)
{
file.write(
node.name.data(),
info.charCount
);
file.write(
reinterpret_cast<char const*>(&node.pre),
sizeof(AnimationBehaviour)
);
file.write(
reinterpret_cast<char const*>(&node.post),
sizeof(AnimationBehaviour)
);
file.write(
reinterpret_cast<char const*>(node.positionKeys.data()),
sizeof(PositionKey) * node.positionKeys.size()
);
file.write(
reinterpret_cast<char const*>(node.rotationKeys.data()),
sizeof(RotationKey) * node.rotationKeys.size()
);
file.write(
reinterpret_cast<char const*>(node.scaleKeys.data()),
sizeof(ScaleKey) * node.scaleKeys.size()
);
}
void MeshWriter::WriteHeaders(FileReference file, ModelConstRef asset)
{
for (auto const& header : asset.meshHeaders)
{
WriteMeshHeader(file, header);
}
for (auto const& header : asset.animHeaders)
{
WriteAnimHeader(file, header);
}
}
void MeshWriter::WriteData(FileReference file, ModelConstRef asset)
{
for (auto i {0}; i < asset.meshes.size(); ++i)
{
WriteMeshData(file, asset.meshHeaders[i], asset.meshes[i]);
}
for (auto i {0}; i < asset.anims.size(); ++i)
{
WriteAnimData(file, asset.animHeaders[i], asset.anims[i]);
}
}
void MeshWriter::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)
);
WriteHeaders(file, asset);
WriteData(file, asset);
file.close();
}
}

View File

@ -0,0 +1,35 @@
/******************************************************************************
* \file MeshWriter.h
* \author Loh Xiao Qi
* \date 19 November 2022
* \brief
*
* \copyright Copyright (c) 2021 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include "AssetMacros.h"
#include "Types/ModelAsset.h"
namespace SH_COMP
{
struct MeshWriter
{
using FileReference = std::ofstream&;
using ModelConstRef = ModelAsset const&;
static void WriteMeshHeader(FileReference file, MeshDataHeader const& header);
static void WriteMeshData(FileReference file, MeshDataHeader const& header, MeshData const& asset);
static void WriteAnimHeader(FileReference file, AnimDataHeader const& header);
static void WriteAnimData(FileReference file, AnimDataHeader const& header, AnimData const& data);
static void WriteAnimNode(FileReference file, AnimNodeInfo const& info, AnimNode const& node);
static void WriteHeaders(FileReference file, ModelConstRef asset);
static void WriteData(FileReference file, ModelConstRef asset);
static void CompileMeshBinary(AssetPath path, ModelConstRef asset) noexcept;
};
}

View File

@ -19,7 +19,7 @@ namespace SH_COMP
enum class AnimationBehaviour : uint8_t enum class AnimationBehaviour : uint8_t
{ {
DEFAULT = 0x0, DEFAULT = 0x0,
CONSTNAT = 0x1, CONSTANT = 0x1,
LINEAR = 0x2, LINEAR = 0x2,
REPEAT = 0x3 REPEAT = 0x3
}; };

View File

@ -23,12 +23,12 @@ namespace SH_COMP
struct RigNode struct RigNode
{ {
uint32_t idRef; uint32_t idRef;
std::vector<uint32_t> children; std::vector<RigNode*> children;
}; };
struct RigData struct RigData
{ {
std::map<uint32_t, RigNodeData> nodeDataCollection; std::map<uint32_t, RigNodeData> nodeDataCollection;
RigNode root; RigNode* root;
}; };
} }

View File

@ -53,7 +53,7 @@ int main(int argc, char* argv[])
// SH_COMP::MeshCompiler::LoadAndCompile(path); // SH_COMP::MeshCompiler::LoadAndCompile(path);
//} //}
SH_COMP::MeshCompiler::LoadAndCompile("Racoon.fbx"); SH_COMP::MeshCompiler::LoadAndCompile("Raccoon.gltf");
return 0; return 0;
} }