chore: dump gltf vertex weights

This commit is contained in:
Jan 2024-05-04 23:59:43 +02:00
parent 9ab78d5384
commit c74be5e8ae
No known key found for this signature in database
GPG Key ID: 44B581F78FF5C57C
3 changed files with 308 additions and 17 deletions

View File

@ -1,6 +1,7 @@
#include "GltfWriter.h" #include "GltfWriter.h"
#include "GitVersion.h" #include "GitVersion.h"
#include "Math/Vector.h"
#include "XModel/Gltf/GltfConstants.h" #include "XModel/Gltf/GltfConstants.h"
#include "XModel/Gltf/JsonGltf.h" #include "XModel/Gltf/JsonGltf.h"
@ -22,9 +23,6 @@ namespace
class GltfWriterImpl final : public gltf::Writer class GltfWriterImpl final : public gltf::Writer
{ {
static constexpr auto NODE_INDEX_MESH = 0u;
static constexpr auto NODE_FIRST_INDEX_BONES = 1u;
public: public:
GltfWriterImpl(const Output* output, std::string gameName, std::string zoneName) GltfWriterImpl(const Output* output, std::string gameName, std::string zoneName)
: m_output(output), : m_output(output),
@ -40,8 +38,8 @@ namespace
CreateJsonAsset(gltf.asset); CreateJsonAsset(gltf.asset);
CreateMeshNode(gltf, xmodel); CreateMeshNode(gltf, xmodel);
CreateMaterials(gltf, xmodel);
CreateSkeletonNodes(gltf, xmodel); CreateSkeletonNodes(gltf, xmodel);
CreateMaterials(gltf, xmodel);
CreateSkin(gltf, xmodel); CreateSkin(gltf, xmodel);
CreateBufferViews(gltf, xmodel); CreateBufferViews(gltf, xmodel);
CreateAccessors(gltf, xmodel); CreateAccessors(gltf, xmodel);
@ -66,7 +64,7 @@ namespace
asset.generator = GLTF_GENERATOR; asset.generator = GLTF_GENERATOR;
} }
static void CreateMeshNode(JsonRoot& gltf, const XModelCommon& xmodel) void CreateMeshNode(JsonRoot& gltf, const XModelCommon& xmodel)
{ {
JsonNode meshNode; JsonNode meshNode;
@ -83,6 +81,7 @@ namespace
if (!gltf.nodes.has_value()) if (!gltf.nodes.has_value())
gltf.nodes.emplace(); gltf.nodes.emplace();
m_mesh_node = gltf.nodes->size();
gltf.nodes->emplace_back(std::move(meshNode)); gltf.nodes->emplace_back(std::move(meshNode));
} }
@ -93,6 +92,8 @@ namespace
JsonMesh mesh; JsonMesh mesh;
const auto hasBoneWeightData = !xmodel.m_vertex_bone_weights.empty();
auto objectIndex = 0u; auto objectIndex = 0u;
for (const auto& object : xmodel.m_objects) for (const auto& object : xmodel.m_objects)
{ {
@ -105,6 +106,12 @@ namespace
primitives.attributes.NORMAL = m_normal_accessor; primitives.attributes.NORMAL = m_normal_accessor;
primitives.attributes.TEXCOORD_0 = m_uv_accessor; primitives.attributes.TEXCOORD_0 = m_uv_accessor;
if (hasBoneWeightData)
{
primitives.attributes.JOINTS_0 = m_joints_accessor;
primitives.attributes.WEIGHTS_0 = m_weights_accessor;
}
primitives.mode = JsonMeshPrimitivesMode::TRIANGLES; primitives.mode = JsonMeshPrimitivesMode::TRIANGLES;
primitives.indices = m_first_index_accessor + objectIndex; primitives.indices = m_first_index_accessor + objectIndex;
@ -136,7 +143,7 @@ namespace
} }
if (!modelMaterial.normalMapName.empty()) if (!modelMaterial.normalMapName.empty())
material.normalTexture.emplace().index = CreateTexture(gltf, modelMaterial.colorMapName); material.normalTexture.emplace().index = CreateTexture(gltf, modelMaterial.normalMapName);
material.doubleSided = true; material.doubleSided = true;
gltf.materials->emplace_back(material); gltf.materials->emplace_back(material);
@ -176,7 +183,7 @@ namespace
return textureIndex; return textureIndex;
} }
static void CreateSkeletonNodes(JsonRoot& gltf, const XModelCommon& xmodel) void CreateSkeletonNodes(JsonRoot& gltf, const XModelCommon& xmodel)
{ {
if (xmodel.m_bones.empty()) if (xmodel.m_bones.empty())
return; return;
@ -185,20 +192,32 @@ namespace
gltf.nodes.emplace(); gltf.nodes.emplace();
const auto boneCount = xmodel.m_bones.size(); const auto boneCount = xmodel.m_bones.size();
m_first_bone_node = gltf.nodes->size();
for (auto boneIndex = 0u; boneIndex < boneCount; boneIndex++) for (auto boneIndex = 0u; boneIndex < boneCount; boneIndex++)
{ {
JsonNode boneNode; JsonNode boneNode;
const auto& bone = xmodel.m_bones[boneIndex]; const auto& bone = xmodel.m_bones[boneIndex];
Vector3f translation(bone.globalOffset[0], bone.globalOffset[2], -bone.globalOffset[1]);
Quaternion32 rotation(bone.globalRotation.m_x, bone.globalRotation.m_z, -bone.globalRotation.m_y, bone.globalRotation.m_w);
if (bone.parentIndex >= 0)
{
const auto& parentBone = xmodel.m_bones[bone.parentIndex];
translation -= Vector3f(parentBone.globalOffset[0], parentBone.globalOffset[2], -parentBone.globalOffset[1]);
rotation -= Quaternion32(
parentBone.globalRotation.m_x, parentBone.globalRotation.m_z, -parentBone.globalRotation.m_y, parentBone.globalRotation.m_w);
}
rotation.Normalize();
boneNode.name = bone.name; boneNode.name = bone.name;
boneNode.translation = std::to_array(bone.globalOffset); boneNode.translation = std::to_array({translation.x(), translation.y(), translation.z()});
boneNode.rotation = std::to_array({bone.globalRotation.m_x, bone.globalRotation.m_y, bone.globalRotation.m_z, bone.globalRotation.m_w}); boneNode.rotation = std::to_array({rotation.m_x, rotation.m_y, rotation.m_z, rotation.m_w});
std::vector<unsigned> children; std::vector<unsigned> children;
for (auto maybeChildIndex = 0u; maybeChildIndex < boneCount; maybeChildIndex++) for (auto maybeChildIndex = 0u; maybeChildIndex < boneCount; maybeChildIndex++)
{ {
if (xmodel.m_bones[maybeChildIndex].parentIndex == static_cast<int>(boneIndex)) if (xmodel.m_bones[maybeChildIndex].parentIndex == static_cast<int>(boneIndex))
children.emplace_back(maybeChildIndex + NODE_FIRST_INDEX_BONES); children.emplace_back(maybeChildIndex + m_first_bone_node);
} }
if (!children.empty()) if (!children.empty())
boneNode.children = std::move(children); boneNode.children = std::move(children);
@ -207,7 +226,7 @@ namespace
} }
} }
static void CreateSkin(JsonRoot& gltf, const XModelCommon& xmodel) void CreateSkin(JsonRoot& gltf, const XModelCommon& xmodel) const
{ {
if (xmodel.m_bones.empty()) if (xmodel.m_bones.empty())
return; return;
@ -221,7 +240,7 @@ namespace
skin.joints.reserve(boneCount); skin.joints.reserve(boneCount);
for (auto boneIndex = 0u; boneIndex < boneCount; boneIndex++) for (auto boneIndex = 0u; boneIndex < boneCount; boneIndex++)
skin.joints.emplace_back(boneIndex + NODE_FIRST_INDEX_BONES); skin.joints.emplace_back(boneIndex + m_first_bone_node);
gltf.skins->emplace_back(std::move(skin)); gltf.skins->emplace_back(std::move(skin));
} }
@ -231,10 +250,7 @@ namespace
JsonScene scene; JsonScene scene;
// Only add skin if the model has bones // Only add skin if the model has bones
if (xmodel.m_bones.empty()) scene.nodes.emplace_back(m_mesh_node);
scene.nodes.emplace_back(NODE_INDEX_MESH);
else
scene.nodes.emplace_back(m_skeleton_node);
if (!gltf.scenes.has_value()) if (!gltf.scenes.has_value())
gltf.scenes.emplace(); gltf.scenes.emplace();
@ -261,6 +277,29 @@ namespace
m_vertex_buffer_view = gltf.bufferViews->size(); m_vertex_buffer_view = gltf.bufferViews->size();
gltf.bufferViews->emplace_back(vertexBufferView); gltf.bufferViews->emplace_back(vertexBufferView);
if (!xmodel.m_vertex_bone_weights.empty())
{
JsonBufferView jointsBufferView;
jointsBufferView.buffer = 0u;
jointsBufferView.byteOffset = bufferOffset;
jointsBufferView.byteLength = sizeof(uint8_t) * xmodel.m_vertices.size() * 4u;
jointsBufferView.target = JsonBufferViewTarget::ARRAY_BUFFER;
bufferOffset += jointsBufferView.byteLength;
m_joints_buffer_view = gltf.bufferViews->size();
gltf.bufferViews->emplace_back(jointsBufferView);
JsonBufferView weightsBufferView;
weightsBufferView.buffer = 0u;
weightsBufferView.byteOffset = bufferOffset;
weightsBufferView.byteLength = sizeof(float) * xmodel.m_vertices.size() * 4u;
weightsBufferView.target = JsonBufferViewTarget::ARRAY_BUFFER;
bufferOffset += weightsBufferView.byteLength;
m_weights_buffer_view = gltf.bufferViews->size();
gltf.bufferViews->emplace_back(weightsBufferView);
}
m_first_index_buffer_view = gltf.bufferViews->size(); m_first_index_buffer_view = gltf.bufferViews->size();
for (const auto& object : xmodel.m_objects) for (const auto& object : xmodel.m_objects)
{ {
@ -307,6 +346,25 @@ namespace
m_uv_accessor = gltf.accessors->size(); m_uv_accessor = gltf.accessors->size();
gltf.accessors->emplace_back(uvAccessor); gltf.accessors->emplace_back(uvAccessor);
if (!xmodel.m_vertex_bone_weights.empty())
{
JsonAccessor jointsAccessor;
jointsAccessor.bufferView = m_joints_buffer_view;
jointsAccessor.componentType = JsonAccessorComponentType::UNSIGNED_BYTE;
jointsAccessor.count = xmodel.m_vertices.size();
jointsAccessor.type = JsonAccessorType::VEC4;
m_joints_accessor = gltf.accessors->size();
gltf.accessors->emplace_back(jointsAccessor);
JsonAccessor weightsAccessor;
weightsAccessor.bufferView = m_weights_buffer_view;
weightsAccessor.componentType = JsonAccessorComponentType::FLOAT;
weightsAccessor.count = xmodel.m_vertices.size();
weightsAccessor.type = JsonAccessorType::VEC4;
m_weights_accessor = gltf.accessors->size();
gltf.accessors->emplace_back(weightsAccessor);
}
m_first_index_accessor = gltf.accessors->size(); m_first_index_accessor = gltf.accessors->size();
for (auto i = 0u; i < xmodel.m_objects.size(); i++) for (auto i = 0u; i < xmodel.m_objects.size(); i++)
{ {
@ -377,6 +435,37 @@ 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 (!xmodel.m_vertex_bone_weights.empty())
{
assert(xmodel.m_vertex_bone_weights.size() == xmodel.m_vertices.size());
auto* joints = reinterpret_cast<uint8_t*>(&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)
{
assert(commonVertexWeights.weights != nullptr);
assert(commonVertexWeights.weightCount <= 4u);
const auto commonVertexWeightCount = std::min(commonVertexWeights.weightCount, 4u);
for (auto i = 0u; i < commonVertexWeightCount; i++)
{
joints[i] = static_cast<unsigned char>(commonVertexWeights.weights[i].boneIndex);
weights[i] = commonVertexWeights.weights[i].weight;
}
for (auto i = commonVertexWeightCount; i < 4u; i++)
{
joints[i] = 0u;
weights[i] = 0.0f;
}
joints += 4u;
weights += 4u;
}
currentBufferOffset += (sizeof(uint8_t) + sizeof(float)) * 4u * xmodel.m_vertex_bone_weights.size();
}
for (const auto& object : xmodel.m_objects) for (const auto& object : xmodel.m_objects)
{ {
for (const auto& face : object.m_faces) for (const auto& face : object.m_faces)
@ -399,6 +488,11 @@ namespace
result += xmodel.m_vertices.size() * sizeof(GltfVertex); result += xmodel.m_vertices.size() * sizeof(GltfVertex);
if (!xmodel.m_vertex_bone_weights.empty())
{
result += xmodel.m_vertices.size() * 4u * (sizeof(uint8_t) + sizeof(float));
}
for (const auto& object : xmodel.m_objects) for (const auto& object : xmodel.m_objects)
{ {
result += object.m_faces.size() * sizeof(unsigned short) * 3u; result += object.m_faces.size() * sizeof(unsigned short) * 3u;
@ -421,11 +515,16 @@ namespace
gltf.buffers->emplace_back(std::move(jsonBuffer)); gltf.buffers->emplace_back(std::move(jsonBuffer));
} }
unsigned m_skeleton_node = 0u; unsigned m_mesh_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_uv_accessor = 0u; unsigned m_uv_accessor = 0u;
unsigned m_joints_accessor = 0u;
unsigned m_weights_accessor = 0u;
unsigned m_vertex_buffer_view = 0u; unsigned m_vertex_buffer_view = 0u;
unsigned m_joints_buffer_view = 0u;
unsigned m_weights_buffer_view = 0u;
unsigned m_first_index_buffer_view = 0u; unsigned m_first_index_buffer_view = 0u;
unsigned m_first_index_accessor = 0u; unsigned m_first_index_accessor = 0u;

View File

@ -51,6 +51,96 @@ public:
return Matrix<T>(m00, m01, m02, 0, m10, m11, m12, 0, m20, m21, m22, 0, 0, 0, 0, T(1.0)); return Matrix<T>(m00, m01, m02, 0, m10, m11, m12, 0, m20, m21, m22, 0, 0, 0, 0, T(1.0));
} }
static T dot(const Quaternion& q1, const Quaternion& q2)
{
return static_cast<T>((q1.m_x * q2.m_x) + (q1.m_y * q2.m_y) + (q1.m_z * q2.m_z) + (q1.m_w * q2.m_w));
}
T lengthSquared()
{
return Quaternion::dot(*this, *this);
}
T length()
{
return sqrt(lengthSquared());
}
void Normalize()
{
const auto l = length();
// return if no magnitude (already as normalized as possible)
if (l < static_cast<T>(0.0001))
return;
T inverseLength = static_cast<T>(1.0) / l;
m_x *= inverseLength;
m_y *= inverseLength;
m_z *= inverseLength;
m_w *= inverseLength;
}
friend Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs)
{
return Quaternion(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y, lhs.m_z + rhs.m_z, lhs.m_w + rhs.m_w);
}
friend Quaternion operator-(const Quaternion& lhs, const Quaternion& rhs)
{
return Quaternion(lhs.m_x - rhs.m_x, lhs.m_y - rhs.m_y, lhs.m_z - rhs.m_z, lhs.m_w - rhs.m_w);
}
friend Quaternion& operator+=(Quaternion& lhs, const Quaternion& rhs)
{
lhs.m_x += rhs.m_x;
lhs.m_y += rhs.m_y;
lhs.m_z += rhs.m_z;
lhs.m_w += rhs.m_w;
return lhs;
}
friend Quaternion& operator-=(Quaternion& lhs, const Quaternion& rhs)
{
lhs.m_x -= rhs.m_x;
lhs.m_y -= rhs.m_y;
lhs.m_z -= rhs.m_z;
lhs.m_w -= rhs.m_w;
return lhs;
}
friend Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs)
{
return Quaternion(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y, lhs.m_z + rhs.m_z, lhs.m_w + rhs.m_w);
}
friend Quaternion operator/(const Quaternion& lhs, const Quaternion& rhs)
{
return Quaternion(lhs.m_x - rhs.m_x, lhs.m_y - rhs.m_y, lhs.m_z - rhs.m_z, lhs.m_w - rhs.m_w);
}
friend Quaternion& operator*=(Quaternion& lhs, const Quaternion& rhs)
{
lhs.m_x += rhs.m_x;
lhs.m_y += rhs.m_y;
lhs.m_z += rhs.m_z;
lhs.m_w += rhs.m_w;
return lhs;
}
friend Quaternion& operator/=(Quaternion& lhs, const Quaternion& rhs)
{
lhs.m_x -= rhs.m_x;
lhs.m_y -= rhs.m_y;
lhs.m_z -= rhs.m_z;
lhs.m_w -= rhs.m_w;
return lhs;
}
}; };
typedef Quaternion<float> Quaternion32; typedef Quaternion<float> Quaternion32;

