Merge pull request #358 from Laupetin/feature/gltf-separate-meshes

feat: separate objects into gltf meshes instead of primitives
This commit is contained in:
Jan 2025-01-23 19:12:04 +01:00 committed by GitHub
commit f6d36b2d6e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 76 additions and 70 deletions

View File

@ -8,6 +8,7 @@
#include <Eigen>
#pragma warning(pop)
#include <algorithm>
#include <format>
using namespace gltf;
@ -41,13 +42,13 @@ namespace
CreateJsonAsset(gltf.asset);
CreateSkeletonNodes(gltf, xmodel);
CreateMeshNode(gltf, xmodel);
CreateMeshNodes(gltf, xmodel);
CreateRootNode(gltf, xmodel);
CreateMaterials(gltf, xmodel);
CreateBufferViews(gltf, xmodel);
CreateAccessors(gltf, xmodel);
CreateSkin(gltf, xmodel);
CreateMesh(gltf, xmodel);
CreateMeshes(gltf, xmodel);
CreateScene(gltf, xmodel);
FillBufferData(gltf, xmodel, bufferData);
CreateBuffer(gltf, xmodel, bufferData);
@ -68,15 +69,22 @@ namespace
asset.generator = GLTF_GENERATOR;
}
void CreateMeshNode(JsonRoot& gltf, const XModelCommon& xmodel)
void CreateMeshNodes(JsonRoot& gltf, const XModelCommon& xmodel)
{
if (!gltf.nodes.has_value())
gltf.nodes.emplace();
m_first_mesh_node = gltf.nodes->size();
auto meshIndex = 0u;
for (const auto& object : xmodel.m_objects)
{
JsonNode meshNode;
if (!xmodel.m_name.empty())
meshNode.name = xmodel.m_name;
if (!object.name.empty())
meshNode.name = object.name;
// We only have one mesh
meshNode.mesh = 0u;
meshNode.mesh = meshIndex++;
// Only add skin if the model has bones
if (!xmodel.m_bones.empty())
@ -85,22 +93,20 @@ namespace
meshNode.skin = 0u;
}
if (!gltf.nodes.has_value())
gltf.nodes.emplace();
m_mesh_node = gltf.nodes->size();
if (xmodel.m_bones.empty())
m_root_node = m_mesh_node;
gltf.nodes->emplace_back(std::move(meshNode));
}
// If we only have one mesh and no bones we don't need a dedicated root node
if (xmodel.m_bones.empty() && xmodel.m_objects.size() == 1)
m_root_node = m_first_mesh_node;
}
void CreateRootNode(JsonRoot& gltf, const XModelCommon& xmodel)
{
JsonNode rootNode;
if (xmodel.m_bones.empty())
// If we have at most one mesh and no bones we don't need a dedicated root node
if (xmodel.m_bones.empty() && xmodel.m_objects.size() <= 1)
return;
if (!xmodel.m_name.empty())
@ -110,29 +116,31 @@ namespace
gltf.nodes.emplace();
rootNode.children.emplace();
rootNode.children->push_back(m_mesh_node);
const auto meshCount = xmodel.m_objects.size();
for (auto meshIndex = 0u; meshIndex < meshCount; meshIndex++)
rootNode.children->push_back(m_first_mesh_node + meshIndex);
rootNode.children->push_back(m_first_bone_node);
m_root_node = gltf.nodes->size();
gltf.nodes->emplace_back(std::move(rootNode));
}
void CreateMesh(JsonRoot& gltf, const XModelCommon& xmodel)
void CreateMeshes(JsonRoot& gltf, const XModelCommon& xmodel)
{
if (!gltf.meshes.has_value())
gltf.meshes.emplace();
JsonMesh mesh;
const auto hasBoneWeightData = !xmodel.m_bone_weight_data.weights.empty();
auto objectIndex = 0u;
for (const auto& object : xmodel.m_objects)
{
JsonMesh mesh;
JsonMeshPrimitives primitives;
if (object.materialIndex >= 0)
primitives.material = static_cast<unsigned>(object.materialIndex);
primitives.material = object.materialIndex;
primitives.attributes.POSITION = m_position_accessor;
primitives.attributes.NORMAL = m_normal_accessor;
@ -149,10 +157,9 @@ namespace
mesh.primitives.emplace_back(primitives);
objectIndex++;
}
gltf.meshes->emplace_back(std::move(mesh));
}
}
static void CreateMaterials(JsonRoot& gltf, const XModelCommon& xmodel)
{
@ -466,18 +473,12 @@ namespace
vertex->coordinates[1] = commonVertex.coordinates[2];
vertex->coordinates[2] = -commonVertex.coordinates[1];
if (minPosition[0] > vertex->coordinates[0])
minPosition[0] = vertex->coordinates[0];
if (minPosition[1] > vertex->coordinates[1])
minPosition[1] = vertex->coordinates[1];
if (minPosition[2] > vertex->coordinates[2])
minPosition[2] = vertex->coordinates[2];
if (maxPosition[0] < vertex->coordinates[0])
maxPosition[0] = vertex->coordinates[0];
if (maxPosition[1] < vertex->coordinates[1])
maxPosition[1] = vertex->coordinates[1];
if (maxPosition[2] < vertex->coordinates[2])
maxPosition[2] = vertex->coordinates[2];
minPosition[0] = std::min(minPosition[0], vertex->coordinates[0]);
minPosition[1] = std::min(minPosition[1], vertex->coordinates[1]);
minPosition[2] = std::min(minPosition[2], vertex->coordinates[2]);
maxPosition[0] = std::max(maxPosition[0], vertex->coordinates[0]);
maxPosition[1] = std::max(maxPosition[1], vertex->coordinates[1]);
maxPosition[2] = std::max(maxPosition[2], vertex->coordinates[2]);
vertex->normal[0] = commonVertex.normal[0];
vertex->normal[1] = commonVertex.normal[2];
@ -499,7 +500,7 @@ namespace
{
assert(xmodel.m_vertex_bone_weights.size() == xmodel.m_vertices.size());
auto* joints = reinterpret_cast<uint8_t*>(&bufferData[currentBufferOffset]);
auto* joints = &bufferData[currentBufferOffset];
auto* weights = reinterpret_cast<float*>(&bufferData[currentBufferOffset + sizeof(uint8_t) * 4u * xmodel.m_vertex_bone_weights.size()]);
for (const auto& commonVertexWeights : xmodel.m_vertex_bone_weights)
{
@ -610,7 +611,7 @@ namespace
gltf.buffers->emplace_back(std::move(jsonBuffer));
}
unsigned m_mesh_node = 0u;
unsigned m_first_mesh_node = 0u;
unsigned m_root_node = 0u;
unsigned m_first_bone_node = 0u;
unsigned m_position_accessor = 0u;

View File

@ -32,7 +32,9 @@
#include <cassert>
#include <format>
namespace GAME
using namespace GAME;
namespace
{
std::string GetFileNameForLod(const std::string& modelName, const unsigned lod, const std::string& extension)
{
@ -223,10 +225,10 @@ namespace GAME
bone.globalOffset[1] = baseMat.trans.y;
bone.globalOffset[2] = baseMat.trans.z;
bone.globalRotation = {
baseMat.quat.x,
baseMat.quat.y,
baseMat.quat.z,
baseMat.quat.w,
.x = baseMat.quat.x,
.y = baseMat.quat.y,
.z = baseMat.quat.z,
.w = baseMat.quat.w,
};
if (boneNum < model->numRootBones)
@ -234,7 +236,7 @@ namespace GAME
bone.localOffset[0] = 0;
bone.localOffset[1] = 0;
bone.localOffset[2] = 0;
bone.localRotation = {0, 0, 0, 1};
bone.localRotation = {.x = 0, .y = 0, .z = 0, .w = 1};
}
else
{
@ -245,10 +247,10 @@ namespace GAME
const auto& quat = model->quats[boneNum - model->numRootBones];
bone.localRotation = {
QuatInt16::ToFloat(quat.v[0]),
QuatInt16::ToFloat(quat.v[1]),
QuatInt16::ToFloat(quat.v[2]),
QuatInt16::ToFloat(quat.v[3]),
.x = QuatInt16::ToFloat(quat.v[0]),
.y = QuatInt16::ToFloat(quat.v[1]),
.z = QuatInt16::ToFloat(quat.v[2]),
.w = QuatInt16::ToFloat(quat.v[3]),
};
}
@ -391,7 +393,7 @@ namespace GAME
const auto& vertList = surface.vertList[vertListIndex];
const auto boneWeightOffset = weightOffset;
weightCollection.weights[weightOffset++] = XModelBoneWeight{vertList.boneOffset / sizeof(DObjSkelMat), 1.0f};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = vertList.boneOffset / sizeof(DObjSkelMat), .weight = 1.0f};
for (auto vertListVertexOffset = 0u; vertListVertexOffset < vertList.vertCount; vertListVertexOffset++)
{
@ -409,7 +411,7 @@ namespace GAME
{
const auto boneWeightOffset = weightOffset;
const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat);
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, 1.0f};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex0, .weight = 1.0f};
vertsBlendOffset += 1;
@ -425,8 +427,8 @@ namespace GAME
const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneWeight0 = 1.0f - boneWeight1;
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex0, .weight = boneWeight0};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex1, .weight = boneWeight1};
vertsBlendOffset += 3;
@ -444,9 +446,9 @@ namespace GAME
const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2;
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex2, boneWeight2};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex0, .weight = boneWeight0};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex1, .weight = boneWeight1};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex2, .weight = boneWeight2};
vertsBlendOffset += 5;
@ -466,10 +468,10 @@ namespace GAME
const auto boneWeight3 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 6]);
const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2 - boneWeight3;
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex2, boneWeight2};
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex3, boneWeight3};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex0, .weight = boneWeight0};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex1, .weight = boneWeight1};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex2, .weight = boneWeight2};
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex3, .weight = boneWeight3};
vertsBlendOffset += 7;
@ -724,7 +726,10 @@ namespace GAME
const JsonDumper dumper(context, *assetFile);
dumper.Dump(asset->Asset());
}
} // namespace
namespace GAME
{
void DumpXModel(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
{
DumpXModelJson(context, asset);