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
This commit is contained in:
Xiao Qi 2023-02-27 21:57:24 +08:00
parent d5ed571b64
commit 94af967fb1
9 changed files with 151 additions and 231 deletions

View File

@ -23,6 +23,7 @@ project "ModelCompiler"
{ {
"%{prj.location}/src/**.h", "%{prj.location}/src/**.h",
"%{prj.location}/src/**.cpp", "%{prj.location}/src/**.cpp",
"%{prj.location}/src/**.hpp"
} }
externalincludedirs externalincludedirs

View File

@ -46,9 +46,9 @@ namespace SH_COMP
static inline void LoadFromFile(AssetPath path, ModelRef asset) noexcept; static inline void LoadFromFile(AssetPath path, ModelRef asset) noexcept;
static inline void ProcessModel(ModelData const& model, ModelRef asset) noexcept; static inline void ProcessMesh(ModelData const& data, ModelRef asset) noexcept;
static inline void ProcessAnimationChannels(ModelData const& model, ModelRef asset) noexcept; static inline void ProcessAnimationChannels(ModelData const& data, ModelRef asset) noexcept;
static inline void ProcessNodes(ModelData const& model, ModelRef asset) noexcept; static inline void ProcessRigNodes(ModelData const& data, ModelRef asset) noexcept;
static inline void BuildHeaders(ModelRef asset) noexcept; static inline void BuildHeaders(ModelRef asset) noexcept;
@ -58,7 +58,7 @@ namespace SH_COMP
template<typename T> template<typename T>
static void FetchChannelKeyFrame(int targetNode, int inputAcc, int outputAcc, int nodeTarget, std::vector<T>& dst); static void FetchChannelKeyFrame(int targetNode, int inputAcc, int outputAcc, int nodeTarget, std::vector<T>& dst);
public: public:
static void LoadAndCompile(AssetPath path) noexcept; static inline void LoadAndCompile(AssetPath path) noexcept;
}; };
} }

View File

@ -56,22 +56,13 @@ namespace SH_COMP
std::exit(1); std::exit(1);
} }
ProcessModel(model, asset); ProcessMesh(model, asset);
ProcessAnimationChannels(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; accessors = &data.accessors;
bufferViews = &data.bufferViews; bufferViews = &data.bufferViews;
buffer = data.buffers[0].data.data(); 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"; std::cout << "[Model Compiler] Failed to load critical data from gltf\n";
} }
}
#endif
try
{
std::vector<SHVec4>weights;
std::vector<SHVec4i>joints;
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 <typename T> template <typename T>
@ -147,8 +160,8 @@ namespace SH_COMP
for (auto j{0}; j < componentCount; ++j) for (auto j{0}; j < componentCount; ++j)
{ {
std::memcpy( std::memcpy(
dstPtr, dstCompPtr,
srcPtr, srcCompPtr,
sizeIdentifier sizeIdentifier
); );
@ -169,7 +182,7 @@ namespace SH_COMP
static_assert(std::derived_from<T, KeyBase> == true); static_assert(std::derived_from<T, KeyBase> == true);
std::vector<float> inputVec; std::vector<float> inputVec;
std::vector<SHVec3> outputVec; std::vector<SHVec4> outputVec;
FetchData(inputAcc, inputVec); FetchData(inputAcc, inputVec);
FetchData(outputAcc, outputVec); FetchData(outputAcc, outputVec);
@ -179,9 +192,9 @@ namespace SH_COMP
inputVec, inputVec,
outputVec, outputVec,
dst.begin(), 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.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.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(); auto const asset = new ModelAsset();
@ -214,12 +240,12 @@ namespace SH_COMP
delete asset; 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()); asset.anims.resize(data.animations.size());
for (auto i {0}; i < model.animations.size(); ++i) 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] }; auto& anim{ asset.anims[i] };
anim.name = animData.name; 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<IndexType> intermediate(node.children.begin(), node.children.end());
asset.rig.nodes.emplace_back(
node.name,
static_cast<std::vector<IndexType> const&>(intermediate),
node.rotation,
node.translation,
node.matrix,
node.weights
);
}
for (auto const& skin : data.skins)
{
std::vector<SHMat4> inverseBindMatrices;
FetchData(skin.inverseBindMatrices, inverseBindMatrices);
std::vector<IndexType> 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++);
}
}
} }
} }

View File