View File

@ -24,6 +24,12 @@ public:
{ {
} }
~Vector2() = default;
Vector2(const Vector2& other) = default;
Vector2(Vector2&& other) noexcept = default;
Vector2& operator=(const Vector2& other) = default;
Vector2& operator=(Vector2&& other) noexcept = default;
_NODISCARD T& operator()(const size_t index) _NODISCARD T& operator()(const size_t index)
{ {
assert(index < 2); assert(index < 2);
@ -55,6 +61,32 @@ public:
{ {
return m_value[1]; return m_value[1];
} }
friend Vector2 operator+(const Vector2& lhs, const Vector2& rhs)
{
return Vector2(lhs.m_value[0] + rhs.m_value[0], lhs.m_value[1] + rhs.m_value[1]);
}
friend Vector2 operator-(const Vector2& lhs, const Vector2& rhs)
{
return Vector2(lhs.m_value[0] - rhs.m_value[0], lhs.m_value[1] - rhs.m_value[1]);
}
friend Vector2& operator+=(Vector2& lhs, const Vector2& rhs)
{
lhs.m_value[0] += rhs.m_value[0];
lhs.m_value[1] += rhs.m_value[1];
return lhs;
}
friend Vector2& operator-=(Vector2& lhs, const Vector2& rhs)
{
lhs.m_value[0] -= rhs.m_value[0];
lhs.m_value[1] -= rhs.m_value[1];
return lhs;
}
}; };
typedef Vector2<float> Vector2f; typedef Vector2<float> Vector2f;
@ -80,6 +112,12 @@ public:
{ {
} }
~Vector3() = default;
Vector3(const Vector3& other) = default;
Vector3(Vector3&& other) noexcept = default;
Vector3& operator=(const Vector3& other) = default;
Vector3& operator=(Vector3&& other) noexcept = default;
_NODISCARD T& operator()(const size_t index) _NODISCARD T& operator()(const size_t index)
{ {
assert(index < 3); assert(index < 3);
@ -151,6 +189,34 @@ public:
{ {
return m_value[2]; return m_value[2];
} }
friend Vector3 operator+(const Vector3& lhs, const Vector3& rhs)
{
return Vector3(lhs.m_value[0] + rhs.m_value[0], lhs.m_value[1] + rhs.m_value[1], lhs.m_value[2] + rhs.m_value[2]);
}
friend Vector3 operator-(const Vector3& lhs, const Vector3& rhs)
{
return Vector3(lhs.m_value[0] - rhs.m_value[0], lhs.m_value[1] - rhs.m_value[1], lhs.m_value[2] - rhs.m_value[2]);
}
friend Vector3& operator+=(Vector3& lhs, const Vector3& rhs)
{
lhs.m_value[0] += rhs.m_value[0];
lhs.m_value[1] += rhs.m_value[1];
lhs.m_value[2] += rhs.m_value[2];
return lhs;
}
friend Vector3& operator-=(Vector3& lhs, const Vector3& rhs)
{
lhs.m_value[0] -= rhs.m_value[0];
lhs.m_value[1] -= rhs.m_value[1];
lhs.m_value[2] -= rhs.m_value[2];
return lhs;
}
}; };
typedef Vector3<float> Vector3f; typedef Vector3<float> Vector3f;
@ -176,6 +242,12 @@ public:
{ {
} }
~Vector4() = default;
Vector4(const Vector4& other) = default;
Vector4(Vector4&& other) noexcept = default;
Vector4& operator=(const Vector4& other) = default;
Vector4& operator=(Vector4&& other) noexcept = default;
_NODISCARD T& operator()(const size_t index) _NODISCARD T& operator()(const size_t index)
{ {
assert(index < 4); assert(index < 4);
@ -267,6 +339,36 @@ public:
{ {
return m_value[3]; return m_value[3];
} }
friend Vector4 operator+(const Vector4& lhs, const Vector4& rhs)
{
return Vector4(lhs.m_value[0] + rhs.m_value[0], lhs.m_value[1] + rhs.m_value[1], lhs.m_value[2] + rhs.m_value[2], lhs.m_value[3] + rhs.m_value[3]);
}
friend Vector4 operator-(const Vector4& lhs, const Vector4& rhs)
{
return Vector4(lhs.m_value[0] - rhs.m_value[0], lhs.m_value[1] - rhs.m_value[1], lhs.m_value[2] - rhs.m_value[2], lhs.m_value[3] - rhs.m_value[3]);
}
friend Vector4& operator+=(Vector4& lhs, const Vector4& rhs)
{
lhs.m_value[0] += rhs.m_value[0];
lhs.m_value[1] += rhs.m_value[1];
lhs.m_value[2] += rhs.m_value[2];
lhs.m_value[3] += rhs.m_value[3];
return lhs;
}
friend Vector4& operator-=(Vector4& lhs, const Vector4& rhs)
{
lhs.m_value[0] -= rhs.m_value[0];
lhs.m_value[1] -= rhs.m_value[1];
lhs.m_value[2] -= rhs.m_value[2];
lhs.m_value[3] -= rhs.m_value[3];
return lhs;
}
}; };
typedef Vector4<float> Vector4f; typedef Vector4<float> Vector4f;