commit
8efa4ab395
|
@ -1,2 +1,2 @@
|
||||||
rmdir "Dependencies/assimp" /S /Q
|
rmdir "Dependencies/tinygltf" /S /Q
|
||||||
git clone https://github.com/SHADE-DP/assimp.git "Dependencies/assimp"
|
git clone https://github.com/XiaoQiDigipen/tinygltf.git "Dependencies/tinygltf"
|
46
premake5.lua
46
premake5.lua
|
@ -1,5 +1,3 @@
|
||||||
AssimpInclude = "%{prj.location}\\Dependencies\\assimp"
|
|
||||||
|
|
||||||
outputdir = "%{wks.location}/bin/%{cfg.buildcfg}"
|
outputdir = "%{wks.location}/bin/%{cfg.buildcfg}"
|
||||||
interdir = "%{wks.location}/bin_int"
|
interdir = "%{wks.location}/bin_int"
|
||||||
workspace "ModelCompile"
|
workspace "ModelCompile"
|
||||||
|
@ -22,62 +20,40 @@ project "ModelCompiler"
|
||||||
{
|
{
|
||||||
"%{prj.location}/src/**.h",
|
"%{prj.location}/src/**.h",
|
||||||
"%{prj.location}/src/**.cpp",
|
"%{prj.location}/src/**.cpp",
|
||||||
}
|
"%{prj.location}/src/**.hpp"
|
||||||
|
|
||||||
externalincludedirs
|
|
||||||
{
|
|
||||||
"%{AssimpInclude}\\include"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
includedirs
|
includedirs
|
||||||
{
|
{
|
||||||
"%{prj.location}/src",
|
"%{prj.location}/src"
|
||||||
}
|
}
|
||||||
|
|
||||||
externalwarnings "Off"
|
externalwarnings "Off"
|
||||||
|
|
||||||
libdirs
|
|
||||||
{
|
|
||||||
"%{AssimpInclude}/lib/Debug",
|
|
||||||
"%{AssimpInclude}/lib/Release"
|
|
||||||
}
|
|
||||||
|
|
||||||
flags
|
flags
|
||||||
{
|
{
|
||||||
"MultiProcessorCompile"
|
"MultiProcessorCompile"
|
||||||
}
|
}
|
||||||
|
|
||||||
filter "configurations:Debug"
|
|
||||||
postbuildcommands
|
|
||||||
{
|
|
||||||
"xcopy /r /y /q \"%{AssimpInclude}\\bin\\Debug\\assimp-vc142-mtd.dll\" \"$(OutDir)\""
|
|
||||||
}
|
|
||||||
|
|
||||||
filter "configurations:Release"
|
|
||||||
postbuildcommands
|
|
||||||
{
|
|
||||||
"xcopy /r /y /q \"%{AssimpInclude}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\""
|
|
||||||
}
|
|
||||||
|
|
||||||
filter "configurations:Publish"
|
|
||||||
postbuildcommands
|
|
||||||
{
|
|
||||||
"xcopy /r /y /q \"%{AssimpInclude}\\bin\\Release\\assimp-vc142-mt.dll\" \"$(OutDir)\""
|
|
||||||
}
|
|
||||||
|
|
||||||
warnings 'Extra'
|
warnings 'Extra'
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"TINYGLTF_IMPLEMENTATION",
|
||||||
|
"TINYGLTF_NO_EXTERNAL_IMAGE",
|
||||||
|
"TINYGLTF_NO_INCLUDE_STB_IMAGE",
|
||||||
|
"TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE",
|
||||||
|
"TINYGLTF_NO_STB_IMAGE_WRITE",
|
||||||
|
"TINYGLTF_NO_STB_IMAGE"
|
||||||
|
}
|
||||||
|
|
||||||
filter "configurations:Debug"
|
filter "configurations:Debug"
|
||||||
symbols "On"
|
symbols "On"
|
||||||
defines {"_DEBUG"}
|
defines {"_DEBUG"}
|
||||||
links{"assimp-vc142-mtd.lib"}
|
|
||||||
|
|
||||||
filter "configurations:Release"
|
filter "configurations:Release"
|
||||||
optimize "On"
|
optimize "On"
|
||||||
defines{"_RELEASE"}
|
defines{"_RELEASE"}
|
||||||
links{"assimp-vc142-mt.lib"}
|
|
||||||
|
|
||||||
filter "configurations:Publish"
|
filter "configurations:Publish"
|
||||||
optimize "On"
|
optimize "On"
|
||||||
defines{"_RELEASE, _PUBLISH"}
|
defines{"_RELEASE, _PUBLISH"}
|
||||||
links{"assimp-vc142-mt.lib"}
|
|
|
@ -14,6 +14,96 @@
|
||||||
// Typedefs
|
// Typedefs
|
||||||
typedef std::filesystem::path AssetPath;
|
typedef std::filesystem::path AssetPath;
|
||||||
|
|
||||||
|
enum class BUFFER_TARGET : int
|
||||||
|
{
|
||||||
|
ARRAY_BUFFER = 34962,
|
||||||
|
ELEMENT_ARRAY_BUFFER = 34963
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ACCESSOR_COMPONENT_TYPE : int
|
||||||
|
{
|
||||||
|
BYTE = 5120,
|
||||||
|
U_BYTE = 5121,
|
||||||
|
SHORT = 5122,
|
||||||
|
U_SHORT = 5123,
|
||||||
|
U_INT = 5125,
|
||||||
|
FLOAT = 5126
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr size_t SizeOfType(ACCESSOR_COMPONENT_TYPE type)
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case ACCESSOR_COMPONENT_TYPE::BYTE:
|
||||||
|
case ACCESSOR_COMPONENT_TYPE::U_BYTE:
|
||||||
|
return sizeof(char);
|
||||||
|
case ACCESSOR_COMPONENT_TYPE::SHORT:
|
||||||
|
case ACCESSOR_COMPONENT_TYPE::U_SHORT:
|
||||||
|
return sizeof(short);
|
||||||
|
case ACCESSOR_COMPONENT_TYPE::U_INT:
|
||||||
|
case ACCESSOR_COMPONENT_TYPE::FLOAT:
|
||||||
|
return sizeof(float);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ACCESSOR_DATA_TYPE : int
|
||||||
|
{
|
||||||
|
SCALAR = 64 + 1,
|
||||||
|
VEC2 = 2,
|
||||||
|
VEC3 = 3,
|
||||||
|
VEC4 = 4,
|
||||||
|
MAT2 = 32 + 2,
|
||||||
|
MAT3 = 32 + 3,
|
||||||
|
MAT4 = 32 + 4,
|
||||||
|
VECTOR = 64 + 4,
|
||||||
|
MATRIX = 64 + 16
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr size_t CountOfType(ACCESSOR_DATA_TYPE type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ACCESSOR_DATA_TYPE::SCALAR:
|
||||||
|
return 1;
|
||||||
|
case ACCESSOR_DATA_TYPE::VEC2:
|
||||||
|
return 2;
|
||||||
|
case ACCESSOR_DATA_TYPE::VEC3:
|
||||||
|
return 3;
|
||||||
|
case ACCESSOR_DATA_TYPE::VEC4:
|
||||||
|
return 4;
|
||||||
|
case ACCESSOR_DATA_TYPE::MAT2:
|
||||||
|
return 2 * 2;
|
||||||
|
case ACCESSOR_DATA_TYPE::MAT3:
|
||||||
|
return 3 * 3;
|
||||||
|
case ACCESSOR_DATA_TYPE::MAT4:
|
||||||
|
return 4 * 4;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PRIMITIVE_MODE : int
|
||||||
|
{
|
||||||
|
POINT = 0,
|
||||||
|
LINE = 1,
|
||||||
|
LINE_LOOP = 2,
|
||||||
|
LINE_STRIP = 3,
|
||||||
|
TRIANGLE = 4,
|
||||||
|
TRIANGLE_STRIP = 5,
|
||||||
|
TRIANLE_FAN = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::string_view TRANSLATION_PATH{ "translation" };
|
||||||
|
constexpr std::string_view SCALE_PATH{ "scale" };
|
||||||
|
constexpr std::string_view ROTATION_PATH{ "rotation" };
|
||||||
|
constexpr std::string_view WEIGHTS_PATH{ "weights" };
|
||||||
|
|
||||||
|
constexpr std::string_view LINEAR_INTERPOLATION{ "LINEAR" };
|
||||||
|
constexpr std::string_view STEP_INTERPOLATION{ "STEP" };
|
||||||
|
constexpr std::string_view CUBICSPLINE_INTERPOLATION{ "CUBICSPLINE" };
|
||||||
|
|
||||||
//Directory
|
//Directory
|
||||||
#ifdef _PUBLISH
|
#ifdef _PUBLISH
|
||||||
constexpr std::string_view ASSET_ROOT{ "Assets" };
|
constexpr std::string_view ASSET_ROOT{ "Assets" };
|
||||||
|
@ -30,6 +120,18 @@ constexpr std::string_view MODEL_EXTENSION {".shmodel"};
|
||||||
constexpr std::string_view FBX_EXTENSION{ ".fbx" };
|
constexpr std::string_view FBX_EXTENSION{ ".fbx" };
|
||||||
constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
|
constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
|
||||||
|
|
||||||
|
// ATTRIBUTE NAMES
|
||||||
|
// BASIC NEEDED
|
||||||
|
constexpr std::string_view ATT_POSITION {"POSITION"};
|
||||||
|
constexpr std::string_view ATT_NORMAL { "NORMAL" };
|
||||||
|
constexpr std::string_view ATT_TANGENT { "TANGENT" };
|
||||||
|
constexpr std::string_view ATT_TEXCOORD { "TEXCOORD_0" };
|
||||||
|
|
||||||
|
// VARIABLE ATTRIBUTES
|
||||||
|
constexpr std::string_view ATT_WEIGHTS { "WEIGHTS_0" };
|
||||||
|
constexpr std::string_view ATT_JOINT{ "JOINTS_0" };
|
||||||
|
constexpr std::string_view ATT_COLOUR{ "COLOR_0" };
|
||||||
|
|
||||||
constexpr std::string_view EXTERNALS[] = {
|
constexpr std::string_view EXTERNALS[] = {
|
||||||
FBX_EXTENSION,
|
FBX_EXTENSION,
|
||||||
GLTF_EXTENSION
|
GLTF_EXTENSION
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,358 +0,0 @@
|
||||||
/*************************************************************************//**
|
|
||||||
* \file MeshCompiler.cpp
|
|
||||||
* \author Loh Xiao Qi
|
|
||||||
* \date 30 September 2022
|
|
||||||
* \brief Library to write data in MeshAsset into binary file for faster
|
|
||||||
* loading in the future
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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 "MeshCompiler.h"
|
|
||||||
#include "MeshWriter.h"
|
|
||||||
#include <assimp/postprocess.h>
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <stack>
|
|
||||||
|
|
||||||
namespace SH_COMP
|
|
||||||
{
|
|
||||||
|
|
||||||
SHMat4 aiTransformToMat4(aiMatrix4x4 const& inMatrx)
|
|
||||||
{
|
|
||||||
SHMat4 result;
|
|
||||||
|
|
||||||
std::memcpy(
|
|
||||||
&result,
|
|
||||||
&inMatrx,
|
|
||||||
sizeof(result)
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Assimp::Importer MeshCompiler::aiImporter;
|
|
||||||
uint32_t MeshCompiler::rigNodeIDCounter { 0 };
|
|
||||||
|
|
||||||
void MeshCompiler::ProcessNode(AiNodeConstPtr node, aiScene const& scene, MeshVectorRef meshes, RigData& rig) noexcept
|
|
||||||
{
|
|
||||||
if (node->mNumMeshes > 0)
|
|
||||||
{
|
|
||||||
aiMesh* mesh = scene.mMeshes[node->mMeshes[0]];
|
|
||||||
meshes.emplace_back();
|
|
||||||
GetMesh(*mesh, meshes.back());
|
|
||||||
meshes.back().name = node->mName.C_Str();
|
|
||||||
}
|
|
||||||
else if (node->mParent != nullptr)
|
|
||||||
{
|
|
||||||
BuildArmature(node, rig);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto i{ 0 }; i < node->mNumChildren; ++i)
|
|
||||||
{
|
|
||||||
ProcessNode(node->mChildren[i], scene, meshes, rig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshCompiler::GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept
|
|
||||||
{
|
|
||||||
meshData.vertexPosition.reserve(mesh.mNumVertices);
|
|
||||||
meshData.vertexNormal.reserve(mesh.mNumVertices);
|
|
||||||
meshData.vertexTangent.reserve(mesh.mNumVertices);
|
|
||||||
meshData.texCoords.reserve(mesh.mNumVertices);
|
|
||||||
|
|
||||||
meshData.bonesInfo.resize(mesh.mNumBones);
|
|
||||||
meshData.bones.resize(mesh.mNumBones);
|
|
||||||
|
|
||||||
for (auto i{ 0 }; i < mesh.mNumBones; ++i)
|
|
||||||
{
|
|
||||||
auto const& bone = *mesh.mBones[i];
|
|
||||||
auto& newBone = meshData.bones[i];
|
|
||||||
auto& newBoneInfo = meshData.bonesInfo[i];
|
|
||||||
|
|
||||||
newBone.name = bone.mName.C_Str();
|
|
||||||
newBoneInfo.charCount = newBone.name.length();
|
|
||||||
|
|
||||||
std::memcpy(&newBone.offset, &bone.mOffsetMatrix, sizeof(SHMat4));
|
|
||||||
|
|
||||||
newBone.weights.resize(bone.mNumWeights);
|
|
||||||
for (auto j{ 0 }; j < bone.mNumWeights; ++j)
|
|
||||||
{
|
|
||||||
newBone.weights[j].index = bone.mWeights[j].mVertexId;
|
|
||||||
newBone.weights[j].weight = bone.mWeights[j].mWeight;
|
|
||||||
}
|
|
||||||
newBoneInfo.weightCount = bone.mNumWeights;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i{ 0 }; i < mesh.mNumVertices; ++i)
|
|
||||||
{
|
|
||||||
// Vertex position
|
|
||||||
SHVec3 vertex;
|
|
||||||
vertex.x = mesh.mVertices[i].x;
|
|
||||||
vertex.y = mesh.mVertices[i].y;
|
|
||||||
vertex.z = mesh.mVertices[i].z;
|
|
||||||
meshData.vertexPosition.push_back(vertex);
|
|
||||||
|
|
||||||
// Tex coords
|
|
||||||
SHVec2 texCoord{ 0.f, 0.f };
|
|
||||||
if (mesh.mTextureCoords[0])
|
|
||||||
{
|
|
||||||
texCoord.x = mesh.mTextureCoords[0][i].x;
|
|
||||||
texCoord.y = mesh.mTextureCoords[0][i].y;
|
|
||||||
}
|
|
||||||
meshData.texCoords.push_back(texCoord);
|
|
||||||
|
|
||||||
// Normals
|
|
||||||
SHVec3 normal{ 0.f, 0.f, 0.f };
|
|
||||||
if (mesh.mNormals)
|
|
||||||
{
|
|
||||||
normal.x = mesh.mNormals[i].x;
|
|
||||||
normal.y = mesh.mNormals[i].y;
|
|
||||||
normal.z = mesh.mNormals[i].z;
|
|
||||||
}
|
|
||||||
meshData.vertexNormal.push_back(normal);
|
|
||||||
|
|
||||||
// Tangent
|
|
||||||
SHVec3 tangent{ 0.f, 0.f, 0.f };
|
|
||||||
if (mesh.mTangents)
|
|
||||||
{
|
|
||||||
tangent.x = mesh.mTangents[i].x;
|
|
||||||
tangent.y = mesh.mTangents[i].y;
|
|
||||||
tangent.z = mesh.mTangents[i].z;
|
|
||||||
}
|
|
||||||
meshData.vertexTangent.push_back(tangent);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i{ 0 }; i < mesh.mNumFaces; ++i)
|
|
||||||
{
|
|
||||||
aiFace face = mesh.mFaces[i];
|
|
||||||
for (size_t j{ 0 }; j < face.mNumIndices; ++j)
|
|
||||||
{
|
|
||||||
meshData.indices.push_back(face.mIndices[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshCompiler::BuildHeaders(ModelRef asset) noexcept
|
|
||||||
{
|
|
||||||
// Mesh Headers
|
|
||||||
asset.meshHeaders.resize(asset.meshes.size());
|
|
||||||
asset.header.meshCount = asset.meshes.size();
|
|
||||||
for (auto i{ 0 }; i < asset.header.meshCount; ++i)
|
|
||||||
{
|
|
||||||
auto const& mesh = asset.meshes[i];
|
|
||||||
auto& head = asset.meshHeaders[i];
|
|
||||||
|
|
||||||
head.charCount = mesh.name.size();
|
|
||||||
head.indexCount = mesh.indices.size();
|
|
||||||
head.vertexCount = mesh.vertexPosition.size();
|
|
||||||
head.boneCount = mesh.bonesInfo.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.nodeChannels.size();
|
|
||||||
head.nodeHeaders.resize(head.animNodeCount);
|
|
||||||
|
|
||||||
for (auto j{ 0 }; j < head.animNodeCount; ++j)
|
|
||||||
{
|
|
||||||
auto const& animNode = anim.nodeChannels[j];
|
|
||||||
auto& nodeHeader = head.nodeHeaders[j];
|
|
||||||
|
|
||||||
nodeHeader.charCount = animNode.name.size();
|
|
||||||
nodeHeader.posKeyCount = animNode.positionKeys.size();
|
|
||||||
nodeHeader.rotKeyCount = animNode.rotationKeys.size();
|
|
||||||
nodeHeader.scaKeyCount = animNode.scaleKeys.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshCompiler::BoneOffsetCopy(ModelRef asset) noexcept
|
|
||||||
{
|
|
||||||
if (asset.meshHeaders[0].boneCount == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const& boneVec {asset.meshes[0].bones};
|
|
||||||
|
|
||||||
std::stack<RigNodeData*> nodeStack;
|
|
||||||
nodeStack.push(asset.rig.root);
|
|
||||||
|
|
||||||
while(!nodeStack.empty())
|
|
||||||
{
|
|
||||||
auto& node = *nodeStack.top();
|
|
||||||
nodeStack.pop();
|
|
||||||
|
|
||||||
for (auto const& bone : boneVec)
|
|
||||||
{
|
|
||||||
if (node.name == bone.name)
|
|
||||||
{
|
|
||||||
node.offset = bone.offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const& child : node.children)
|
|
||||||
{
|
|
||||||
nodeStack.push(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshCompiler::ParseAnimations(aiScene const& scene, std::vector<AnimData>& anims) noexcept
|
|
||||||
{
|
|
||||||
// Size and read for number of animation clips
|
|
||||||
anims.resize(scene.mNumAnimations);
|
|
||||||
for (auto i{ 0 }; i < scene.mNumAnimations; ++i)
|
|
||||||
{
|
|
||||||
auto const& animData = *scene.mAnimations[i];
|
|
||||||
auto& anim = anims[i];
|
|
||||||
|
|
||||||
anim.name = animData.mName.C_Str();
|
|
||||||
anim.duration = animData.mDuration;
|
|
||||||
anim.ticksPerSecond = animData.mTicksPerSecond;
|
|
||||||
|
|
||||||
// Size and read for number of animation frames
|
|
||||||
anim.nodeChannels.resize(animData.mNumChannels);
|
|
||||||
for (auto j{ 0 }; j < animData.mNumChannels; ++j)
|
|
||||||
{
|
|
||||||
auto const& channelData = *animData.mChannels[j];
|
|
||||||
auto& node = anim.nodeChannels[j];
|
|
||||||
|
|
||||||
node.name = channelData.mNodeName.C_Str();
|
|
||||||
|
|
||||||
// Position Keys
|
|
||||||
node.positionKeys.resize(channelData.mNumPositionKeys);
|
|
||||||
for (auto k{ 0 }; k < channelData.mNumPositionKeys; ++k)
|
|
||||||
{
|
|
||||||
auto const& posKeyData = channelData.mPositionKeys[k];
|
|
||||||
auto& posKey = node.positionKeys[k];
|
|
||||||
|
|
||||||
posKey.time = posKeyData.mTime;
|
|
||||||
posKey.value.x = posKeyData.mValue.x;
|
|
||||||
posKey.value.y = posKeyData.mValue.y;
|
|
||||||
posKey.value.z = posKeyData.mValue.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rotation Keys
|
|
||||||
node.rotationKeys.resize(channelData.mNumRotationKeys);
|
|
||||||
for (auto k{ 0 }; k < channelData.mNumRotationKeys; ++k)
|
|
||||||
{
|
|
||||||
auto const& rotKeyData = channelData.mRotationKeys[k];
|
|
||||||
auto& rotKey = node.rotationKeys[k];
|
|
||||||
|
|
||||||
rotKey.time = rotKeyData.mTime;
|
|
||||||
rotKey.value.x = rotKeyData.mValue.x;
|
|
||||||
rotKey.value.y = rotKeyData.mValue.y;
|
|
||||||
rotKey.value.z = rotKeyData.mValue.z;
|
|
||||||
rotKey.value.w = rotKeyData.mValue.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scale Keys
|
|
||||||
node.scaleKeys.resize(channelData.mNumScalingKeys);
|
|
||||||
for (auto k{ 0 }; k < channelData.mNumScalingKeys; ++k)
|
|
||||||
{
|
|
||||||
auto const& scaKeyData = channelData.mScalingKeys[k];
|
|
||||||
auto& scaKey = node.scaleKeys[k];
|
|
||||||
|
|
||||||
scaKey.time = scaKeyData.mTime;
|
|
||||||
scaKey.value.x = scaKeyData.mValue.x;
|
|
||||||
scaKey.value.y = scaKeyData.mValue.y;
|
|
||||||
scaKey.value.z = scaKeyData.mValue.z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<RigNodeData*, aiNode const*> MeshCompiler::PairHelper(AiNodeConstPtr node)
|
|
||||||
{
|
|
||||||
return std::make_pair(NewNode(node), node);
|
|
||||||
}
|
|
||||||
|
|
||||||
RigNodeData* MeshCompiler::NewNode(AiNodeConstPtr inNode)
|
|
||||||
{
|
|
||||||
return new RigNodeData(inNode->mName.C_Str(), aiTransformToMat4(inNode->mTransformation));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshCompiler::LoadFromFile(AssetPath path, ModelRef 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_FindInvalidData // detect invalid model data, such as invalid normal vector
|
|
||||||
| aiProcess_FlipUVs // flip the V to match the Vulkans way of doing UVs
|
|
||||||
//| 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())
|
|
||||||
{
|
|
||||||
std::cout << "ERROR in GLTF::ASSIMP: " << aiImporter.GetErrorString() << "\nFile: " << path.string() << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessNode(scene->mRootNode, *scene, asset.meshes, asset.rig);
|
|
||||||
|
|
||||||
ParseAnimations(*scene, asset.anims);
|
|
||||||
|
|
||||||
aiImporter.FreeScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshCompiler::BuildArmature(AiNodeConstPtr baseNode, RigData& rig) noexcept
|
|
||||||
{
|
|
||||||
// Build implementation copy of armature tree
|
|
||||||
// node collection write done later when writing to file
|
|
||||||
std::stack<std::pair<RigNodeData*, AiNodeConstPtr>> nodeStack;
|
|
||||||
|
|
||||||
nodeStack.emplace(PairHelper(baseNode));
|
|
||||||
rig.root = nodeStack.top().first;
|
|
||||||
|
|
||||||
while(!nodeStack.empty())
|
|
||||||
{
|
|
||||||
auto currPair = nodeStack.top();
|
|
||||||
nodeStack.pop();
|
|
||||||
auto currNode = currPair.first;
|
|
||||||
auto const& currAiNode = currPair.second;
|
|
||||||
int const iStart {static_cast<int>(currAiNode->mNumChildren - 1)};
|
|
||||||
|
|
||||||
rig.header.nodeCount++;
|
|
||||||
rig.header.charCounts.push_back(currNode->name.length());
|
|
||||||
|
|
||||||
for (int i {iStart}; i >= 0 ; --i)
|
|
||||||
{
|
|
||||||
auto newPair = PairHelper(currAiNode->mChildren[i]);
|
|
||||||
currNode->children.push_back(newPair.first);
|
|
||||||
nodeStack.push(newPair);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshCompiler::LoadAndCompile(AssetPath path) noexcept
|
|
||||||
{
|
|
||||||
auto const asset = new ModelAsset();
|
|
||||||
|
|
||||||
LoadFromFile(path, *asset);
|
|
||||||
BuildHeaders(*asset);
|
|
||||||
BoneOffsetCopy(*asset);
|
|
||||||
MeshWriter::CompileMeshBinary(path, *asset);
|
|
||||||
|
|
||||||
delete asset;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,44 +12,54 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <assimp/Importer.hpp>
|
|
||||||
#include <assimp/scene.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Types/AnimationAsset.h"
|
#include "Types/AnimationAsset.h"
|
||||||
#include "Types/ModelAsset.h"
|
#include "Types/ModelAsset.h"
|
||||||
#include "AssetMacros.h"
|
#include "AssetMacros.h"
|
||||||
|
|
||||||
|
//Forward Declare
|
||||||
|
namespace tinygltf
|
||||||
|
{
|
||||||
|
struct Accessor;
|
||||||
|
struct BufferView;
|
||||||
|
class Model;
|
||||||
|
}
|
||||||
|
|
||||||
namespace SH_COMP
|
namespace SH_COMP
|
||||||
{
|
{
|
||||||
|
using MeshVectorRef = std::vector<MeshData>&;
|
||||||
|
using AnimVectorRef = std::vector<AnimData>&;
|
||||||
|
|
||||||
|
using ModelRef = ModelAsset&;
|
||||||
|
using ModelData = tinygltf::Model;
|
||||||
|
using AccessorReference = std::vector<tinygltf::Accessor> const*;
|
||||||
|
using BufferViewReference = std::vector<tinygltf::BufferView> const*;
|
||||||
|
using BufferData = unsigned char const*;
|
||||||
|
|
||||||
class MeshCompiler
|
class MeshCompiler
|
||||||
{
|
{
|
||||||
|
|
||||||
using MeshVectorRef = std::vector<MeshData>&;
|
static AccessorReference accessors;
|
||||||
using AnimVectorRef = std::vector<AnimData>&;
|
static BufferViewReference bufferViews;
|
||||||
|
static BufferData buffer;
|
||||||
|
|
||||||
using ModelRef = ModelAsset&;
|
static inline void LoadFromFile(AssetPath path, ModelRef asset) noexcept;
|
||||||
|
|
||||||
using AiNodeConstPtr = aiNode const*;
|
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 Assimp::Importer aiImporter;
|
static inline void BuildHeaders(ModelRef asset) noexcept;
|
||||||
static uint32_t rigNodeIDCounter;
|
|
||||||
|
|
||||||
static void ProcessNode(AiNodeConstPtr node, aiScene const& scene, MeshVectorRef meshes, RigData& rig) noexcept;
|
template<typename T>
|
||||||
static void GetMesh(aiMesh const& mesh, MeshData& meshData) noexcept;
|
static void FetchData(int accessorID, std::vector<T>& dst);
|
||||||
static void BuildHeaders(ModelRef asset) noexcept;
|
|
||||||
|
|
||||||
static void BoneOffsetCopy(ModelRef asset) noexcept;
|
|
||||||
|
|
||||||
static void BuildArmature(AiNodeConstPtr node, RigData& rig) noexcept;
|
|
||||||
static void ParseAnimations(aiScene const& scene, std::vector<AnimData>& anims) noexcept;
|
|
||||||
|
|
||||||
static std::pair<RigNodeData*, AiNodeConstPtr> PairHelper(AiNodeConstPtr node);
|
|
||||||
static RigNodeData* NewNode(AiNodeConstPtr inNode);
|
|
||||||
|
|
||||||
static void LoadFromFile(AssetPath path, ModelRef asset) noexcept;
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void FetchChannelKeyFrame(int inputAcc, int outputAcc, std::vector<T>& dst);
|
||||||
public:
|
public:
|
||||||
static void LoadAndCompile(AssetPath path) noexcept;
|
static inline void LoadAndCompile(AssetPath path) noexcept;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "MeshCompiler.hpp"
|
||||||
|
|
|
@ -0,0 +1,324 @@
|
||||||
|
/*************************************************************************//**
|
||||||
|
* \file MeshCompiler.cpp
|
||||||
|
* \author Loh Xiao Qi
|
||||||
|
* \date 30 September 2022
|
||||||
|
* \brief Library to write data in MeshAsset into binary file for faster
|
||||||
|
* loading in the future
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 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 "MeshCompiler.h"
|
||||||
|
#include "MeshWriter.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "Includes/tiny_gltf.h"
|
||||||
|
#include <map>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
namespace SH_COMP
|
||||||
|
{
|
||||||
|
AccessorReference MeshCompiler::accessors{ nullptr };
|
||||||
|
BufferViewReference MeshCompiler::bufferViews{ nullptr };
|
||||||
|
BufferData MeshCompiler::buffer{ nullptr };
|
||||||
|
|
||||||
|
inline void MeshCompiler::LoadFromFile(AssetPath path, ModelRef asset) noexcept
|
||||||
|
{
|
||||||
|
ModelData model;
|
||||||
|
tinygltf::TinyGLTF loader;
|
||||||
|
std::string warn, error;
|
||||||
|
|
||||||
|
bool result = loader.LoadASCIIFromFile(&model, &error, &warn, path.string());
|
||||||
|
|
||||||
|
if (!warn.empty())
|
||||||
|
std::cout << "[TinyGLTF Warning]: " << warn << std::endl;
|
||||||
|
|
||||||
|
if (!error.empty())
|
||||||
|
std::cout << "[TinyGLTF Error]: " << error << std::endl;
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
std::cout << "TinyGLTF failed to parse.\n";
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessMesh(model, asset);
|
||||||
|
ProcessRigNodes(model, asset);
|
||||||
|
ProcessAnimationChannels(model, asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MeshCompiler::ProcessMesh(ModelData const& data, ModelRef asset) noexcept
|
||||||
|
{
|
||||||
|
accessors = &data.accessors;
|
||||||
|
bufferViews = &data.bufferViews;
|
||||||
|
buffer = data.buffers[0].data.data();
|
||||||
|
|
||||||
|
for (auto const& mesh : data.meshes)
|
||||||
|
{
|
||||||
|
auto const& primitive { mesh.primitives[0] };
|
||||||
|
auto& meshIn {asset.meshes.emplace_back()};
|
||||||
|
meshIn.name = mesh.name;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FetchData(primitive.attributes.at(ATT_POSITION.data()), meshIn.vertexPosition);
|
||||||
|
FetchData(primitive.attributes.at(ATT_NORMAL.data()), meshIn.vertexNormal);
|
||||||
|
FetchData(primitive.attributes.at(ATT_TEXCOORD.data()), meshIn.texCoords);
|
||||||
|
FetchData(primitive.indices, meshIn.indices);
|
||||||
|
|
||||||
|
std::vector<SHVec4> intermediate;
|
||||||
|
FetchData(primitive.attributes.at(ATT_TANGENT.data()), intermediate);
|
||||||
|
meshIn.vertexTangent.resize(intermediate.size());
|
||||||
|
std::ranges::transform(
|
||||||
|
intermediate,
|
||||||
|
meshIn.vertexTangent.begin(),
|
||||||
|
[](auto const& inTan)
|
||||||
|
{
|
||||||
|
return SHVec3{ inTan.x, inTan.y, inTan.z };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (std::out_of_range e)
|
||||||
|
{
|
||||||
|
std::cout << "[Model Compiler] Failed to load critical data from gltf\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FetchData(primitive.attributes.at(ATT_WEIGHTS.data()), meshIn.weights);
|
||||||
|
FetchData(primitive.attributes.at(ATT_JOINT.data()), meshIn.joints);
|
||||||
|
}
|
||||||
|
catch(std::out_of_range e)
|
||||||
|
{
|
||||||
|
std::cout << "No weights and joints found for mesh: " << mesh.name << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void MeshCompiler::FetchData(int accessorID, std::vector<T>& dst)
|
||||||
|
{
|
||||||
|
auto const& accessor = (*accessors)[accessorID];
|
||||||
|
auto const& view = (*bufferViews)[accessor.bufferView];
|
||||||
|
auto const typeIdentifier{ static_cast<ACCESSOR_COMPONENT_TYPE>(accessor.componentType) };
|
||||||
|
auto const sizeIdentifier{ SizeOfType(typeIdentifier) };
|
||||||
|
auto const componentCount{ CountOfType(static_cast<ACCESSOR_DATA_TYPE>(accessor.type))};
|
||||||
|
auto const totalStrideBytes{ sizeIdentifier * componentCount };
|
||||||
|
dst.resize(accessor.count);
|
||||||
|
if (sizeof(T) == totalStrideBytes)
|
||||||
|
{
|
||||||
|
std::memcpy(
|
||||||
|
dst.data(),
|
||||||
|
buffer + view.byteOffset,
|
||||||
|
view.byteLength
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::byte> tempData(view.byteLength);
|
||||||
|
std::memcpy(
|
||||||
|
tempData.data(),
|
||||||
|
buffer + view.byteOffset,
|
||||||
|
view.byteLength
|
||||||
|
);
|
||||||
|
|
||||||
|
auto srcPtr{ tempData.data() };
|
||||||
|
T* dstPtr{ dst.data() };
|
||||||
|
size_t index{ 0 };
|
||||||
|
for (auto i{0}; i < accessor.count; ++i, ++index)
|
||||||
|
{
|
||||||
|
auto srcCompPtr{ srcPtr };
|
||||||
|
auto dstCompPtr{ reinterpret_cast<IndexType*>(dstPtr)};
|
||||||
|
for (auto j{0}; j < componentCount; ++j)
|
||||||
|
{
|
||||||
|
std::memcpy(
|
||||||
|
dstCompPtr,
|
||||||
|
srcCompPtr,
|
||||||
|
sizeIdentifier
|
||||||
|
);
|
||||||
|
|
||||||
|
srcCompPtr += sizeIdentifier;
|
||||||
|
++dstCompPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcPtr += totalStrideBytes;
|
||||||
|
|
||||||
|
++dstPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void MeshCompiler::FetchChannelKeyFrame(int inputAcc, int outputAcc, std::vector<T>& dst)
|
||||||
|
{
|
||||||
|
// ONLY ALLOW THIS FUNCTION TO BE USED ON KEY DATA STRUCT
|
||||||
|
static_assert(std::derived_from<T, KeyBase> == true);
|
||||||
|
|
||||||
|
std::vector<float> inputVec;
|
||||||
|
std::vector<SHVec4> outputVec;
|
||||||
|
FetchData(inputAcc, inputVec);
|
||||||
|
FetchData(outputAcc, outputVec);
|
||||||
|
|
||||||
|
dst.resize(inputVec.size());
|
||||||
|
|
||||||
|
std::ranges::transform(
|
||||||
|
inputVec,
|
||||||
|
outputVec,
|
||||||
|
dst.begin(),
|
||||||
|
[](float const& time, SHVec4 const& value)->T
|
||||||
|
{
|
||||||
|
return { time, value };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MeshCompiler::BuildHeaders(ModelRef asset) noexcept
|
||||||
|
{
|
||||||
|
// Mesh Headers
|
||||||
|
asset.meshHeaders.resize(asset.meshes.size());
|
||||||
|
asset.header.meshCount = asset.meshes.size();
|
||||||
|
for (auto i{ 0 }; i < asset.header.meshCount; ++i)
|
||||||
|
{
|
||||||
|
auto const& mesh = asset.meshes[i];
|
||||||
|
auto& head = asset.meshHeaders[i];
|
||||||
|
|
||||||
|
head.charCount = mesh.name.size();
|
||||||
|
head.indexCount = mesh.indices.size();
|
||||||
|
head.vertexCount = mesh.vertexPosition.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MeshCompiler::LoadAndCompile(AssetPath path) noexcept
|
||||||
|
{
|
||||||
|
auto const asset = new ModelAsset();
|
||||||
|
|
||||||
|
LoadFromFile(path, *asset);
|
||||||
|
BuildHeaders(*asset);
|
||||||
|
MeshWriter::CompileMeshBinary(path, *asset);
|
||||||
|
|
||||||
|
delete asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MeshCompiler::ProcessAnimationChannels(ModelData const& data, ModelRef asset) noexcept
|
||||||
|
{
|
||||||
|
if (data.animations.empty())
|
||||||
|
{
|
||||||
|
std::cout << "[Model Compiler] Animations do not exist\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
asset.anims.resize(data.animations.size());
|
||||||
|
for (auto i {0}; i < data.animations.size(); ++i)
|
||||||
|
{
|
||||||
|
auto const& animData{ data.animations[i] };
|
||||||
|
auto& anim{ asset.anims[i] };
|
||||||
|
|
||||||
|
anim.name = animData.name;
|
||||||
|
|
||||||
|
for (auto const& channel : animData.channels)
|
||||||
|
{
|
||||||
|
auto const& sampler{ animData.samplers[channel.sampler] };
|
||||||
|
auto const& targetNode{asset.nodeIndexMap[channel.target_node]};
|
||||||
|
|
||||||
|
// Resize nodes vector to latest largest index called
|
||||||
|
if (anim.nodes.size() <= targetNode)
|
||||||
|
anim.nodes.resize(targetNode + 1);
|
||||||
|
|
||||||
|
if (channel.target_path == TRANSLATION_PATH.data())
|
||||||
|
FetchChannelKeyFrame(sampler.input, sampler.output, anim.nodes[targetNode].positionKeys);
|
||||||
|
else if (channel.target_path == SCALE_PATH.data())
|
||||||
|
FetchChannelKeyFrame(sampler.input, sampler.output, anim.nodes[targetNode].scaleKeys);
|
||||||
|
else if (channel.target_path == ROTATION_PATH.data())
|
||||||
|
FetchChannelKeyFrame(sampler.input, sampler.output, anim.nodes[targetNode].rotationKeys);
|
||||||
|
|
||||||
|
anim.nodes[targetNode].interpolation =
|
||||||
|
sampler.interpolation == LINEAR_INTERPOLATION.data() ? AnimationInterpolation::LINEAR :
|
||||||
|
sampler.interpolation == STEP_INTERPOLATION.data() ? AnimationInterpolation::STEP :
|
||||||
|
sampler.interpolation == CUBICSPLINE_INTERPOLATION.data() ? AnimationInterpolation::CUBICSPLINE :
|
||||||
|
AnimationInterpolation::DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
anim.duration = (anim.nodes[0].positionKeys.end() - 1)->time;
|
||||||
|
anim.ticksPerSecond = 1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void MeshCompiler::ProcessRigNodes(ModelData const& data, ModelRef asset) noexcept
|
||||||
|
{
|
||||||
|
if (data.skins.empty())
|
||||||
|
{
|
||||||
|
std::cout << "[Model Compiler] Unable to load rigs without skin, aborting";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& rig = asset.rig;
|
||||||
|
auto& header = rig.header;
|
||||||
|
auto const& skin = data.skins[0];
|
||||||
|
auto const jointsCount {skin.joints.size()};
|
||||||
|
auto const& joints = skin.joints;
|
||||||
|
auto const& nodeMap {asset.nodeIndexMap};
|
||||||
|
|
||||||
|
std::vector<SHMat4> inverseBindMatrices;
|
||||||
|
FetchData(skin.inverseBindMatrices, inverseBindMatrices);
|
||||||
|
|
||||||
|
for (auto i{0}; i < skin.joints.size(); ++i)
|
||||||
|
{
|
||||||
|
asset.nodeIndexMap.insert({skin.joints[i], i});
|
||||||
|
}
|
||||||
|
std::vector<NodeAsset> nodesOrdered;
|
||||||
|
nodesOrdered.reserve(jointsCount);
|
||||||
|
auto& nodes{ data.nodes };
|
||||||
|
|
||||||
|
for (auto i{0}; i < jointsCount; ++i)
|
||||||
|
{
|
||||||
|
auto const& node{nodes[joints[i]]};
|
||||||
|
std::vector<IndexType> intermediate(node.children.size());
|
||||||
|
std::ranges::transform(
|
||||||
|
node.children,
|
||||||
|
intermediate.begin(),
|
||||||
|
[nodeMap](auto const& index)->IndexType
|
||||||
|
{
|
||||||
|
return nodeMap.at(static_cast<uint32_t>(index));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
nodesOrdered.emplace_back(
|
||||||
|
node.name,
|
||||||
|
static_cast<std::vector<IndexType> const&>(intermediate),
|
||||||
|
node.rotation,
|
||||||
|
node.scale,
|
||||||
|
node.translation,
|
||||||
|
node.matrix,
|
||||||
|
inverseBindMatrices[i]
|
||||||
|
);
|
||||||
|
nodesOrdered[i].inverseBindMatrix = inverseBindMatrices[i];
|
||||||
|
header.charCounts.emplace_back(node.name.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
rig.nodes = std::move(nodesOrdered);
|
||||||
|
|
||||||
|
//Build header
|
||||||
|
header.startNode = 0;
|
||||||
|
header.nodeCount = rig.nodes.size();
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,36 +57,25 @@ 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(SHVec4) * header.vertexCount
|
||||||
);
|
);
|
||||||
|
file.write(
|
||||||
for (auto const& bone : asset.bones)
|
reinterpret_cast<char const*>(asset.joints.data()),
|
||||||
{
|
sizeof(SHVec4i) * header.vertexCount
|
||||||
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,37 +98,22 @@ 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.nodeChannels[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(
|
file.write(
|
||||||
node.name.data(),
|
reinterpret_cast<char const*>(&node.interpolation),
|
||||||
info.charCount
|
sizeof(AnimationInterpolation)
|
||||||
);
|
|
||||||
|
|
||||||
file.write(
|
|
||||||
reinterpret_cast<char const*>(&node.pre),
|
|
||||||
sizeof(AnimationBehaviour)
|
|
||||||
);
|
|
||||||
|
|
||||||
file.write(
|
|
||||||
reinterpret_cast<char const*>(&node.post),
|
|
||||||
sizeof(AnimationBehaviour)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
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
|
||||||
|
@ -159,9 +133,8 @@ 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);
|
WriteRigStructure(file, data);
|
||||||
WriteRigTree(file, root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshWriter::WriteRigHeader(FileReference file, RigDataHeader const& header)
|
void MeshWriter::WriteRigHeader(FileReference file, RigDataHeader const& header)
|
||||||
|
@ -171,90 +144,101 @@ namespace SH_COMP
|
||||||
sizeof(uint32_t)
|
sizeof(uint32_t)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
file.write(
|
||||||
|
reinterpret_cast<char const*>(&header.startNode),
|
||||||
|
sizeof(uint32_t)
|
||||||
|
);
|
||||||
|
|
||||||
file.write(
|
file.write(
|
||||||
reinterpret_cast<char const*>(header.charCounts.data()),
|
reinterpret_cast<char const*>(header.charCounts.data()),
|
||||||
sizeof(uint32_t) * header.nodeCount
|
sizeof(uint32_t) * header.nodeCount
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
std::vector<IndexType> treeNodeWrite;
|
||||||
// Build tree of nodes using ID
|
for (auto const& node : rig.nodes)
|
||||||
|
|
||||||
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(
|
file.write(
|
||||||
reinterpret_cast<char const*>(&data.transform),
|
node.name.data(),
|
||||||
|
node.name.size()
|
||||||
|
);
|
||||||
|
|
||||||
|
file.write(
|
||||||
|
reinterpret_cast<char const*>(&node.inverseBindMatrix),
|
||||||
sizeof(SHMat4)
|
sizeof(SHMat4)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Build data flags
|
||||||
|
NodeDataFlag flag{ 0 };
|
||||||
|
|
||||||
|
if (!node.rotation.empty())
|
||||||
|
flag |= NODE_DATA_ROTATION;
|
||||||
|
if (!node.scale.empty())
|
||||||
|
flag |= NODE_DATA_SCALE;
|
||||||
|
if (!node.translation.empty())
|
||||||
|
flag |= NODE_DATA_TRANSLATION;
|
||||||
|
if (!node.matrix.empty())
|
||||||
|
flag |= NODE_DATA_MATRIX;
|
||||||
|
|
||||||
|
file.put(flag);
|
||||||
|
|
||||||
file.write(
|
file.write(
|
||||||
reinterpret_cast<char const*>(&data.offset),
|
reinterpret_cast<char const*>(node.rotation.data()),
|
||||||
sizeof(SHMat4)
|
sizeof(double) * node.rotation.size()
|
||||||
|
);
|
||||||
|
|
||||||
|
file.write(
|
||||||
|
reinterpret_cast<char const*>(node.scale.data()),
|
||||||
|
sizeof(double) * node.scale.size()
|
||||||
|
);
|
||||||
|
|
||||||
|
file.write(
|
||||||
|
reinterpret_cast<char const*>(node.translation.data()),
|
||||||
|
sizeof(double) * node.translation.size()
|
||||||
|
);
|
||||||
|
|
||||||
|
file.write(
|
||||||
|
reinterpret_cast<char const*>(node.matrix.data()),
|
||||||
|
sizeof(double) * node.matrix.size()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshWriter::WriteRigTree(FileReference file, RigWriteNode const* root)
|
void MeshWriter::WriteRigStructure(FileReference file, RigData const& rig)
|
||||||
{
|
{
|
||||||
std::queue<RigWriteNode const*> nodeQueue;
|
std::queue<std::pair<IndexType, NodeAsset const*>> nodeQueue;
|
||||||
nodeQueue.push(root);
|
nodeQueue.push(
|
||||||
|
std::make_pair(
|
||||||
|
rig.header.startNode,
|
||||||
|
rig.nodes.data() + rig.header.startNode
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
int ctr = 0;
|
while (!nodeQueue.empty())
|
||||||
|
|
||||||
while(!nodeQueue.empty())
|
|
||||||
{
|
{
|
||||||
auto node = nodeQueue.front();
|
auto const currentPair = nodeQueue.front();
|
||||||
|
auto const& node = *currentPair.second;
|
||||||
nodeQueue.pop();
|
nodeQueue.pop();
|
||||||
|
|
||||||
file.write(
|
file.write(
|
||||||
reinterpret_cast<char const*>(&node->id),
|
reinterpret_cast<char const*>(¤tPair.first),
|
||||||
|
sizeof(IndexType)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto const childCount{ static_cast<uint32_t>(node.children.size()) };
|
||||||
|
file.write(
|
||||||
|
reinterpret_cast<char const*>(&childCount),
|
||||||
sizeof(uint32_t)
|
sizeof(uint32_t)
|
||||||
);
|
);
|
||||||
|
|
||||||
uint32_t size = static_cast<uint32_t>(node->children.size());
|
for (auto const& child : node.children)
|
||||||
|
|
||||||
file.write(
|
|
||||||
reinterpret_cast<char const*>(&size),
|
|
||||||
sizeof(uint32_t)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (auto child : node->children)
|
|
||||||
{
|
{
|
||||||
nodeQueue.push(child);
|
nodeQueue.push(std::make_pair(
|
||||||
|
child,
|
||||||
|
rig.nodes.data() + child
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,26 +260,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)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +272,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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,12 @@ 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 WriteRigStructure(FileReference file, RigData const& rig);
|
||||||
//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);
|
||||||
|
|
|
@ -8,16 +8,34 @@ namespace SH_COMP
|
||||||
float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHVec3
|
|
||||||
{
|
|
||||||
float x, y, z;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SHVec4
|
struct SHVec4
|
||||||
{
|
{
|
||||||
float x, y, z, w;
|
float x, y, z, w;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SHVec3
|
||||||
|
{
|
||||||
|
SHVec3()
|
||||||
|
:x{ 0.f }, y{ 0.f }, z{ 0.f }
|
||||||
|
{}
|
||||||
|
|
||||||
|
SHVec3(SHVec4 const& rhs)
|
||||||
|
:x{ rhs.x }, y{ rhs.y }, z{ rhs.z }
|
||||||
|
{}
|
||||||
|
|
||||||
|
SHVec3(float inx, float iny, float inz)
|
||||||
|
:x{ iny }, y{ iny }, z{ inz }
|
||||||
|
{}
|
||||||
|
|
||||||
|
float x, y, z;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SHVec4i
|
||||||
|
{
|
||||||
|
uint32_t x, y, z, w;
|
||||||
|
};
|
||||||
|
|
||||||
struct SHMat4
|
struct SHMat4
|
||||||
{
|
{
|
||||||
float data[16];
|
float data[16];
|
||||||
|
@ -35,4 +53,7 @@ namespace SH_COMP
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using IndexType = uint32_t;
|
||||||
|
|
||||||
}
|
}
|
|
@ -12,64 +12,55 @@
|
||||||
|
|
||||||
#include "PseudoMath.h"
|
#include "PseudoMath.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <assimp/anim.h>
|
#include <string>
|
||||||
|
|
||||||
namespace SH_COMP
|
namespace SH_COMP
|
||||||
{
|
{
|
||||||
enum class AnimationBehaviour : uint8_t
|
enum class AnimationInterpolation : uint8_t
|
||||||
{
|
{
|
||||||
DEFAULT = 0x0,
|
DEFAULT = 0x1,
|
||||||
CONSTANT = 0x1,
|
LINEAR = 0x1,
|
||||||
LINEAR = 0x2,
|
STEP = 0x2,
|
||||||
REPEAT = 0x3
|
CUBICSPLINE = 0x3
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base
|
||||||
|
struct KeyBase
|
||||||
|
{
|
||||||
|
float time;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Smallest data containers
|
// Smallest data containers
|
||||||
struct PositionKey
|
struct PositionKey :KeyBase
|
||||||
{
|
{
|
||||||
float time;
|
|
||||||
SHVec3 value;
|
SHVec3 value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RotationKey
|
struct RotationKey : KeyBase
|
||||||
{
|
{
|
||||||
float time;
|
|
||||||
SHVec4 value;
|
SHVec4 value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScaleKey
|
struct ScaleKey :KeyBase
|
||||||
{
|
{
|
||||||
float time;
|
|
||||||
SHVec3 value;
|
SHVec3 value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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;
|
||||||
AnimationBehaviour pre;
|
|
||||||
AnimationBehaviour post;
|
|
||||||
|
|
||||||
std::vector<PositionKey> positionKeys;
|
std::vector<PositionKey> positionKeys;
|
||||||
std::vector<RotationKey> rotationKeys;
|
std::vector<RotationKey> rotationKeys;
|
||||||
std::vector<ScaleKey> scaleKeys;
|
std::vector<ScaleKey> scaleKeys;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AnimData
|
struct AnimData
|
||||||
|
@ -79,8 +70,7 @@ namespace SH_COMP
|
||||||
double duration;
|
double duration;
|
||||||
double ticksPerSecond;
|
double ticksPerSecond;
|
||||||
|
|
||||||
std::vector<AnimNode> nodeChannels;
|
//One node represents the animation transforms for one bone in the rig
|
||||||
//std::vector<aiMeshAnim*> meshChannels;
|
std::vector<AnimNode> nodes;
|
||||||
//std::vector<aiMeshMorphAnim*> morphMeshChannels;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -12,37 +12,21 @@ 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
|
|
||||||
{
|
|
||||||
uint32_t charCount;
|
|
||||||
uint32_t weightCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
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<uint32_t> indices;
|
std::vector<IndexType> indices;
|
||||||
std::vector<MeshBoneInfo> bonesInfo;
|
|
||||||
std::vector<MeshBone> bones;
|
//Variable data
|
||||||
|
std::vector<SHVec4> weights;
|
||||||
|
std::vector<SHVec4i> joints;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "MeshAsset.h"
|
#include "MeshAsset.h"
|
||||||
#include "AnimationAsset.h"
|
#include "AnimationAsset.h"
|
||||||
|
@ -30,12 +31,15 @@ namespace SH_COMP
|
||||||
struct ModelAsset
|
struct ModelAsset
|
||||||
{
|
{
|
||||||
ModelAssetHeader header;
|
ModelAssetHeader header;
|
||||||
RigData rig;
|
|
||||||
|
|
||||||
std::vector<MeshDataHeader> meshHeaders;
|
std::vector<MeshDataHeader> meshHeaders;
|
||||||
std::vector<AnimDataHeader> animHeaders;
|
std::vector<AnimDataHeader> animHeaders;
|
||||||
|
|
||||||
std::vector<MeshData> meshes;
|
std::vector<MeshData> meshes;
|
||||||
std::vector<AnimData> anims;
|
std::vector<AnimData> anims;
|
||||||
};
|
|
||||||
|
RigData rig;
|
||||||
|
|
||||||
|
std::unordered_map<uint32_t, uint32_t> nodeIndexMap;
|
||||||
|
; };
|
||||||
}
|
}
|
|
@ -8,40 +8,37 @@
|
||||||
|
|
||||||
namespace SH_COMP
|
namespace SH_COMP
|
||||||
{
|
{
|
||||||
|
using NodeDataFlag = unsigned char;
|
||||||
|
|
||||||
|
constexpr NodeDataFlag NODE_DATA_ROTATION = 0b0001;
|
||||||
|
constexpr NodeDataFlag NODE_DATA_SCALE = 0b0010;
|
||||||
|
constexpr NodeDataFlag NODE_DATA_TRANSLATION = 0b0100;
|
||||||
|
constexpr NodeDataFlag NODE_DATA_MATRIX = 0b1000;
|
||||||
|
//constexpr NodeDataFlag NODE_DATA_WEIGHTS = 0b10000;
|
||||||
|
|
||||||
struct RigDataHeader
|
struct RigDataHeader
|
||||||
{
|
{
|
||||||
uint32_t nodeCount;
|
uint32_t nodeCount;
|
||||||
|
IndexType startNode;
|
||||||
std::vector<uint32_t> charCounts;
|
std::vector<uint32_t> charCounts;
|
||||||
};
|
};
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
19
src/main.cpp
19
src/main.cpp
|
@ -8,11 +8,11 @@
|
||||||
* 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/MeshCompiler.h"
|
#include "Libraries/MeshCompiler.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
{
|
{
|
||||||
|
#if 1
|
||||||
if (std::filesystem::is_directory(ASSET_ROOT))
|
if (std::filesystem::is_directory(ASSET_ROOT))
|
||||||
{
|
{
|
||||||
for (auto& dir :
|
for (auto& dir :
|
||||||
|
@ -41,6 +42,18 @@ int main(int argc, char* argv[])
|
||||||
std::cout << "Default path not found!" << std::endl;
|
std::cout << "Default path not found!" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
for (auto& dir : std::filesystem::directory_iterator{ "./" })
|
||||||
|
{
|
||||||
|
if (dir.path().extension().string() == GLTF_EXTENSION ||
|
||||||
|
dir.path().extension().string() == FBX_EXTENSION)
|
||||||
|
{
|
||||||
|
auto path = dir.path();
|
||||||
|
path.make_preferred();
|
||||||
|
paths.push_back(path.string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (argc > 1)
|
else if (argc > 1)
|
||||||
{
|
{
|
||||||
|
@ -57,7 +70,9 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
SH_COMP::MeshCompiler::LoadAndCompile("racoon.gltf");
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
SH_COMP::MeshCompiler::LoadAndCompile("MD_HomeownerV2.gltf");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue