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>
|
#include <Eigen>
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <format>
|
#include <format>
|
||||||
|
|
||||||
using namespace gltf;
|
using namespace gltf;
|
||||||
@ -41,13 +42,13 @@ namespace
|
|||||||
|
|
||||||
CreateJsonAsset(gltf.asset);
|
CreateJsonAsset(gltf.asset);
|
||||||
CreateSkeletonNodes(gltf, xmodel);
|
CreateSkeletonNodes(gltf, xmodel);
|
||||||
CreateMeshNode(gltf, xmodel);
|
CreateMeshNodes(gltf, xmodel);
|
||||||
CreateRootNode(gltf, xmodel);
|
CreateRootNode(gltf, xmodel);
|
||||||
CreateMaterials(gltf, xmodel);
|
CreateMaterials(gltf, xmodel);
|
||||||
CreateBufferViews(gltf, xmodel);
|
CreateBufferViews(gltf, xmodel);
|
||||||
CreateAccessors(gltf, xmodel);
|
CreateAccessors(gltf, xmodel);
|
||||||
CreateSkin(gltf, xmodel);
|
CreateSkin(gltf, xmodel);
|
||||||
CreateMesh(gltf, xmodel);
|
CreateMeshes(gltf, xmodel);
|
||||||
CreateScene(gltf, xmodel);
|
CreateScene(gltf, xmodel);
|
||||||
FillBufferData(gltf, xmodel, bufferData);
|
FillBufferData(gltf, xmodel, bufferData);
|
||||||
CreateBuffer(gltf, xmodel, bufferData);
|
CreateBuffer(gltf, xmodel, bufferData);
|
||||||
@ -68,39 +69,44 @@ namespace
|
|||||||
asset.generator = GLTF_GENERATOR;
|
asset.generator = GLTF_GENERATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateMeshNode(JsonRoot& gltf, const XModelCommon& xmodel)
|
void CreateMeshNodes(JsonRoot& gltf, const XModelCommon& xmodel)
|
||||||
{
|
{
|
||||||
JsonNode meshNode;
|
|
||||||
|
|
||||||
if (!xmodel.m_name.empty())
|
|
||||||
meshNode.name = xmodel.m_name;
|
|
||||||
|
|
||||||
// We only have one mesh
|
|
||||||
meshNode.mesh = 0u;
|
|
||||||
|
|
||||||
// Only add skin if the model has bones
|
|
||||||
if (!xmodel.m_bones.empty())
|
|
||||||
{
|
|
||||||
// We only have one skin
|
|
||||||
meshNode.skin = 0u;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gltf.nodes.has_value())
|
if (!gltf.nodes.has_value())
|
||||||
gltf.nodes.emplace();
|
gltf.nodes.emplace();
|
||||||
|
|
||||||
m_mesh_node = gltf.nodes->size();
|
m_first_mesh_node = gltf.nodes->size();
|
||||||
|
|
||||||
if (xmodel.m_bones.empty())
|
auto meshIndex = 0u;
|
||||||
m_root_node = m_mesh_node;
|
for (const auto& object : xmodel.m_objects)
|
||||||
|
{
|
||||||
|
JsonNode meshNode;
|
||||||
|
|
||||||
gltf.nodes->emplace_back(std::move(meshNode));
|
if (!object.name.empty())
|
||||||
|
meshNode.name = object.name;
|
||||||
|
|
||||||
|
meshNode.mesh = meshIndex++;
|
||||||
|
|
||||||
|
// Only add skin if the model has bones
|
||||||
|
if (!xmodel.m_bones.empty())
|
||||||
|
{
|
||||||
|
// We only have one skin
|
||||||
|
meshNode.skin = 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
void CreateRootNode(JsonRoot& gltf, const XModelCommon& xmodel)
|
||||||
{
|
{
|
||||||
JsonNode rootNode;
|
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;
|
return;
|
||||||
|
|
||||||
if (!xmodel.m_name.empty())
|
if (!xmodel.m_name.empty())
|
||||||
@ -110,29 +116,31 @@ namespace
|
|||||||
gltf.nodes.emplace();
|
gltf.nodes.emplace();
|
||||||
|
|
||||||
rootNode.children.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);
|
rootNode.children->push_back(m_first_bone_node);
|
||||||
|
|
||||||
m_root_node = gltf.nodes->size();
|
m_root_node = gltf.nodes->size();
|
||||||
gltf.nodes->emplace_back(std::move(rootNode));
|
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())
|
if (!gltf.meshes.has_value())
|
||||||
gltf.meshes.emplace();
|
gltf.meshes.emplace();
|
||||||
|
|
||||||
JsonMesh mesh;
|
|
||||||
|
|
||||||
const auto hasBoneWeightData = !xmodel.m_bone_weight_data.weights.empty();
|
const auto hasBoneWeightData = !xmodel.m_bone_weight_data.weights.empty();
|
||||||
|
|
||||||
auto objectIndex = 0u;
|
auto objectIndex = 0u;
|
||||||
for (const auto& object : xmodel.m_objects)
|
for (const auto& object : xmodel.m_objects)
|
||||||
{
|
{
|
||||||
|
JsonMesh mesh;
|
||||||
JsonMeshPrimitives primitives;
|
JsonMeshPrimitives primitives;
|
||||||
|
|
||||||
if (object.materialIndex >= 0)
|
primitives.material = object.materialIndex;
|
||||||
primitives.material = static_cast<unsigned>(object.materialIndex);
|
|
||||||
|
|
||||||
primitives.attributes.POSITION = m_position_accessor;
|
primitives.attributes.POSITION = m_position_accessor;
|
||||||
primitives.attributes.NORMAL = m_normal_accessor;
|
primitives.attributes.NORMAL = m_normal_accessor;
|
||||||
@ -149,9 +157,8 @@ namespace
|
|||||||
|
|
||||||
mesh.primitives.emplace_back(primitives);
|
mesh.primitives.emplace_back(primitives);
|
||||||
objectIndex++;
|
objectIndex++;
|
||||||
|
gltf.meshes->emplace_back(std::move(mesh));
|
||||||
}
|
}
|
||||||
|
|
||||||
gltf.meshes->emplace_back(std::move(mesh));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CreateMaterials(JsonRoot& gltf, const XModelCommon& xmodel)
|
static void CreateMaterials(JsonRoot& gltf, const XModelCommon& xmodel)
|
||||||
@ -466,18 +473,12 @@ namespace
|
|||||||
vertex->coordinates[1] = commonVertex.coordinates[2];
|
vertex->coordinates[1] = commonVertex.coordinates[2];
|
||||||
vertex->coordinates[2] = -commonVertex.coordinates[1];
|
vertex->coordinates[2] = -commonVertex.coordinates[1];
|
||||||
|
|
||||||
if (minPosition[0] > vertex->coordinates[0])
|
minPosition[0] = std::min(minPosition[0], vertex->coordinates[0]);
|
||||||
minPosition[0] = vertex->coordinates[0];
|
minPosition[1] = std::min(minPosition[1], vertex->coordinates[1]);
|
||||||
if (minPosition[1] > vertex->coordinates[1])
|
minPosition[2] = std::min(minPosition[2], vertex->coordinates[2]);
|
||||||
minPosition[1] = vertex->coordinates[1];
|
maxPosition[0] = std::max(maxPosition[0], vertex->coordinates[0]);
|
||||||
if (minPosition[2] > vertex->coordinates[2])
|
maxPosition[1] = std::max(maxPosition[1], vertex->coordinates[1]);
|
||||||
minPosition[2] = vertex->coordinates[2];
|
maxPosition[2] = std::max(maxPosition[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];
|
|
||||||
|
|
||||||
vertex->normal[0] = commonVertex.normal[0];
|
vertex->normal[0] = commonVertex.normal[0];
|
||||||
vertex->normal[1] = commonVertex.normal[2];
|
vertex->normal[1] = commonVertex.normal[2];
|
||||||
@ -499,7 +500,7 @@ namespace
|
|||||||
{
|
{
|
||||||
assert(xmodel.m_vertex_bone_weights.size() == xmodel.m_vertices.size());
|
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()]);
|
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)
|
for (const auto& commonVertexWeights : xmodel.m_vertex_bone_weights)
|
||||||
{
|
{
|
||||||
@ -610,7 +611,7 @@ namespace
|
|||||||
gltf.buffers->emplace_back(std::move(jsonBuffer));
|
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_root_node = 0u;
|
||||||
unsigned m_first_bone_node = 0u;
|
unsigned m_first_bone_node = 0u;
|
||||||
unsigned m_position_accessor = 0u;
|
unsigned m_position_accessor = 0u;
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <format>
|
#include <format>
|
||||||
|
|
||||||
namespace GAME
|
using namespace GAME;
|
||||||
|
|
||||||
|
namespace
|
||||||
{
|
{
|
||||||
std::string GetFileNameForLod(const std::string& modelName, const unsigned lod, const std::string& extension)
|
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[1] = baseMat.trans.y;
|
||||||
bone.globalOffset[2] = baseMat.trans.z;
|
bone.globalOffset[2] = baseMat.trans.z;
|
||||||
bone.globalRotation = {
|
bone.globalRotation = {
|
||||||
baseMat.quat.x,
|
.x = baseMat.quat.x,
|
||||||
baseMat.quat.y,
|
.y = baseMat.quat.y,
|
||||||
baseMat.quat.z,
|
.z = baseMat.quat.z,
|
||||||
baseMat.quat.w,
|
.w = baseMat.quat.w,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (boneNum < model->numRootBones)
|
if (boneNum < model->numRootBones)
|
||||||
@ -234,7 +236,7 @@ namespace GAME
|
|||||||
bone.localOffset[0] = 0;
|
bone.localOffset[0] = 0;
|
||||||
bone.localOffset[1] = 0;
|
bone.localOffset[1] = 0;
|
||||||
bone.localOffset[2] = 0;
|
bone.localOffset[2] = 0;
|
||||||
bone.localRotation = {0, 0, 0, 1};
|
bone.localRotation = {.x = 0, .y = 0, .z = 0, .w = 1};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -245,10 +247,10 @@ namespace GAME
|
|||||||
|
|
||||||
const auto& quat = model->quats[boneNum - model->numRootBones];
|
const auto& quat = model->quats[boneNum - model->numRootBones];
|
||||||
bone.localRotation = {
|
bone.localRotation = {
|
||||||
QuatInt16::ToFloat(quat.v[0]),
|
.x = QuatInt16::ToFloat(quat.v[0]),
|
||||||
QuatInt16::ToFloat(quat.v[1]),
|
.y = QuatInt16::ToFloat(quat.v[1]),
|
||||||
QuatInt16::ToFloat(quat.v[2]),
|
.z = QuatInt16::ToFloat(quat.v[2]),
|
||||||
QuatInt16::ToFloat(quat.v[3]),
|
.w = QuatInt16::ToFloat(quat.v[3]),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +393,7 @@ namespace GAME
|
|||||||
const auto& vertList = surface.vertList[vertListIndex];
|
const auto& vertList = surface.vertList[vertListIndex];
|
||||||
const auto boneWeightOffset = weightOffset;
|
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++)
|
for (auto vertListVertexOffset = 0u; vertListVertexOffset < vertList.vertCount; vertListVertexOffset++)
|
||||||
{
|
{
|
||||||
@ -409,7 +411,7 @@ namespace GAME
|
|||||||
{
|
{
|
||||||
const auto boneWeightOffset = weightOffset;
|
const auto boneWeightOffset = weightOffset;
|
||||||
const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat);
|
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;
|
vertsBlendOffset += 1;
|
||||||
|
|
||||||
@ -425,8 +427,8 @@ namespace GAME
|
|||||||
const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
|
const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
|
||||||
const auto boneWeight0 = 1.0f - boneWeight1;
|
const auto boneWeight0 = 1.0f - boneWeight1;
|
||||||
|
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex0, .weight = boneWeight0};
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex1, .weight = boneWeight1};
|
||||||
|
|
||||||
vertsBlendOffset += 3;
|
vertsBlendOffset += 3;
|
||||||
|
|
||||||
@ -444,9 +446,9 @@ namespace GAME
|
|||||||
const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
|
const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
|
||||||
const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2;
|
const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2;
|
||||||
|
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex0, .weight = boneWeight0};
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex1, .weight = boneWeight1};
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex2, boneWeight2};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex2, .weight = boneWeight2};
|
||||||
|
|
||||||
vertsBlendOffset += 5;
|
vertsBlendOffset += 5;
|
||||||
|
|
||||||
@ -466,10 +468,10 @@ namespace GAME
|
|||||||
const auto boneWeight3 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 6]);
|
const auto boneWeight3 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 6]);
|
||||||
const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2 - boneWeight3;
|
const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2 - boneWeight3;
|
||||||
|
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex0, .weight = boneWeight0};
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex1, .weight = boneWeight1};
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex2, boneWeight2};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex2, .weight = boneWeight2};
|
||||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex3, boneWeight3};
|
weightCollection.weights[weightOffset++] = XModelBoneWeight{.boneIndex = boneIndex3, .weight = boneWeight3};
|
||||||
|
|
||||||
vertsBlendOffset += 7;
|
vertsBlendOffset += 7;
|
||||||
|
|
||||||
@ -724,7 +726,10 @@ namespace GAME
|
|||||||
const JsonDumper dumper(context, *assetFile);
|
const JsonDumper dumper(context, *assetFile);
|
||||||
dumper.Dump(asset->Asset());
|
dumper.Dump(asset->Asset());
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace GAME
|
||||||
|
{
|
||||||
void DumpXModel(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
void DumpXModel(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||||
{
|
{
|
||||||
DumpXModelJson(context, asset);
|
DumpXModelJson(context, asset);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user