Merge pull request #395 from Laupetin/fix/bad-xmodel-loading

fix: bad xmodel loading
This commit is contained in:
Jan 2025-04-05 17:59:45 +02:00 committed by GitHub
commit d3bb99e92c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 40 additions and 33 deletions

View File

@ -286,7 +286,7 @@ namespace
common.m_vertices.emplace_back(vertex); common.m_vertices.emplace_back(vertex);
XModelVertexBoneWeights vertexWeights{common.m_bone_weight_data.weights.size(), 0u}; XModelVertexBoneWeights vertexWeights{.weightOffset = common.m_bone_weight_data.weights.size(), .weightCount = 0u};
for (auto i = 0u; i < std::extent_v<decltype(joints)>; i++) for (auto i = 0u; i < std::extent_v<decltype(joints)>; i++)
{ {
if (std::abs(weights[i]) < std::numeric_limits<float>::epsilon()) if (std::abs(weights[i]) < std::numeric_limits<float>::epsilon())
@ -315,12 +315,12 @@ namespace
throw GltfLoadException("Requires primitives attribute POSITION"); throw GltfLoadException("Requires primitives attribute POSITION");
AccessorsForVertex accessorsForVertex{ AccessorsForVertex accessorsForVertex{
*primitives.attributes.POSITION, .positionAccessor = *primitives.attributes.POSITION,
primitives.attributes.NORMAL, .normalAccessor = primitives.attributes.NORMAL,
primitives.attributes.COLOR_0, .colorAccessor = primitives.attributes.COLOR_0,
primitives.attributes.TEXCOORD_0, .uvAccessor = primitives.attributes.TEXCOORD_0,
primitives.attributes.JOINTS_0, .jointsAccessor = primitives.attributes.JOINTS_0,
primitives.attributes.WEIGHTS_0, .weightsAccessor = primitives.attributes.WEIGHTS_0,
}; };
const auto existingVertices = m_vertex_offset_for_accessors.find(accessorsForVertex); const auto existingVertices = m_vertex_offset_for_accessors.find(accessorsForVertex);
@ -328,7 +328,7 @@ namespace
existingVertices == m_vertex_offset_for_accessors.end() ? CreateVertices(common, accessorsForVertex) : existingVertices->second; existingVertices == m_vertex_offset_for_accessors.end() ? CreateVertices(common, accessorsForVertex) : existingVertices->second;
// clang-format off // clang-format off
auto* indexAccessor = GetAccessorForIndex( const auto* indexAccessor = GetAccessorForIndex(
"INDICES", "INDICES",
primitives.indices, primitives.indices,
{JsonAccessorType::SCALAR}, {JsonAccessorType::SCALAR},
@ -552,7 +552,7 @@ namespace
common.m_bones.resize(skinBoneOffset + skin.joints.size()); common.m_bones.resize(skinBoneOffset + skin.joints.size());
constexpr float defaultTranslation[3]{0.0f, 0.0f, 0.0f}; constexpr float defaultTranslation[3]{0.0f, 0.0f, 0.0f};
constexpr XModelQuaternion defaultRotation{0.0f, 0.0f, 0.0f, 1.0f}; constexpr XModelQuaternion defaultRotation{.x = 0.0f, .y = 0.0f, .z = 0.0f, .w = 1.0f};
constexpr float defaultScale[3]{1.0f, 1.0f, 1.0f}; constexpr float defaultScale[3]{1.0f, 1.0f, 1.0f};
return ConvertJoint(jRoot, skin, common, skinBoneOffset, rootNode, std::nullopt, defaultTranslation, defaultRotation, defaultScale); return ConvertJoint(jRoot, skin, common, skinBoneOffset, rootNode, std::nullopt, defaultTranslation, defaultRotation, defaultScale);

View File

@ -22,7 +22,6 @@
#include JSON_HEADER #include JSON_HEADER
#include "Asset/AssetRegistration.h" #include "Asset/AssetRegistration.h"
#include "ObjLoading.h"
#include "Utils/QuatInt16.h" #include "Utils/QuatInt16.h"
#include "Utils/StringUtils.h" #include "Utils/StringUtils.h"
#include "XModel/Gltf/GltfBinInput.h" #include "XModel/Gltf/GltfBinInput.h"
@ -44,7 +43,6 @@
#include <format> #include <format>
#include <iostream> #include <iostream>
#include <numeric> #include <numeric>
#include <set>
#include <vector> #include <vector>
using namespace GAME; using namespace GAME;
@ -146,17 +144,17 @@ namespace
assert(common.m_vertex_bone_weights.size() == common.m_vertices.size()); assert(common.m_vertex_bone_weights.size() == common.m_vertices.size());
XModelBone rootBone{ XModelBone rootBone{
"root", .name = "root",
std::nullopt, .parentIndex = std::nullopt,
{1.0f, 1.0f, 1.0f}, .scale = {1.0f, 1.0f, 1.0f},
{0.0f, 0.0f, 0.0f}, .globalOffset = {0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f}, .localOffset = {0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}, .globalRotation = {.x = 0.0f, .y = 0.0f, .z = 0.0f, .w = 1.0f},
{0.0f, 0.0f, 0.0f, 1.0f}, .localRotation = {.x = 0.0f, .y = 0.0f, .z = 0.0f, .w = 1.0f},
}; };
common.m_bones.emplace_back(rootBone); common.m_bones.emplace_back(rootBone);
XModelBoneWeight rootWeight{0, 1.0f}; XModelBoneWeight rootWeight{.boneIndex = 0, .weight = 1.0f};
common.m_bone_weight_data.weights.emplace_back(rootWeight); common.m_bone_weight_data.weights.emplace_back(rootWeight);
for (auto& vertexBoneWeights : common.m_vertex_bone_weights) for (auto& vertexBoneWeights : common.m_vertex_bone_weights)
@ -401,7 +399,7 @@ namespace
} }
static std::vector<std::optional<size_t>> static std::vector<std::optional<size_t>>
GetRigidBoneIndicesForTris(const std::vector<size_t>& vertexIndices, XSurface& surface, const XModelCommon& common) GetRigidBoneIndicesForTris(const std::vector<size_t>& vertexIndices, const XSurface& surface, const XModelCommon& common)
{ {
std::vector<std::optional<size_t>> rigidBoneIndexForTri; std::vector<std::optional<size_t>> rigidBoneIndexForTri;
rigidBoneIndexForTri.reserve(surface.triCount); rigidBoneIndexForTri.reserve(surface.triCount);
@ -422,7 +420,7 @@ namespace
return rigidBoneIndexForTri; return rigidBoneIndexForTri;
} }
static void ReorderRigidTrisByBoneIndex(const std::vector<size_t>& vertexIndices, XSurface& surface, const XModelCommon& common) static void ReorderRigidTrisByBoneIndex(const std::vector<size_t>& vertexIndices, const XSurface& surface, const XModelCommon& common)
{ {
const auto rigidBoneIndexForTri = GetRigidBoneIndicesForTris(vertexIndices, surface, common); const auto rigidBoneIndexForTri = GetRigidBoneIndicesForTris(vertexIndices, surface, common);
@ -456,17 +454,17 @@ namespace
surface.partBits[partBitsIndex] |= 1 << shiftValue; surface.partBits[partBitsIndex] |= 1 << shiftValue;
} }
void CreateVertListData(XSurface& surface, const std::vector<size_t>& vertexIndices, const XModelCommon& common) const void CreateVertListData(XSurface& surface, const std::vector<size_t>& xmodelToCommonVertexIndexLookup, const XModelCommon& common) const
{ {
ReorderRigidTrisByBoneIndex(vertexIndices, surface, common); ReorderRigidTrisByBoneIndex(xmodelToCommonVertexIndexLookup, surface, common);
const auto rigidBoneIndexForTri = GetRigidBoneIndicesForTris(vertexIndices, surface, common); const auto rigidBoneIndexForTri = GetRigidBoneIndicesForTris(xmodelToCommonVertexIndexLookup, surface, common);
std::vector<XRigidVertList> vertLists; std::vector<XRigidVertList> vertLists;
auto currentVertexTail = 0u; auto currentVertexTail = 0u;
auto currentTriTail = 0u; auto currentTriTail = 0u;
const auto vertexCount = vertexIndices.size(); const auto vertexCount = xmodelToCommonVertexIndexLookup.size();
const auto triCount = static_cast<size_t>(surface.triCount); const auto triCount = static_cast<size_t>(surface.triCount);
const auto boneCount = common.m_bones.size(); const auto boneCount = common.m_bones.size();
for (auto boneIndex = 0u; boneIndex < boneCount; boneIndex++) for (auto boneIndex = 0u; boneIndex < boneCount; boneIndex++)
@ -475,7 +473,7 @@ namespace
boneVertList.boneOffset = static_cast<uint16_t>(boneIndex * sizeof(DObjSkelMat)); boneVertList.boneOffset = static_cast<uint16_t>(boneIndex * sizeof(DObjSkelMat));
auto currentVertexHead = currentVertexTail; auto currentVertexHead = currentVertexTail;
while (currentVertexHead < vertexCount && GetRigidBoneForVertex(currentVertexHead, common) == boneIndex) while (currentVertexHead < vertexCount && GetRigidBoneForVertex(xmodelToCommonVertexIndexLookup[currentVertexHead], common) == boneIndex)
currentVertexHead++; currentVertexHead++;
auto currentTriHead = currentTriTail; auto currentTriHead = currentTriTail;
@ -512,7 +510,7 @@ namespace
// TODO // TODO
} }
static void ReorderVerticesByWeightCount(std::vector<size_t>& vertexIndices, XSurface& surface, const XModelCommon& common) static void ReorderVerticesByWeightCount(std::vector<size_t>& vertexIndices, const XSurface& surface, const XModelCommon& common)
{ {
if (common.m_bone_weight_data.weights.empty()) if (common.m_bone_weight_data.weights.empty())
return; return;
@ -541,13 +539,21 @@ namespace
return false; return false;
}); });
std::vector<XSurfaceTri> preSortTris(surface.triCount);
std::memcpy(preSortTris.data(), surface.triIndices, sizeof(XSurfaceTri) * surface.triCount);
std::vector<size_t> reverseLookup(reorderLookup.size());
for (auto i = 0u; i < reverseLookup.size(); i++)
reverseLookup[reorderLookup[i]] = i;
for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++) for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++)
{ {
const auto& preSortTriIndices = preSortTris[triIndex];
auto& triIndices = surface.triIndices[triIndex]; auto& triIndices = surface.triIndices[triIndex];
triIndices.i[0] = static_cast<uint16_t>(reorderLookup[triIndices.i[0]]); triIndices.i[0] = static_cast<uint16_t>(reverseLookup[preSortTriIndices.i[0]]);
triIndices.i[1] = static_cast<uint16_t>(reorderLookup[triIndices.i[1]]); triIndices.i[1] = static_cast<uint16_t>(reverseLookup[preSortTriIndices.i[1]]);
triIndices.i[2] = static_cast<uint16_t>(reorderLookup[triIndices.i[2]]); triIndices.i[2] = static_cast<uint16_t>(reverseLookup[preSortTriIndices.i[2]]);
} }
for (auto& entry : reorderLookup) for (auto& entry : reorderLookup)
@ -572,6 +578,7 @@ namespace
surface.triCount = static_cast<uint16_t>(commonObject.m_faces.size()); surface.triCount = static_cast<uint16_t>(commonObject.m_faces.size());
surface.triIndices = m_memory.Alloc<XSurfaceTri>(surface.triCount); surface.triIndices = m_memory.Alloc<XSurfaceTri>(surface.triCount);
xmodelToCommonVertexIndexLookup.reserve(static_cast<size_t>(surface.triCount) * std::extent_v<decltype(XModelFace::vertexIndex)>);
for (auto faceIndex = 0u; faceIndex < surface.triCount; faceIndex++) for (auto faceIndex = 0u; faceIndex < surface.triCount; faceIndex++)
{ {
const auto& face = commonObject.m_faces[faceIndex]; const auto& face = commonObject.m_faces[faceIndex];
@ -594,8 +601,6 @@ namespace
} }
} }
ReorderVerticesByWeightCount(xmodelToCommonVertexIndexLookup, surface, common);
constexpr auto maxVertices = std::numeric_limits<decltype(XSurface::vertCount)>::max(); constexpr auto maxVertices = std::numeric_limits<decltype(XSurface::vertCount)>::max();
if (vertexOffset + xmodelToCommonVertexIndexLookup.size() > maxVertices) if (vertexOffset + xmodelToCommonVertexIndexLookup.size() > maxVertices)
{ {
@ -603,6 +608,8 @@ namespace
return false; return false;
} }
ReorderVerticesByWeightCount(xmodelToCommonVertexIndexLookup, surface, common);
surface.baseVertIndex = static_cast<uint16_t>(vertexOffset); surface.baseVertIndex = static_cast<uint16_t>(vertexOffset);
surface.vertCount = static_cast<uint16_t>(xmodelToCommonVertexIndexLookup.size()); surface.vertCount = static_cast<uint16_t>(xmodelToCommonVertexIndexLookup.size());
surface.verts0 = m_memory.Alloc<GfxPackedVertex>(surface.vertCount); surface.verts0 = m_memory.Alloc<GfxPackedVertex>(surface.vertCount);