@ -57,36 +57,19 @@ namespace SH_COMP
sizeof(uint32_t) * header.indexCount sizeof(uint32_t) * header.indexCount
); );
if (header.boneCount) if (header.hasWeights)
{
file.write( file.write(
reinterpret_cast<char const*>(asset.bonesInfo.data()), reinterpret_cast<char const*>(asset.weights.data()),
sizeof(MeshBoneInfo) * header.boneCount sizeof(VertexWeights) * header.vertexCount
); );
for (auto const& bone : asset.bones)
{
file.write(
bone.name.data(),
bone.name.size()
);
file.write(
reinterpret_cast<char const*>(&bone.offset),
sizeof(SHMat4)
);
file.write(
reinterpret_cast<char const*>(bone.weights.data()),
sizeof(BoneWeight) * bone.weights.size()
);
}
}
} }
} }
void MeshWriter::WriteAnimData(FileReference file, std::vector<AnimDataHeader> const& headers, void MeshWriter::WriteAnimData(
std::vector<AnimData> const& anims) FileReference file,
std::vector<AnimDataHeader> const& headers,
std::vector<AnimData> const& anims
)
{ {
for (auto i {0}; i < headers.size(); ++i) for (auto i {0}; i < headers.size(); ++i)
@ -109,20 +92,15 @@ namespace SH_COMP
sizeof(double) sizeof(double)
); );
for (auto i{0}; i < header.animNodeCount; ++i) for (auto const& node : data.nodes)
{ {
WriteAnimNode(file, header.nodeHeaders[i], data.nodes[i]); 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( file.write(
reinterpret_cast<char const*>(&node.interpolation), reinterpret_cast<char const*>(&node.interpolation),
sizeof(AnimationInterpolation) sizeof(AnimationInterpolation)
@ -130,11 +108,6 @@ namespace SH_COMP
uint32_t const keySize = node.positionKeys.size(); uint32_t const keySize = node.positionKeys.size();
file.write(
reinterpret_cast<char const*>(&keySize),
sizeof(uint32_t)
);
file.write( file.write(
reinterpret_cast<char const*>(node.positionKeys.data()), reinterpret_cast<char const*>(node.positionKeys.data()),
sizeof(PositionKey) * keySize sizeof(PositionKey) * keySize
@ -154,9 +127,7 @@ namespace SH_COMP
void MeshWriter::WriteRig(FileReference file, RigData const& data) void MeshWriter::WriteRig(FileReference file, RigData const& data)
{ {
WriteRigHeader(file, data.header); WriteRigHeader(file, data.header);
RigWriteNode* root {nullptr}; WriteRigNodeData(file, data);
WriteRigNodeData(file, data,root);
WriteRigTree(file, root);
} }
void MeshWriter::WriteRigHeader(FileReference file, RigDataHeader const& header) 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 //TODO reimplement rig node data write
// Build tree of nodes using ID
std::vector<RigNodeDataWrite> dataToWrite;
dataToWrite.reserve(rig.header.nodeCount);
std::stack<std::pair<RigWriteNode*, RigNodeData*>> 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<char const*>(&data.transform),
sizeof(SHMat4)
);
file.write(
reinterpret_cast<char const*>(&data.offset),
sizeof(SHMat4)
);
}
}
void MeshWriter::WriteRigTree(FileReference file, RigWriteNode const* root)
{
std::queue<RigWriteNode const*> nodeQueue;
nodeQueue.push(root);
int ctr = 0;
while(!nodeQueue.empty())
{
auto node = nodeQueue.front();
nodeQueue.pop();
file.write(
reinterpret_cast<char const*>(&node->id),
sizeof(uint32_t)
);
uint32_t size = static_cast<uint32_t>(node->children.size());
file.write(
reinterpret_cast<char const*>(&size),
sizeof(uint32_t)
);
for (auto child : node->children)
{
nodeQueue.push(child);
}
}
} }
void MeshWriter::WriteHeaders(FileReference file, ModelConstRef asset) void MeshWriter::WriteHeaders(FileReference file, ModelConstRef asset)
@ -271,26 +165,10 @@ namespace SH_COMP
if (asset.header.animCount > 0) if (asset.header.animCount > 0)
{ {
for(auto const& animHeader : asset.animHeaders) file.write(
{ reinterpret_cast<char const*>(asset.animHeaders.data()),
file.write( sizeof(AnimDataHeader) * asset.header.animCount
reinterpret_cast<char const*>(&animHeader.charCount), );
sizeof(uint32_t)
);
file.write(
reinterpret_cast<char const*>(&animHeader.animNodeCount),
sizeof(uint32_t)
);
for (auto const& nodeHeader : animHeader.nodeHeaders)
{
file.write(
reinterpret_cast<char const*>(&nodeHeader),
sizeof(nodeHeader)
);
}
}
} }
} }
@ -299,7 +177,7 @@ namespace SH_COMP
WriteMeshData(file, asset.meshHeaders, asset.meshes); WriteMeshData(file, asset.meshHeaders, asset.meshes);
WriteAnimData(file, asset.animHeaders, asset.anims); WriteAnimData(file, asset.animHeaders, asset.anims);
if (asset.rig.root) if (!asset.rig.nodes.empty())
{ {
WriteRig(file, asset.rig); WriteRig(file, asset.rig);
} }

View File

