mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-19 15:52:53 +00:00
Merge pull request #358 from Laupetin/feature/gltf-separate-meshes
feat: separate objects into gltf meshes instead of primitives
This commit is contained in:
commit
f6d36b2d6e
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user