From 94af967fb1f0ab894662c0aa907936d578dc6114 Mon Sep 17 00:00:00 2001 From: Xiao Qi Date: Mon, 27 Feb 2023 21:57:24 +0800 Subject: [PATCH] Changed structure of model asset in mesh and animations. Data write for mesh and animations have been update. TODO: Reimplement data write for rig node data --- premake5.lua | 1 + src/Libraries/MeshCompiler.h | 8 +- src/Libraries/MeshCompiler.hpp | 113 +++++++++++++++++------ src/Libraries/MeshWriter.cpp | 164 +++++---------------------------- src/Libraries/MeshWriter.h | 6 +- src/PseudoMath.h | 5 + src/Types/AnimationAsset.h | 15 +-- src/Types/MeshAsset.h | 28 ++---- src/Types/RigAsset.h | 42 ++++----- 9 files changed, 151 insertions(+), 231 deletions(-) diff --git a/premake5.lua b/premake5.lua index d5ffe96..63d6629 100644 --- a/premake5.lua +++ b/premake5.lua @@ -23,6 +23,7 @@ project "ModelCompiler" { "%{prj.location}/src/**.h", "%{prj.location}/src/**.cpp", + "%{prj.location}/src/**.hpp" } externalincludedirs diff --git a/src/Libraries/MeshCompiler.h b/src/Libraries/MeshCompiler.h index 533e0b8..c00b87a 100644 --- a/src/Libraries/MeshCompiler.h +++ b/src/Libraries/MeshCompiler.h @@ -46,9 +46,9 @@ namespace SH_COMP static inline void LoadFromFile(AssetPath path, ModelRef asset) noexcept; - static inline void ProcessModel(ModelData const& model, ModelRef asset) noexcept; - static inline void ProcessAnimationChannels(ModelData const& model, ModelRef asset) noexcept; - static inline void ProcessNodes(ModelData const& model, ModelRef asset) noexcept; + static inline void ProcessMesh(ModelData const& data, ModelRef asset) noexcept; + static inline void ProcessAnimationChannels(ModelData const& data, ModelRef asset) noexcept; + static inline void ProcessRigNodes(ModelData const& data, ModelRef asset) noexcept; static inline void BuildHeaders(ModelRef asset) noexcept; @@ -58,7 +58,7 @@ namespace SH_COMP template static void FetchChannelKeyFrame(int targetNode, int inputAcc, int outputAcc, int nodeTarget, std::vector& dst); public: - static void LoadAndCompile(AssetPath path) noexcept; + static inline void LoadAndCompile(AssetPath path) noexcept; }; } diff --git a/src/Libraries/MeshCompiler.hpp b/src/Libraries/MeshCompiler.hpp index 9d42c47..5cf4427 100644 --- a/src/Libraries/MeshCompiler.hpp +++ b/src/Libraries/MeshCompiler.hpp @@ -56,22 +56,13 @@ namespace SH_COMP std::exit(1); } - ProcessModel(model, asset); + ProcessMesh(model, asset); ProcessAnimationChannels(model, asset); + ProcessRigNodes(model, asset); } - inline void MeshCompiler::ProcessModel(ModelData const& data, ModelRef asset) noexcept + inline void MeshCompiler::ProcessMesh(ModelData const& data, ModelRef asset) noexcept { -#if 0 - for (auto i {0}; i < 2; ++i) - { - auto& mesh{ asset.meshes.emplace_back() }; - mesh.vertexNormal.resize(3883); - mesh.vertexPosition.resize(3883); - mesh.vertexTangent.resize(3883); - mesh.texCoords.resize(3883); - } -#else accessors = &data.accessors; bufferViews = &data.bufferViews; buffer = data.buffers[0].data.data(); @@ -105,9 +96,31 @@ namespace SH_COMP { std::cout << "[Model Compiler] Failed to load critical data from gltf\n"; } - } -#endif + try + { + std::vectorweights; + std::vectorjoints; + FetchData(primitive.attributes.at(ATT_WEIGHTS.data()), weights); + FetchData(primitive.attributes.at(ATT_JOINT.data()), joints); + meshIn.weights.resize(weights.size()); + std::ranges::transform( + weights, + joints, + meshIn.weights.begin(), + [](SHVec4 const& weights, SHVec4i const& joints) ->VertexWeights + { + return { weights, joints }; + } + ); + + std::cout << "hi\n"; + } + catch(std::out_of_range e) + { + std::cout << "No weights and joints found for mesh: " << mesh.name << std::endl; + } + } } template @@ -147,8 +160,8 @@ namespace SH_COMP for (auto j{0}; j < componentCount; ++j) { std::memcpy( - dstPtr, - srcPtr, + dstCompPtr, + srcCompPtr, sizeIdentifier ); @@ -169,7 +182,7 @@ namespace SH_COMP static_assert(std::derived_from == true); std::vector inputVec; - std::vector outputVec; + std::vector outputVec; FetchData(inputAcc, inputVec); FetchData(outputAcc, outputVec); @@ -179,9 +192,9 @@ namespace SH_COMP inputVec, outputVec, dst.begin(), - [](float const& time, SHVec3 const& value)->T + [](float const& time, SHVec4 const& value)->T { - return { time, value }; + return { time, {value.x, value.y, value.z} }; } ); } @@ -199,11 +212,24 @@ namespace SH_COMP head.charCount = mesh.name.size(); head.indexCount = mesh.indices.size(); head.vertexCount = mesh.vertexPosition.size(); - head.boneCount = mesh.bonesInfo.size(); + head.hasWeights = mesh.weights.empty() ? false : true; + } + + // 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.nodes.size(); + head.frameCount = anim.nodes[0].positionKeys.size(); } } - void MeshCompiler::LoadAndCompile(AssetPath path) noexcept + inline void MeshCompiler::LoadAndCompile(AssetPath path) noexcept { auto const asset = new ModelAsset(); @@ -214,12 +240,12 @@ namespace SH_COMP delete asset; } - inline void MeshCompiler::ProcessAnimationChannels(ModelData const& model, ModelRef asset) noexcept + inline void MeshCompiler::ProcessAnimationChannels(ModelData const& data, ModelRef asset) noexcept { - asset.anims.resize(model.animations.size()); - for (auto i {0}; i < model.animations.size(); ++i) + asset.anims.resize(data.animations.size()); + for (auto i {0}; i < data.animations.size(); ++i) { - auto const& animData{ model.animations[i] }; + auto const& animData{ data.animations[i] }; auto& anim{ asset.anims[i] }; anim.name = animData.name; @@ -250,8 +276,43 @@ namespace SH_COMP } } - inline void MeshCompiler::ProcessNodes(ModelData const& model, ModelRef asset) noexcept + inline void MeshCompiler::ProcessRigNodes(ModelData const& data, ModelRef asset) noexcept { + if (asset.anims.empty()) + return; + for (auto const& node : data.nodes) + { + if ( + node.rotation.empty() && + node.translation.empty() && + node.translation.empty() + ) + continue; + + std::vector intermediate(node.children.begin(), node.children.end()); + + asset.rig.nodes.emplace_back( + node.name, + static_cast const&>(intermediate), + node.rotation, + node.translation, + node.matrix, + node.weights + ); + } + for (auto const& skin : data.skins) + { + std::vector inverseBindMatrices; + FetchData(skin.inverseBindMatrices, inverseBindMatrices); + + std::vector joints(skin.joints.begin(), skin.joints.end()); + auto& nodes{ asset.rig.nodes }; + auto matrix{ inverseBindMatrices.begin() }; + for (auto const& joint : joints) + { + nodes[joint].inverseBindMatrix = *(matrix++); + } + } } } diff --git a/src/Libraries/MeshWriter.cpp b/src/Libraries/MeshWriter.cpp index 094bdbe..e34840e 100644 --- a/src/Libraries/MeshWriter.cpp +++ b/src/Libraries/MeshWriter.cpp @@ -57,36 +57,19 @@ namespace SH_COMP sizeof(uint32_t) * header.indexCount ); - if (header.boneCount) - { + if (header.hasWeights) file.write( - reinterpret_cast(asset.bonesInfo.data()), - sizeof(MeshBoneInfo) * header.boneCount + reinterpret_cast(asset.weights.data()), + sizeof(VertexWeights) * header.vertexCount ); - - for (auto const& bone : asset.bones) - { - file.write( - bone.name.data(), - bone.name.size() - ); - - file.write( - reinterpret_cast(&bone.offset), - sizeof(SHMat4) - ); - - file.write( - reinterpret_cast(bone.weights.data()), - sizeof(BoneWeight) * bone.weights.size() - ); - } - } } } - void MeshWriter::WriteAnimData(FileReference file, std::vector const& headers, - std::vector const& anims) + void MeshWriter::WriteAnimData( + FileReference file, + std::vector const& headers, + std::vector const& anims + ) { for (auto i {0}; i < headers.size(); ++i) @@ -109,20 +92,15 @@ namespace SH_COMP sizeof(double) ); - for (auto i{0}; i < header.animNodeCount; ++i) - { - WriteAnimNode(file, header.nodeHeaders[i], data.nodes[i]); - } + for (auto const& node : data.nodes) + { + WriteAnimNode(file, node); + } } } - void MeshWriter::WriteAnimNode(FileReference file, AnimNodeInfo const& info, AnimNode const& node) + void MeshWriter::WriteAnimNode(FileReference file, AnimNode const& node) { - file.write( - node.name.data(), - info.charCount - ); - file.write( reinterpret_cast(&node.interpolation), sizeof(AnimationInterpolation) @@ -130,11 +108,6 @@ namespace SH_COMP uint32_t const keySize = node.positionKeys.size(); - file.write( - reinterpret_cast(&keySize), - sizeof(uint32_t) - ); - file.write( reinterpret_cast(node.positionKeys.data()), sizeof(PositionKey) * keySize @@ -154,9 +127,7 @@ namespace SH_COMP void MeshWriter::WriteRig(FileReference file, RigData const& data) { WriteRigHeader(file, data.header); - RigWriteNode* root {nullptr}; - WriteRigNodeData(file, data,root); - WriteRigTree(file, root); + WriteRigNodeData(file, data); } void MeshWriter::WriteRigHeader(FileReference file, RigDataHeader const& header) @@ -172,86 +143,9 @@ namespace SH_COMP ); } - void MeshWriter::WriteRigNodeData(FileReference file, RigData const& rig, RigWriteNode*& treeRoot) + void MeshWriter::WriteRigNodeData(FileReference file, RigData const& rig) { - // Build node collection and assign ID to each node BFS STYLE - // Build tree of nodes using ID - - std::vector dataToWrite; - dataToWrite.reserve(rig.header.nodeCount); - - std::stack> nodeStack; - treeRoot = new RigWriteNode; - treeRoot->id = 0; - treeRoot->children.clear(); - nodeStack.emplace(std::make_pair(treeRoot, rig.root)); - - while(!nodeStack.empty()) - { - auto currPair = nodeStack.top(); - nodeStack.pop(); - auto currWriteNode = currPair.first; - auto currDataNode = currPair.second; - - dataToWrite.emplace_back(currDataNode->name, currDataNode->transform, currDataNode->offset); - uint32_t idCounter = dataToWrite.size() + currDataNode->children.size() - 1; - - for (auto i{0}; i < currDataNode->children.size(); ++i) - { - auto child = currDataNode->children[i]; - auto newPair = std::make_pair(new RigWriteNode(), child); - - newPair.first->id = idCounter - i; - currWriteNode->children.push_back(newPair.first); - nodeStack.push(newPair); - } - - delete currDataNode; - } - - for (auto const& data : dataToWrite) - { - file.write(data.name.c_str(), data.name.size()); - file.write( - reinterpret_cast(&data.transform), - sizeof(SHMat4) - ); - file.write( - reinterpret_cast(&data.offset), - sizeof(SHMat4) - ); - } - } - - void MeshWriter::WriteRigTree(FileReference file, RigWriteNode const* root) - { - std::queue nodeQueue; - nodeQueue.push(root); - - int ctr = 0; - - while(!nodeQueue.empty()) - { - auto node = nodeQueue.front(); - nodeQueue.pop(); - - file.write( - reinterpret_cast(&node->id), - sizeof(uint32_t) - ); - - uint32_t size = static_cast(node->children.size()); - - file.write( - reinterpret_cast(&size), - sizeof(uint32_t) - ); - - for (auto child : node->children) - { - nodeQueue.push(child); - } - } + //TODO reimplement rig node data write } void MeshWriter::WriteHeaders(FileReference file, ModelConstRef asset) @@ -271,26 +165,10 @@ namespace SH_COMP if (asset.header.animCount > 0) { - for(auto const& animHeader : asset.animHeaders) - { - file.write( - reinterpret_cast(&animHeader.charCount), - sizeof(uint32_t) - ); - - file.write( - reinterpret_cast(&animHeader.animNodeCount), - sizeof(uint32_t) - ); - - for (auto const& nodeHeader : animHeader.nodeHeaders) - { - file.write( - reinterpret_cast(&nodeHeader), - sizeof(nodeHeader) - ); - } - } + file.write( + reinterpret_cast(asset.animHeaders.data()), + sizeof(AnimDataHeader) * asset.header.animCount + ); } } @@ -299,7 +177,7 @@ namespace SH_COMP WriteMeshData(file, asset.meshHeaders, asset.meshes); WriteAnimData(file, asset.animHeaders, asset.anims); - if (asset.rig.root) + if (!asset.rig.nodes.empty()) { WriteRig(file, asset.rig); } diff --git a/src/Libraries/MeshWriter.h b/src/Libraries/MeshWriter.h index 3cba904..87c57f5 100644 --- a/src/Libraries/MeshWriter.h +++ b/src/Libraries/MeshWriter.h @@ -22,13 +22,11 @@ namespace SH_COMP static void WriteMeshData(FileReference file, std::vector const& headers, std::vector const& meshes); static void WriteAnimData(FileReference file, std::vector const& headers, std::vector const& anims); - static void WriteAnimNode(FileReference file, AnimNodeInfo const& info, AnimNode const& node); + static void WriteAnimNode(FileReference file, AnimNode const& node); static void WriteRig(FileReference file, RigData const& data); static void WriteRigHeader(FileReference file, RigDataHeader const& header); - static void WriteRigNodeData(FileReference file, RigData const& rig, RigWriteNode*& treeRoot); - static void WriteRigTree(FileReference file, RigWriteNode const* root); - //static void WriteRigNodes(FileReference file, RigDataHeader const& header, RigNode const* root); + static void WriteRigNodeData(FileReference file, RigData const& rig); static void WriteHeaders(FileReference file, ModelConstRef asset); static void WriteData(FileReference file, ModelConstRef asset); diff --git a/src/PseudoMath.h b/src/PseudoMath.h index d3adc22..a0e17dd 100644 --- a/src/PseudoMath.h +++ b/src/PseudoMath.h @@ -18,6 +18,11 @@ namespace SH_COMP float x, y, z, w; }; + struct SHVec4i + { + uint32_t x, y, z, w; + }; + struct SHMat4 { float data[16]; diff --git a/src/Types/AnimationAsset.h b/src/Types/AnimationAsset.h index 255d555..fa89337 100644 --- a/src/Types/AnimationAsset.h +++ b/src/Types/AnimationAsset.h @@ -38,26 +38,16 @@ namespace SH_COMP struct ScaleKey :KeyBase {}; - // 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 nodeHeaders; + uint32_t frameCount; }; // Main data containers struct AnimNode { - std::string name; AnimationInterpolation interpolation; std::vector positionKeys; @@ -72,8 +62,7 @@ namespace SH_COMP double duration; double ticksPerSecond; + //One node represents the animation transforms for one bone in the rig std::vector nodes; - //std::vector meshChannels; - //std::vector morphMeshChannels; }; } \ No newline at end of file diff --git a/src/Types/MeshAsset.h b/src/Types/MeshAsset.h index 83735b4..c419f88 100644 --- a/src/Types/MeshAsset.h +++ b/src/Types/MeshAsset.h @@ -2,6 +2,7 @@ #include #include +#include #include "PseudoMath.h" @@ -12,37 +13,26 @@ namespace SH_COMP uint32_t vertexCount; uint32_t indexCount; uint32_t charCount; - uint32_t boneCount; + bool hasWeights; }; - struct MeshBoneInfo + struct VertexWeights { - uint32_t charCount; - uint32_t weightCount; - }; - - struct BoneWeight - { - uint32_t index; - float weight; - }; - - struct MeshBone - { - std::string name; - SHMat4 offset; - std::vector weights; + SHVec4 weights; + SHVec4i joints; }; struct MeshData { std::string name; + std::vector vertexPosition; std::vector vertexTangent; std::vector vertexNormal; std::vector texCoords; std::vector indices; - std::vector bonesInfo; - std::vector bones; + + //Variable data + std::vector weights; }; } \ No newline at end of file diff --git a/src/Types/RigAsset.h b/src/Types/RigAsset.h index 9f7a321..3dd7d75 100644 --- a/src/Types/RigAsset.h +++ b/src/Types/RigAsset.h @@ -8,40 +8,38 @@ namespace SH_COMP { + using NodeDataFlag = unsigned char; + + constexpr NodeDataFlag NODE_DATA_ROTATION = 0b00001; + constexpr NodeDataFlag NODE_DATA_SCALE = 0b00010; + constexpr NodeDataFlag NODE_DATA_TRANSLATION = 0b00100; + constexpr NodeDataFlag NODE_DATA_MATRIX = 0b01000; + constexpr NodeDataFlag NODE_DATA_WEIGHTS = 0b10000; + struct RigDataHeader { uint32_t nodeCount; std::vector charCounts; + std::vector childCount; + std::vector dataFlags; }; - struct RigNodeData - { - RigNodeData(const char* cstr, SHMat4 mat) - :name {cstr}, transform{mat} {} - - std::string name; - SHMat4 transform; - SHMat4 offset; - std::vector children; - }; - - struct RigNodeDataWrite + struct NodeAsset { std::string name; - SHMat4 transform; - SHMat4 offset; - }; - - struct RigWriteNode - { - uint32_t id; - std::vector children; + std::vector children; + std::vector + rotation, + scale, + translation, + matrix, + weights; + SHMat4 inverseBindMatrix; }; struct RigData { RigDataHeader header; - // std::map nodeDataCollection; - RigNodeData* root; + std::vector nodes; }; }