@ -22,13 +22,11 @@ namespace SH_COMP
static void WriteMeshData(FileReference file, std::vector<MeshDataHeader> const& headers, std::vector<MeshData> const& meshes); static void WriteMeshData(FileReference file, std::vector<MeshDataHeader> const& headers, std::vector<MeshData> const& meshes);
static void WriteAnimData(FileReference file, std::vector<AnimDataHeader> const& headers, std::vector<AnimData> const& anims); static void WriteAnimData(FileReference file, std::vector<AnimDataHeader> const& headers, std::vector<AnimData> 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 WriteRig(FileReference file, RigData const& data);
static void WriteRigHeader(FileReference file, RigDataHeader const& header); static void WriteRigHeader(FileReference file, RigDataHeader const& header);
static void WriteRigNodeData(FileReference file, RigData const& rig, RigWriteNode*& treeRoot); static void WriteRigNodeData(FileReference file, RigData const& rig);
static void WriteRigTree(FileReference file, RigWriteNode const* root);
//static void WriteRigNodes(FileReference file, RigDataHeader const& header, RigNode const* root);
static void WriteHeaders(FileReference file, ModelConstRef asset); static void WriteHeaders(FileReference file, ModelConstRef asset);
static void WriteData(FileReference file, ModelConstRef asset); static void WriteData(FileReference file, ModelConstRef asset);

View File

@ -18,6 +18,11 @@ namespace SH_COMP
float x, y, z, w; float x, y, z, w;
}; };
struct SHVec4i
{
uint32_t x, y, z, w;
};
struct SHMat4 struct SHMat4
{ {
float data[16]; float data[16];

View File

@ -38,26 +38,16 @@ namespace SH_COMP
struct ScaleKey :KeyBase {}; struct ScaleKey :KeyBase {};
// Headers for read/write
struct AnimNodeInfo
{
uint32_t charCount;
uint32_t posKeyCount;
uint32_t rotKeyCount;
uint32_t scaKeyCount;
};
struct AnimDataHeader struct AnimDataHeader
{ {
uint32_t charCount; uint32_t charCount;
uint32_t animNodeCount; uint32_t animNodeCount;
std::vector<AnimNodeInfo> nodeHeaders; uint32_t frameCount;
}; };
// Main data containers // Main data containers
struct AnimNode struct AnimNode
{ {
std::string name;
AnimationInterpolation interpolation; AnimationInterpolation interpolation;
std::vector<PositionKey> positionKeys; std::vector<PositionKey> positionKeys;
@ -72,8 +62,7 @@ namespace SH_COMP
double duration; double duration;
double ticksPerSecond; double ticksPerSecond;
//One node represents the animation transforms for one bone in the rig
std::vector<AnimNode> nodes; std::vector<AnimNode> nodes;
//std::vector<aiMeshAnim*> meshChannels;
//std::vector<aiMeshMorphAnim*> morphMeshChannels;
}; };
} }

View File

@ -2,6 +2,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <array>
#include "PseudoMath.h" #include "PseudoMath.h"
@ -12,37 +13,26 @@ namespace SH_COMP
uint32_t vertexCount; uint32_t vertexCount;
uint32_t indexCount; uint32_t indexCount;
uint32_t charCount; uint32_t charCount;
uint32_t boneCount; bool hasWeights;
}; };
struct MeshBoneInfo struct VertexWeights
{ {
uint32_t charCount; SHVec4 weights;
uint32_t weightCount; SHVec4i joints;
};
struct BoneWeight
{
uint32_t index;
float weight;
};
struct MeshBone
{
std::string name;
SHMat4 offset;
std::vector<BoneWeight> weights;
}; };
struct MeshData struct MeshData
{ {
std::string name; std::string name;
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<IndexType> indices; std::vector<IndexType> indices;
std::vector<MeshBoneInfo> bonesInfo;
std::vector<MeshBone> bones; //Variable data
std::vector<VertexWeights> weights;
}; };
} }

View File

@ -8,40 +8,38 @@
namespace SH_COMP 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 struct RigDataHeader
{ {
uint32_t nodeCount; uint32_t nodeCount;
std::vector<uint32_t> charCounts; std::vector<uint32_t> charCounts;
std::vector<uint32_t> childCount;
std::vector<NodeDataFlag> dataFlags;
}; };
struct RigNodeData struct NodeAsset
{
RigNodeData(const char* cstr, SHMat4 mat)
:name {cstr}, transform{mat} {}
std::string name;
SHMat4 transform;
SHMat4 offset;
std::vector<RigNodeData*> children;
};
struct RigNodeDataWrite
{ {
std::string name; std::string name;
SHMat4 transform; std::vector<IndexType> children;
SHMat4 offset; std::vector<double>
}; rotation,
scale,
struct RigWriteNode translation,
{ matrix,
uint32_t id; weights;
std::vector<RigWriteNode*> children; SHMat4 inverseBindMatrix;
}; };
struct RigData struct RigData
{ {
RigDataHeader header; RigDataHeader header;
// std::map<uint32_t, RigNodeData> nodeDataCollection; std::vector<NodeAsset> nodes;
RigNodeData* root;
}; };
} }