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:
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user