Updated Model asset and rig loading

This commit is contained in:
Xiao Qi 2023-01-07 16:42:13 +08:00
parent 06b7db14d5
commit ab766d9304
6 changed files with 263 additions and 67 deletions

View File

@ -24,7 +24,6 @@ namespace SHADE
uint32_t indexCount; uint32_t indexCount;
uint32_t charCount; uint32_t charCount;
uint32_t boneCount; uint32_t boneCount;
std::string name;
}; };
struct MeshBoneInfo struct MeshBoneInfo
@ -48,7 +47,7 @@ namespace SHADE
struct SH_API SHMeshAsset : SHAssetData struct SH_API SHMeshAsset : SHAssetData
{ {
SHMeshDataHeader header; std::string name;
std::vector<SHVec3> VertexPositions; std::vector<SHVec3> VertexPositions;
std::vector<SHVec3> VertexTangents; std::vector<SHVec3> VertexTangents;
std::vector<SHVec3> VertexNormals; std::vector<SHVec3> VertexNormals;

View File

@ -29,9 +29,11 @@ namespace SHADE
struct SH_API SHModelAsset : SHAssetData struct SH_API SHModelAsset : SHAssetData
{ {
SHModelAssetHeader header; SHModelAssetHeader header;
SHRigAsset rig; SHRigAsset rig;
std::vector<SHMeshDataHeader> meshHeaders;
std::vector<SHAnimDataHeader> animHeaders;
std::vector<SHMeshAsset*> meshes; std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimAsset*> anims; std::vector<SHAnimAsset*> anims;
}; };

View File

@ -0,0 +1,26 @@
#include "SHpch.h"
#include "SHRigAsset.h"
#include <queue>
namespace SHADE
{
SHRigAsset::~SHRigAsset()
{
std::queue<SHRigNode*> nodeQueue;
nodeQueue.push(root);
while(!nodeQueue.empty())
{
auto curr = nodeQueue.front();
nodeQueue.pop();
for (auto child : curr->children)
{
nodeQueue.push(child);
}
delete curr;
}
}
}

View File

@ -17,32 +17,30 @@
namespace SHADE namespace SHADE
{ {
struct RigDataHeader struct SHRigDataHeader
{ {
uint32_t nodeCount; uint32_t nodeCount;
std::vector<uint32_t> charCounts; std::vector<uint32_t> charCounts;
}; };
struct RigNodeData struct SHRigNodeData
{ {
std::string name; std::string name;
SHMatrix transform; SHMatrix transform;
}; };
struct RigNode struct SHRigNode
{ {
uint32_t idRef; uint32_t idRef;
std::vector<RigNode*> children; std::vector<SHRigNode*> children;
}; };
struct SH_API SHRigAsset : SHAssetData struct SH_API SHRigAsset : SHAssetData
{ {
~SHRigAsset() ~SHRigAsset();
{
delete root;
}
std::map<uint32_t, RigNodeData> nodeDataCollection; SHRigDataHeader header;
RigNode* root; std::vector<SHRigNodeData> nodeDataCollection;
SHRigNode* root;
}; };
} }

View File

@ -13,42 +13,231 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHModelLoader.h" #include "SHModelLoader.h"
#include <fstream> #include <fstream>
#include <queue>
namespace SHADE namespace SHADE
{ {
void SHModelLoader::ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept void SHModelLoader::ReadHeaders(FileReference file, SHModelAsset& asset)
{ {
file.read( file.read(
reinterpret_cast<char*>(&header), reinterpret_cast<char*>(&asset.header),
sizeof(SHMeshLoaderHeader) sizeof(asset.header)
);
asset.meshHeaders.resize(asset.header.meshCount);
asset.animHeaders.resize(asset.header.animCount);
file.read(
reinterpret_cast<char*>(asset.meshHeaders.data()),
sizeof(asset.header.meshCount) * sizeof(SHMeshDataHeader)
);
file.read(
reinterpret_cast<char*>(asset.animHeaders.data()),
sizeof(asset.header.animCount) * sizeof(SHAnimDataHeader)
); );
} }
void SHModelLoader::ReadData(std::ifstream& file, SHMeshLoaderHeader const& header, SHMeshAsset& data) noexcept void SHModelLoader::ReadData(FileReference file, SHModelAsset& asset)
{ {
ReadMeshData(file, asset.meshHeaders, asset.meshes);
ReadAnimData(file, asset.animHeaders, asset.anims);
// Not eof yet, animation exists
if (file.peek() != EOF)
{
ReadRigHeader(file, asset.rig.header);
ReadRigData(file, asset.rig.header, asset.rig.nodeDataCollection);
ReadRigTree(file, asset.rig.header, asset.rig.root);
}
}
void SHModelLoader::ReadAnimNode(FileReference file, SHAnimNodeInfo const& info, SHAnimData& data)
{
file.read(
data.name.data(),
info.charCount
);
file.read(
reinterpret_cast<char*>(&data.pre),
sizeof(SHAnimationBehaviour)
);
file.read(
reinterpret_cast<char*>(&data.post),
sizeof(SHAnimationBehaviour)
);
uint32_t keySize {0};
file.read(
reinterpret_cast<char*>(&keySize),
sizeof(uint32_t)
);
data.positionKeys.resize(keySize);
data.rotationKeys.resize(keySize);
data.scaleKeys.resize(keySize);
file.read(
reinterpret_cast<char*>(data.positionKeys.data()),
sizeof(PositionKey) * keySize
);
file.read(
reinterpret_cast<char*>(data.rotationKeys.data()),
sizeof(RotationKey) * keySize
);
file.read(
reinterpret_cast<char*>(data.scaleKeys.data()),
sizeof(ScaleKey) * keySize
);
}
void SHModelLoader::ReadRigHeader(FileReference file, SHRigDataHeader& header)
{
file.read(
reinterpret_cast<char*>(&header.nodeCount),
sizeof(uint32_t)
);
header.charCounts.resize(header.nodeCount);
file.read(
reinterpret_cast<char*>(header.charCounts.data()),
sizeof(uint32_t) * header.nodeCount
);
}
void SHModelLoader::ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeData>& data)
{
data.resize(header.nodeCount);
for (auto i {0}; i < header.nodeCount; ++i)
{
data[i].name.resize(header.charCounts[i]);
file.read(
data[i].name.data(),
header.charCounts[i]
);
file.read(
reinterpret_cast<char*>(&data[i].transform),
sizeof(SHMatrix)
);
}
}
void SHModelLoader::ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNode* root)
{
// Read All nodes into one contiguous data block
struct NodeTemp
{
uint32_t id, numChild;
};
NodeTemp* dst = new NodeTemp[header.nodeCount];
file.read(
reinterpret_cast<char*>(dst),
sizeof(NodeTemp) * header.nodeCount
);
// Build and populate tree
SHRigNode* nodePool = new SHRigNode[header.nodeCount];
root = nodePool;
std::queue<std::pair<SHRigNode*, NodeTemp*>> nodeQueue;
nodeQueue.emplace(std::make_pair(nodePool, dst));
auto depthPtr = nodePool + 1;
auto depthTempPtr = dst + 1;
while(!nodeQueue.empty())
{
auto currPair = nodeQueue.front();
nodeQueue.pop();
auto currNode = currPair.first;
auto currTemp = currPair.second;
currNode->idRef = currTemp->id;
for (auto i{0}; i < currTemp->numChild; ++i)
{
currNode->children.push_back(depthPtr);
nodeQueue.emplace(depthPtr++, depthTempPtr++);
}
}
}
void SHModelLoader::ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers,
std::vector<SHMeshAsset*>& meshes)
{
meshes.resize(headers.size());
for (auto i {0}; i < headers.size(); ++i)
{
auto const& header = headers[i];
auto& data = *new SHMeshAsset;
auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount }; auto const vertexVec3Byte{ sizeof(SHVec3) * header.vertexCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount }; auto const vertexVec2Byte{ sizeof(SHVec2) * header.vertexCount };
data.name.resize(header.charCount);
data.VertexPositions.resize(header.vertexCount); data.VertexPositions.resize(header.vertexCount);
data.VertexTangents.resize(header.vertexCount); data.VertexTangents.resize(header.vertexCount);
data.VertexNormals.resize(header.vertexCount); data.VertexNormals.resize(header.vertexCount);
data.VertexTexCoords.resize(header.vertexCount); data.VertexTexCoords.resize(header.vertexCount);
data.Indices.resize(header.indexCount); data.Indices.resize(header.indexCount);
data.header.name.resize(header.charCount);
file.read(data.header.name.data(), header.charCount); file.read(data.name.data(), header.charCount);
file.read(reinterpret_cast<char*>(data.VertexPositions.data()), vertexVec3Byte); file.read(reinterpret_cast<char*>(data.VertexPositions.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTangents.data()), vertexVec3Byte); file.read(reinterpret_cast<char*>(data.VertexTangents.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexNormals.data()), vertexVec3Byte); file.read(reinterpret_cast<char*>(data.VertexNormals.data()), vertexVec3Byte);
file.read(reinterpret_cast<char*>(data.VertexTexCoords.data()), vertexVec2Byte); file.read(reinterpret_cast<char*>(data.VertexTexCoords.data()), vertexVec2Byte);
file.read(reinterpret_cast<char*>(data.Indices.data()), sizeof(uint32_t) * header.indexCount); file.read(reinterpret_cast<char*>(data.Indices.data()), sizeof(uint32_t) * header.indexCount);
data.header.vertexCount = header.vertexCount; meshes[i] = &data;
data.header.indexCount = header.indexCount; }
} }
void SHModelLoader::LoadSHMesh(AssetPath path, SHModelAsset& model) noexcept void SHModelLoader::ReadAnimData(FileReference file, std::vector<SHAnimDataHeader> const& headers,
std::vector<SHAnimAsset*>& anims)
{ {
anims.resize(headers.size());
for (auto i {0}; i < headers.size(); ++i)
{
auto const& header = headers[i];
auto& animAsset = *new SHAnimAsset;
file.read(
animAsset.name.data(),
header.charCount
);
file.read(
reinterpret_cast<char*>(&animAsset.duration),
sizeof(double)
);
file.read(
reinterpret_cast<char*>(&animAsset.ticksPerSecond),
sizeof(double)
);
animAsset.nodeChannels.resize(header.animNodeCount);
for (auto i {0}; i < header.animNodeCount; ++i)
{
ReadAnimNode(file, header.nodeHeaders[i], animAsset.nodeChannels[i]);
}
anims[i] = &animAsset;
}
}
SHAssetData* SHModelLoader::Load(AssetPath path)
{
auto result = new SHModelAsset();
std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open()) if (!file.is_open())
{ {
@ -58,29 +247,10 @@ namespace SHADE
file.seekg(0); file.seekg(0);
//TODO Update to new mesh header with anim count when animation saving is done ReadHeaders(file, *result);
file.read( ReadData(file, *result);
reinterpret_cast<char*>(&model.header.meshCount),
sizeof(model.header.meshCount)
);
std::vector<SHMeshLoaderHeader> headers(model.header.meshCount);
model.meshes.resize(model.header.meshCount);
for (auto i{ 0 }; i < model.header.meshCount; ++i)
{
model.meshes[i] = new SHMeshAsset();
ReadHeader(file, headers[i]);
ReadData(file, headers[i], *model.meshes[i]);
}
file.close(); file.close();
}
SHAssetData* SHModelLoader::Load(AssetPath path)
{
auto result = new SHModelAsset();
LoadSHMesh(path, *result);
return result; return result;
} }

View File

@ -18,19 +18,20 @@ namespace SHADE
{ {
class SHModelLoader : public SHAssetLoader class SHModelLoader : public SHAssetLoader
{ {
struct SHMeshLoaderHeader using FileReference = std::ifstream&;
{
uint32_t vertexCount;
uint32_t indexCount;
uint32_t charCount;
};
void ReadAnimNode(FileReference file, SHAnimNodeInfo const& info, SHAnimData& data);
void ReadHeader(std::ifstream& file, SHMeshLoaderHeader& header) noexcept; void ReadRigHeader(FileReference file, SHRigDataHeader& header);
void ReadData(std::ifstream& file, SHMeshLoaderHeader const& header, SHMeshAsset& data) noexcept; void ReadRigData(FileReference file, SHRigDataHeader const& header, std::vector<SHRigNodeData>& data);
void ReadRigTree(FileReference file, SHRigDataHeader const& header, SHRigNode* root);
void ReadMeshData(FileReference file, std::vector<SHMeshDataHeader> const& headers, std::vector<SHMeshAsset*>& meshes);
void ReadAnimData(FileReference file, std::vector<SHAnimDataHeader> const& headers, std::vector<SHAnimAsset*>& anims);
void ReadHeaders(FileReference file, SHModelAsset& asset);
void ReadData(FileReference file, SHModelAsset& asset);
public: public:
void LoadSHMesh(AssetPath path, SHModelAsset& model) noexcept;
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override; void Write(SHAssetData const* data, AssetPath path) override;
}; };