2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-05-02 00:19:35 +00:00

Merge pull request #760 from michaeloliverx/xmodel-glTF-dump-bug

fix: xmodel glTF dumps dropping `COLOR_0` vertex attributes
This commit is contained in:
Jan
2026-05-01 22:20:39 +02:00
committed by GitHub
2 changed files with 79 additions and 11 deletions
+1 -1
View File
@@ -265,7 +265,7 @@ namespace gltf
std::optional<unsigned> WEIGHTS_0; std::optional<unsigned> WEIGHTS_0;
}; };
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonMeshPrimitivesAttributes, POSITION, NORMAL, TEXCOORD_0, JOINTS_0, WEIGHTS_0); NLOHMANN_DEFINE_TYPE_EXTENSION(JsonMeshPrimitivesAttributes, POSITION, NORMAL, COLOR_0, TEXCOORD_0, JOINTS_0, WEIGHTS_0);
class JsonMeshPrimitives class JsonMeshPrimitives
{ {
+78 -10
View File
@@ -26,6 +26,11 @@ namespace
float uv[2]; float uv[2];
}; };
struct GltfVertexColorData
{
float color[4];
};
void LhcToRhcCoordinates(float (&coords)[3]) void LhcToRhcCoordinates(float (&coords)[3])
{ {
const float two[3]{coords[0], coords[1], coords[2]}; const float two[3]{coords[0], coords[1], coords[2]};
@@ -70,6 +75,22 @@ namespace
matrix = result; matrix = result;
} }
[[nodiscard]] bool HasNonDefaultColorData(const XModelCommon& xmodel)
{
for (const auto& vertex : xmodel.m_vertices)
{
if (std::abs(vertex.color[0] - 1.0f) >= std::numeric_limits<float>::epsilon()
|| std::abs(vertex.color[1] - 1.0f) >= std::numeric_limits<float>::epsilon()
|| std::abs(vertex.color[2] - 1.0f) >= std::numeric_limits<float>::epsilon()
|| std::abs(vertex.color[3] - 1.0f) >= std::numeric_limits<float>::epsilon())
{
return true;
}
}
return false;
}
class GltfWriterImpl final : public gltf::Writer class GltfWriterImpl final : public gltf::Writer
{ {
public: public:
@@ -85,17 +106,19 @@ namespace
JsonRoot gltf; JsonRoot gltf;
std::vector<uint8_t> bufferData; std::vector<uint8_t> bufferData;
const auto hasNonDefaultColorData = HasNonDefaultColorData(xmodel);
CreateJsonAsset(gltf.asset); CreateJsonAsset(gltf.asset);
CreateSkeletonNodes(gltf, xmodel); CreateSkeletonNodes(gltf, xmodel);
CreateMeshNodes(gltf, xmodel); CreateMeshNodes(gltf, xmodel);
CreateRootNode(gltf, xmodel); CreateRootNode(gltf, xmodel);
CreateMaterials(gltf, xmodel); CreateMaterials(gltf, xmodel);
CreateBufferViews(gltf, xmodel); CreateBufferViews(gltf, xmodel, hasNonDefaultColorData);
CreateAccessors(gltf, xmodel); CreateAccessors(gltf, xmodel, hasNonDefaultColorData);
CreateSkin(gltf, xmodel); CreateSkin(gltf, xmodel);
CreateMeshes(gltf, xmodel); CreateMeshes(gltf, xmodel, hasNonDefaultColorData);
CreateScene(gltf, xmodel); CreateScene(gltf, xmodel);
FillBufferData(gltf, xmodel, bufferData); FillBufferData(gltf, xmodel, bufferData, hasNonDefaultColorData);
CreateBuffer(gltf, xmodel, bufferData); CreateBuffer(gltf, xmodel, bufferData);
const ordered_json jRoot = gltf; const ordered_json jRoot = gltf;
@@ -173,7 +196,7 @@ namespace
gltf.nodes->emplace_back(std::move(rootNode)); gltf.nodes->emplace_back(std::move(rootNode));
} }
void CreateMeshes(JsonRoot& gltf, const XModelCommon& xmodel) void CreateMeshes(JsonRoot& gltf, const XModelCommon& xmodel, const bool hasNonDefaultColorData)
{ {
if (!gltf.meshes.has_value()) if (!gltf.meshes.has_value())
gltf.meshes.emplace(); gltf.meshes.emplace();
@@ -190,6 +213,8 @@ namespace
primitives.attributes.POSITION = m_position_accessor; primitives.attributes.POSITION = m_position_accessor;
primitives.attributes.NORMAL = m_normal_accessor; primitives.attributes.NORMAL = m_normal_accessor;
if (hasNonDefaultColorData)
primitives.attributes.COLOR_0 = m_color_accessor;
primitives.attributes.TEXCOORD_0 = m_uv_accessor; primitives.attributes.TEXCOORD_0 = m_uv_accessor;
if (hasBoneWeightData) if (hasBoneWeightData)
@@ -368,7 +393,7 @@ namespace
gltf.scene = 0u; gltf.scene = 0u;
} }
void CreateBufferViews(JsonRoot& gltf, const XModelCommon& xmodel) void CreateBufferViews(JsonRoot& gltf, const XModelCommon& xmodel, const bool hasNonDefaultColorData)
{ {
if (!gltf.bufferViews.has_value()) if (!gltf.bufferViews.has_value())
gltf.bufferViews.emplace(); gltf.bufferViews.emplace();
@@ -386,6 +411,19 @@ namespace
m_vertex_buffer_view = static_cast<unsigned>(gltf.bufferViews->size()); m_vertex_buffer_view = static_cast<unsigned>(gltf.bufferViews->size());
gltf.bufferViews->emplace_back(vertexBufferView); gltf.bufferViews->emplace_back(vertexBufferView);
if (hasNonDefaultColorData)
{
JsonBufferView colorBufferView;
colorBufferView.buffer = 0u;
colorBufferView.byteOffset = bufferOffset;
colorBufferView.byteLength = static_cast<unsigned>(sizeof(GltfVertexColorData) * xmodel.m_vertices.size());
colorBufferView.target = JsonBufferViewTarget::ARRAY_BUFFER;
bufferOffset += colorBufferView.byteLength;
m_color_buffer_view = static_cast<unsigned>(gltf.bufferViews->size());
gltf.bufferViews->emplace_back(colorBufferView);
}
if (!xmodel.m_bone_weight_data.weights.empty()) if (!xmodel.m_bone_weight_data.weights.empty())
{ {
JsonBufferView jointsBufferView; JsonBufferView jointsBufferView;
@@ -432,7 +470,7 @@ namespace
} }
} }
void CreateAccessors(JsonRoot& gltf, const XModelCommon& xmodel) void CreateAccessors(JsonRoot& gltf, const XModelCommon& xmodel, const bool hasNonDefaultColorData)
{ {
if (!gltf.accessors.has_value()) if (!gltf.accessors.has_value())
gltf.accessors.emplace(); gltf.accessors.emplace();
@@ -455,6 +493,17 @@ namespace
m_normal_accessor = static_cast<unsigned>(gltf.accessors->size()); m_normal_accessor = static_cast<unsigned>(gltf.accessors->size());
gltf.accessors->emplace_back(normalAccessor); gltf.accessors->emplace_back(normalAccessor);
if (hasNonDefaultColorData)
{
JsonAccessor colorAccessor;
colorAccessor.bufferView = m_color_buffer_view;
colorAccessor.componentType = JsonAccessorComponentType::FLOAT;
colorAccessor.count = static_cast<unsigned>(xmodel.m_vertices.size());
colorAccessor.type = JsonAccessorType::VEC4;
m_color_accessor = static_cast<unsigned>(gltf.accessors->size());
gltf.accessors->emplace_back(colorAccessor);
}
JsonAccessor uvAccessor; JsonAccessor uvAccessor;
uvAccessor.bufferView = m_vertex_buffer_view; uvAccessor.bufferView = m_vertex_buffer_view;
uvAccessor.byteOffset = static_cast<unsigned>(offsetof(GltfVertex, uv)); uvAccessor.byteOffset = static_cast<unsigned>(offsetof(GltfVertex, uv));
@@ -506,9 +555,9 @@ namespace
} }
} }
void FillBufferData(JsonRoot& gltf, const XModelCommon& xmodel, std::vector<uint8_t>& bufferData) const void FillBufferData(JsonRoot& gltf, const XModelCommon& xmodel, std::vector<uint8_t>& bufferData, const bool hasNonDefaultColorData) const
{ {
const auto expectedBufferSize = GetExpectedBufferSize(xmodel); const auto expectedBufferSize = GetExpectedBufferSize(xmodel, hasNonDefaultColorData);
bufferData.resize(expectedBufferSize); bufferData.resize(expectedBufferSize);
auto currentBufferOffset = 0uz; auto currentBufferOffset = 0uz;
@@ -557,6 +606,20 @@ namespace
gltf.accessors.value()[m_position_accessor].max = std::vector({maxPosition[0], maxPosition[1], maxPosition[2]}); gltf.accessors.value()[m_position_accessor].max = std::vector({maxPosition[0], maxPosition[1], maxPosition[2]});
} }
if (hasNonDefaultColorData)
{
for (const auto& commonVertex : xmodel.m_vertices)
{
auto* colorData = reinterpret_cast<GltfVertexColorData*>(&bufferData[currentBufferOffset]);
colorData->color[0] = commonVertex.color[0];
colorData->color[1] = commonVertex.color[1];
colorData->color[2] = commonVertex.color[2];
colorData->color[3] = commonVertex.color[3];
currentBufferOffset += sizeof(GltfVertexColorData);
}
}
if (!xmodel.m_bone_weight_data.weights.empty()) if (!xmodel.m_bone_weight_data.weights.empty())
{ {
assert(xmodel.m_vertex_bone_weights.size() == xmodel.m_vertices.size()); assert(xmodel.m_vertex_bone_weights.size() == xmodel.m_vertices.size());
@@ -639,12 +702,15 @@ namespace
assert(expectedBufferSize == currentBufferOffset); assert(expectedBufferSize == currentBufferOffset);
} }
static size_t GetExpectedBufferSize(const XModelCommon& xmodel) static size_t GetExpectedBufferSize(const XModelCommon& xmodel, const bool hasNonDefaultColorData)
{ {
auto result = 0uz; auto result = 0uz;
result += xmodel.m_vertices.size() * sizeof(GltfVertex); result += xmodel.m_vertices.size() * sizeof(GltfVertex);
if (hasNonDefaultColorData)
result += xmodel.m_vertices.size() * sizeof(GltfVertexColorData);
if (!xmodel.m_bone_weight_data.weights.empty()) if (!xmodel.m_bone_weight_data.weights.empty())
{ {
// Joints and weights // Joints and weights
@@ -681,11 +747,13 @@ namespace
unsigned m_first_bone_node = 0u; unsigned m_first_bone_node = 0u;
unsigned m_position_accessor = 0u; unsigned m_position_accessor = 0u;
unsigned m_normal_accessor = 0u; unsigned m_normal_accessor = 0u;
unsigned m_color_accessor = 0u;
unsigned m_uv_accessor = 0u; unsigned m_uv_accessor = 0u;
unsigned m_joints_accessor = 0u; unsigned m_joints_accessor = 0u;
unsigned m_weights_accessor = 0u; unsigned m_weights_accessor = 0u;
unsigned m_inverse_bind_matrices_accessor = 0u; unsigned m_inverse_bind_matrices_accessor = 0u;
unsigned m_vertex_buffer_view = 0u; unsigned m_vertex_buffer_view = 0u;
unsigned m_color_buffer_view = 0u;
unsigned m_joints_buffer_view = 0u; unsigned m_joints_buffer_view = 0u;
unsigned m_weights_buffer_view = 0u; unsigned m_weights_buffer_view = 0u;
unsigned m_inverse_bind_matrices_buffer_view = 0u; unsigned m_inverse_bind_matrices_buffer_view = 0u;