Merge pull request #192 from Laupetin/fix/gltf-bone-rotations

fix: gltf bone rotations
This commit is contained in:
Jan 2024-05-12 21:35:26 +02:00 committed by GitHub
commit 30394e6a4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 265 additions and 750 deletions

3
.gitmodules vendored
View File

@ -13,3 +13,6 @@
[submodule "thirdparty/json"] [submodule "thirdparty/json"]
path = thirdparty/json path = thirdparty/json
url = https://github.com/nlohmann/json.git url = https://github.com/nlohmann/json.git
[submodule "thirdparty/eigen"]
path = thirdparty/eigen
url = https://gitlab.com/libeigen/eigen.git

View File

@ -84,6 +84,7 @@ workspace "OpenAssetTools"
-- ThirdParty -- ThirdParty
-- ======================== -- ========================
include "thirdparty/catch2.lua" include "thirdparty/catch2.lua"
include "thirdparty/eigen.lua"
include "thirdparty/libtomcrypt.lua" include "thirdparty/libtomcrypt.lua"
include "thirdparty/libtommath.lua" include "thirdparty/libtommath.lua"
include "thirdparty/json.lua" include "thirdparty/json.lua"
@ -95,6 +96,7 @@ include "thirdparty/zlib.lua"
-- ThirdParty group: All projects that are external dependencies -- ThirdParty group: All projects that are external dependencies
group "ThirdParty" group "ThirdParty"
catch2:project() catch2:project()
eigen:project()
libtommath:project() libtommath:project()
libtomcrypt:project() libtomcrypt:project()
json:project() json:project()

View File

@ -1,11 +1,18 @@
#pragma once #pragma once
#include "Math/Quaternion.h"
#include "Utils/DistinctMapper.h" #include "Utils/DistinctMapper.h"
#include <string> #include <string>
#include <vector> #include <vector>
struct XModelQuaternion
{
float x;
float y;
float z;
float w;
};
struct XModelBone struct XModelBone
{ {
std::string name; std::string name;
@ -13,8 +20,8 @@ struct XModelBone
float scale[3]; float scale[3];
float globalOffset[3]; float globalOffset[3];
float localOffset[3]; float localOffset[3];
Quaternion32 globalRotation; XModelQuaternion globalRotation;
Quaternion32 localRotation; XModelQuaternion localRotation;
}; };
struct XModelBoneWeight struct XModelBoneWeight

View File

@ -56,4 +56,5 @@ function ObjLoading:project()
minizip:include(includes) minizip:include(includes)
zlib:include(includes) zlib:include(includes)
json:include(includes) json:include(includes)
eigen:include(includes)
end end

View File

@ -80,16 +80,16 @@ float AbstractGdtEntryReader::ReadFloatProperty(const std::string& propertyName,
return result; return result;
} }
Vector2f AbstractGdtEntryReader::ReadVec2Property(const std::string& propertyName, const Vector2f defaultValue) const GdtVec2 AbstractGdtEntryReader::ReadVec2Property(const std::string& propertyName, const GdtVec2 defaultValue) const
{ {
const auto foundProperty = m_entry.m_properties.find(propertyName); const auto foundProperty = m_entry.m_properties.find(propertyName);
if (foundProperty == m_entry.m_properties.end()) if (foundProperty == m_entry.m_properties.end())
return defaultValue; return defaultValue;
std::istringstream iss(foundProperty->second); std::istringstream iss(foundProperty->second);
Vector2f result; GdtVec2 result;
iss >> result(0) >> result(1); iss >> result.x >> result.y;
if (iss.fail()) if (iss.fail())
{ {
@ -101,16 +101,16 @@ Vector2f AbstractGdtEntryReader::ReadVec2Property(const std::string& propertyNam
return result; return result;
} }
Vector3f AbstractGdtEntryReader::ReadVec3Property(const std::string& propertyName, const Vector3f defaultValue) const GdtVec3 AbstractGdtEntryReader::ReadVec3Property(const std::string& propertyName, const GdtVec3 defaultValue) const
{ {
const auto foundProperty = m_entry.m_properties.find(propertyName); const auto foundProperty = m_entry.m_properties.find(propertyName);
if (foundProperty == m_entry.m_properties.end()) if (foundProperty == m_entry.m_properties.end())
return defaultValue; return defaultValue;
std::istringstream iss(foundProperty->second); std::istringstream iss(foundProperty->second);
Vector3f result; GdtVec3 result;
iss >> result(0) >> result(1) >> result(2); iss >> result.x >> result.y >> result.z;
if (iss.fail()) if (iss.fail())
{ {
@ -122,16 +122,16 @@ Vector3f AbstractGdtEntryReader::ReadVec3Property(const std::string& propertyNam
return result; return result;
} }
Vector4f AbstractGdtEntryReader::ReadVec4Property(const std::string& propertyName, const Vector4f defaultValue) const GdtVec4 AbstractGdtEntryReader::ReadVec4Property(const std::string& propertyName, const GdtVec4 defaultValue) const
{ {
const auto foundProperty = m_entry.m_properties.find(propertyName); const auto foundProperty = m_entry.m_properties.find(propertyName);
if (foundProperty == m_entry.m_properties.end()) if (foundProperty == m_entry.m_properties.end())
return defaultValue; return defaultValue;
std::istringstream iss(foundProperty->second); std::istringstream iss(foundProperty->second);
Vector4f result; GdtVec4 result;
iss >> result(0) >> result(1) >> result(2) >> result(3); iss >> result.x >> result.y >> result.z >> result.w;
if (iss.fail()) if (iss.fail())
{ {

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "Math/Vector.h"
#include "Obj/Gdt/GdtEntry.h" #include "Obj/Gdt/GdtEntry.h"
#include "Utils/ClassUtils.h" #include "Utils/ClassUtils.h"
@ -16,6 +15,27 @@ private:
std::string m_message; std::string m_message;
}; };
struct GdtVec2
{
float x;
float y;
};
struct GdtVec3
{
float x;
float y;
float z;
};
struct GdtVec4
{
float x;
float y;
float z;
float w;
};
class AbstractGdtEntryReader class AbstractGdtEntryReader
{ {
protected: protected:
@ -25,9 +45,9 @@ protected:
_NODISCARD bool ReadBoolProperty(const std::string& propertyName, bool defaultValue = false) const; _NODISCARD bool ReadBoolProperty(const std::string& propertyName, bool defaultValue = false) const;
_NODISCARD int ReadIntegerProperty(const std::string& propertyName, int defaultValue = 0) const; _NODISCARD int ReadIntegerProperty(const std::string& propertyName, int defaultValue = 0) const;
_NODISCARD float ReadFloatProperty(const std::string& propertyName, float defaultValue = 0.0f) const; _NODISCARD float ReadFloatProperty(const std::string& propertyName, float defaultValue = 0.0f) const;
_NODISCARD Vector2f ReadVec2Property(const std::string& propertyName, Vector2f defaultValue = {}) const; _NODISCARD GdtVec2 ReadVec2Property(const std::string& propertyName, GdtVec2 defaultValue = {}) const;
_NODISCARD Vector3f ReadVec3Property(const std::string& propertyName, Vector3f defaultValue = {}) const; _NODISCARD GdtVec3 ReadVec3Property(const std::string& propertyName, GdtVec3 defaultValue = {}) const;
_NODISCARD Vector4f ReadVec4Property(const std::string& propertyName, Vector4f defaultValue = {}) const; _NODISCARD GdtVec4 ReadVec4Property(const std::string& propertyName, GdtVec4 defaultValue = {}) const;
const GdtEntry& m_entry; const GdtEntry& m_entry;
}; };

View File

@ -7,7 +7,6 @@
#include "Game/IW4/MaterialConstantsIW4.h" #include "Game/IW4/MaterialConstantsIW4.h"
#include "Game/IW4/ObjConstantsIW4.h" #include "Game/IW4/ObjConstantsIW4.h"
#include "Game/IW4/TechsetConstantsIW4.h" #include "Game/IW4/TechsetConstantsIW4.h"
#include "Math/Vector.h"
#include "ObjLoading.h" #include "ObjLoading.h"
#include "Pool/GlobalAssetPool.h" #include "Pool/GlobalAssetPool.h"
#include "StateMap/StateMapFromTechniqueExtractor.h" #include "StateMap/StateMapFromTechniqueExtractor.h"
@ -198,14 +197,14 @@ namespace IW4
const auto distortionScaleX = ReadFloatProperty("distortionScaleX"); const auto distortionScaleX = ReadFloatProperty("distortionScaleX");
const auto distortionScaleY = ReadFloatProperty("distortionScaleY"); const auto distortionScaleY = ReadFloatProperty("distortionScaleY");
AddConstant("distortionScale", Vector4f(distortionScaleX, distortionScaleY, 0, 0)); AddConstant("distortionScale", {distortionScaleX, distortionScaleY, 0, 0});
if (uvAnim) if (uvAnim)
{ {
const auto uvScrollX = ReadFloatProperty("uvScrollX"); const auto uvScrollX = ReadFloatProperty("uvScrollX");
const auto uvScrollY = ReadFloatProperty("uvScrollY"); const auto uvScrollY = ReadFloatProperty("uvScrollY");
const auto uvScrollRotate = ReadFloatProperty("uvScrollRotate"); const auto uvScrollRotate = ReadFloatProperty("uvScrollRotate");
AddConstant("uvAnimParms", Vector4f(uvScrollX, uvScrollY, uvScrollRotate, 0)); AddConstant("uvAnimParms", {uvScrollX, uvScrollY, uvScrollRotate, 0});
} }
} }
@ -504,11 +503,11 @@ namespace IW4
const auto zFeatherDepth = ReadFloatProperty("zFeatherDepth"); const auto zFeatherDepth = ReadFloatProperty("zFeatherDepth");
if (std::fpclassify(zFeatherDepth) == FP_ZERO) if (std::fpclassify(zFeatherDepth) == FP_ZERO)
throw GdtReadingException("zFeatherDepth may not be zero"); throw GdtReadingException("zFeatherDepth may not be zero");
AddConstant("featherParms", Vector4f(1.0f / zFeatherDepth, zFeatherDepth, 0, 0)); AddConstant("featherParms", {1.0f / zFeatherDepth, zFeatherDepth, 0, 0});
} }
if (std::fpclassify(eyeOffsetDepth) != FP_ZERO) if (std::fpclassify(eyeOffsetDepth) != FP_ZERO)
AddConstant("eyeOffsetParms", Vector4f(eyeOffsetDepth, 0, 0, 0)); AddConstant("eyeOffsetParms", {eyeOffsetDepth, 0, 0, 0});
const auto colorTint = ReadVec4Property("colorTint", {1.0f, 1.0f, 1.0f, 1.0f}); const auto colorTint = ReadVec4Property("colorTint", {1.0f, 1.0f, 1.0f, 1.0f});
AddConstant("colorTint", colorTint); AddConstant("colorTint", colorTint);
@ -1009,13 +1008,13 @@ namespace IW4
m_textures.push_back(textureDef); m_textures.push_back(textureDef);
} }
void AddConstant(const std::string& constantName, Vector4f literalData) void AddConstant(const std::string& constantName, const GdtVec4& literalData)
{ {
MaterialConstantDef constantDef{}; MaterialConstantDef constantDef{};
constantDef.literal[0] = literalData(0); constantDef.literal[0] = literalData.x;
constantDef.literal[1] = literalData(1); constantDef.literal[1] = literalData.y;
constantDef.literal[2] = literalData(2); constantDef.literal[2] = literalData.z;
constantDef.literal[3] = literalData(3); constantDef.literal[3] = literalData.w;
strncpy(constantDef.name, constantName.c_str(), std::extent_v<decltype(MaterialConstantDef::name)>); strncpy(constantDef.name, constantName.c_str(), std::extent_v<decltype(MaterialConstantDef::name)>);
constantDef.nameHash = Common::R_HashString(constantName.c_str()); constantDef.nameHash = Common::R_HashString(constantName.c_str());

View File

@ -55,6 +55,7 @@ function ObjWriting:project()
Utils:include(includes) Utils:include(includes)
minilzo:include(includes) minilzo:include(includes)
minizip:include(includes) minizip:include(includes)
eigen:include(includes)
json:include(includes) json:include(includes)
libtomcrypt:include(includes) libtomcrypt:include(includes)

View File

@ -1,7 +1,6 @@
#include "AssetDumperXModel.h" #include "AssetDumperXModel.h"
#include "Game/IW3/CommonIW3.h" #include "Game/IW3/CommonIW3.h"
#include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h" #include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h" #include "Utils/HalfFloat.h"
@ -125,25 +124,31 @@ namespace
bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
bone.globalRotation = Quaternion32( bone.globalRotation = {
model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]); model->baseMat[boneNum].quat[0],
model->baseMat[boneNum].quat[1],
model->baseMat[boneNum].quat[2],
model->baseMat[boneNum].quat[3],
};
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
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 = Quaternion32(0, 0, 0, 1); bone.localRotation = {0, 0, 0, 1};
} }
else else
{ {
bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0]; bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0];
bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1]; bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1];
bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2]; bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2];
bone.localRotation = Quaternion32(QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]), bone.localRotation = {
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3])); QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3]),
};
} }
out.m_bones.emplace_back(std::move(bone)); out.m_bones.emplace_back(std::move(bone));
@ -267,6 +272,11 @@ namespace
weightCollection.weights.resize(totalWeightCount); weightCollection.weights.resize(totalWeightCount);
} }
float BoneWeight16(const uint16_t value)
{
return static_cast<float>(value) / static_cast<float>(std::numeric_limits<uint16_t>::max());
}
void AddXModelVertexBoneWeights(XModelCommon& out, const XModel* model, const unsigned lod) void AddXModelVertexBoneWeights(XModelCommon& out, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
@ -318,7 +328,7 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -335,9 +345,9 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -355,11 +365,11 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]); const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat)); const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat));
const auto boneWeight3 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};

View File

@ -3,9 +3,9 @@
#include "Game/IW4/MaterialConstantsIW4.h" #include "Game/IW4/MaterialConstantsIW4.h"
#include "Game/IW4/ObjConstantsIW4.h" #include "Game/IW4/ObjConstantsIW4.h"
#include "Game/IW4/TechsetConstantsIW4.h" #include "Game/IW4/TechsetConstantsIW4.h"
#include "Math/Vector.h"
#include "Utils/ClassUtils.h" #include "Utils/ClassUtils.h"
#include <Eigen>
#include <iomanip> #include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <sstream> #include <sstream>
@ -450,7 +450,7 @@ namespace IW4
class ConstantsInfo class ConstantsInfo
{ {
public: public:
Vector4f m_color_tint = Vector4f(1.0f, 1.0f, 1.0f, 1.0f); Eigen::Vector4f m_color_tint = Eigen::Vector4f(1.0f, 1.0f, 1.0f, 1.0f);
float m_env_map_min = 0.2f; float m_env_map_min = 0.2f;
float m_env_map_max = 1.0f; float m_env_map_max = 1.0f;
float m_env_map_exponent = 2.5f; float m_env_map_exponent = 2.5f;
@ -460,13 +460,13 @@ namespace IW4
float m_falloff_end_angle = 65.0f; float m_falloff_end_angle = 65.0f;
float m_dist_falloff_begin_distance = 200.0f; float m_dist_falloff_begin_distance = 200.0f;
float m_dist_falloff_end_distance = 10.0f; float m_dist_falloff_end_distance = 10.0f;
Vector4f m_falloff_begin_color = Vector4f(1.0f, 1.0f, 1.0f, 1.0f); Eigen::Vector4f m_falloff_begin_color = Eigen::Vector4f(1.0f, 1.0f, 1.0f, 1.0f);
Vector4f m_falloff_end_color = Vector4f(0.5f, 0.5f, 0.5f, 0.5f); Eigen::Vector4f m_falloff_end_color = Eigen::Vector4f(0.5f, 0.5f, 0.5f, 0.5f);
Vector2f m_detail_scale = Vector2f(8.0f, 8.0f); Eigen::Vector2f m_detail_scale = Eigen::Vector2f(8.0f, 8.0f);
Vector2f m_distortion_scale = Vector2f(0.5f, 0.5f); Eigen::Vector2f m_distortion_scale = Eigen::Vector2f(0.5f, 0.5f);
Vector4f m_color_obj_min = Vector4f(0.0f, 0.0f, 0.0f, 0.0f); Eigen::Vector4f m_color_obj_min = Eigen::Vector4f(0.0f, 0.0f, 0.0f, 0.0f);
Vector4f m_color_obj_max = Vector4f(1.0f, 1.0f, 1.0f, 1.0f); Eigen::Vector4f m_color_obj_max = Eigen::Vector4f(1.0f, 1.0f, 1.0f, 1.0f);
Vector4f m_water_color = Vector4f(1.0f, 1.0f, 1.0f, 1.0f); Eigen::Vector4f m_water_color = Eigen::Vector4f(1.0f, 1.0f, 1.0f, 1.0f);
// Speed in which the wave animation is played // Speed in which the wave animation is played
float m_flag_speed = 1.0f; float m_flag_speed = 1.0f;
@ -497,7 +497,7 @@ namespace IW4
m_entry.m_properties.emplace(std::make_pair(key, std::move(value))); m_entry.m_properties.emplace(std::make_pair(key, std::move(value)));
} }
void SetValue(const std::string& key, const Vector4f& v) void SetValue(const std::string& key, const Eigen::Vector4f& v)
{ {
std::ostringstream ss; std::ostringstream ss;
ss << v.x() << " " << v.y() << " " << v.z() << " " << v.w(); ss << v.x() << " " << v.y() << " " << v.z() << " " << v.w();
@ -1183,7 +1183,7 @@ namespace IW4
if (constant.nameHash == Common::R_HashString("colorTint")) if (constant.nameHash == Common::R_HashString("colorTint"))
{ {
m_constants_info.m_color_tint = Vector4f(constant.literal); m_constants_info.m_color_tint = Eigen::Vector4f(constant.literal);
} }
else if (constant.nameHash == Common::R_HashString("envMapParms")) else if (constant.nameHash == Common::R_HashString("envMapParms"))
{ {
@ -1198,11 +1198,11 @@ namespace IW4
} }
else if (constant.nameHash == Common::R_HashString("falloffBeginColor")) else if (constant.nameHash == Common::R_HashString("falloffBeginColor"))
{ {
m_constants_info.m_falloff_begin_color = Vector4f(constant.literal); m_constants_info.m_falloff_begin_color = Eigen::Vector4f(constant.literal);
} }
else if (constant.nameHash == Common::R_HashString("falloffEndColor")) else if (constant.nameHash == Common::R_HashString("falloffEndColor"))
{ {
m_constants_info.m_falloff_end_color = Vector4f(constant.literal); m_constants_info.m_falloff_end_color = Eigen::Vector4f(constant.literal);
} }
else if (constant.nameHash == Common::R_HashString("eyeOffsetParms")) else if (constant.nameHash == Common::R_HashString("eyeOffsetParms"))
{ {
@ -1227,14 +1227,15 @@ namespace IW4
{ {
const auto detailScaleFactorX = static_cast<float>(colorMapTexture->width) / static_cast<float>(detailMapTexture->width); const auto detailScaleFactorX = static_cast<float>(colorMapTexture->width) / static_cast<float>(detailMapTexture->width);
const auto detailScaleFactorY = static_cast<float>(colorMapTexture->height) / static_cast<float>(detailMapTexture->height); const auto detailScaleFactorY = static_cast<float>(colorMapTexture->height) / static_cast<float>(detailMapTexture->height);
m_constants_info.m_detail_scale = Vector2f(constant.literal[0] / detailScaleFactorX, constant.literal[1] / detailScaleFactorY); m_constants_info.m_detail_scale =
Eigen::Vector2f(constant.literal[0] / detailScaleFactorX, constant.literal[1] / detailScaleFactorY);
} }
else else
m_constants_info.m_detail_scale = Vector2f(constant.literal[0], constant.literal[1]); m_constants_info.m_detail_scale = Eigen::Vector2f(constant.literal[0], constant.literal[1]);
} }
else else
{ {
m_constants_info.m_detail_scale = Vector2f(constant.literal[0], constant.literal[1]); m_constants_info.m_detail_scale = Eigen::Vector2f(constant.literal[0], constant.literal[1]);
} }
} }
else if (constant.nameHash == Common::R_HashString("flagParms")) else if (constant.nameHash == Common::R_HashString("flagParms"))
@ -1252,7 +1253,7 @@ namespace IW4
} }
else if (constant.nameHash == Common::R_HashString("distortionScale")) else if (constant.nameHash == Common::R_HashString("distortionScale"))
{ {
m_constants_info.m_distortion_scale = Vector2f(constant.literal[0], constant.literal[1]); m_constants_info.m_distortion_scale = Eigen::Vector2f(constant.literal[0], constant.literal[1]);
} }
else if (constant.nameHash == Common::R_HashString("uvAnimParms")) else if (constant.nameHash == Common::R_HashString("uvAnimParms"))
{ {
@ -1262,15 +1263,15 @@ namespace IW4
} }
else if (constant.nameHash == Common::R_HashString("colorObjMin")) else if (constant.nameHash == Common::R_HashString("colorObjMin"))
{ {
m_constants_info.m_color_obj_min = Vector4f(constant.literal); m_constants_info.m_color_obj_min = Eigen::Vector4f(constant.literal);
} }
else if (constant.nameHash == Common::R_HashString("colorObjMax")) else if (constant.nameHash == Common::R_HashString("colorObjMax"))
{ {
m_constants_info.m_color_obj_max = Vector4f(constant.literal); m_constants_info.m_color_obj_max = Eigen::Vector4f(constant.literal);
} }
else if (constant.nameHash == Common::R_HashString("waterColor")) else if (constant.nameHash == Common::R_HashString("waterColor"))
{ {
m_constants_info.m_water_color = Vector4f(constant.literal); m_constants_info.m_water_color = Eigen::Vector4f(constant.literal);
} }
else else
{ {

View File

@ -1,7 +1,6 @@
#include "AssetDumperXModel.h" #include "AssetDumperXModel.h"
#include "Game/IW4/CommonIW4.h" #include "Game/IW4/CommonIW4.h"
#include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h" #include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h" #include "Utils/HalfFloat.h"
@ -120,25 +119,31 @@ namespace
bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
bone.globalRotation = Quaternion32( bone.globalRotation = {
model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]); model->baseMat[boneNum].quat[0],
model->baseMat[boneNum].quat[1],
model->baseMat[boneNum].quat[2],
model->baseMat[boneNum].quat[3],
};
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
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 = Quaternion32(0, 0, 0, 1); bone.localRotation = {0, 0, 0, 1};
} }
else else
{ {
bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0]; bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0];
bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1]; bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1];
bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2]; bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2];
bone.localRotation = Quaternion32(QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]), bone.localRotation = {
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3])); QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3]),
};
} }
out.m_bones.emplace_back(std::move(bone)); out.m_bones.emplace_back(std::move(bone));
@ -253,6 +258,11 @@ namespace
weightCollection.weights.resize(totalWeightCount); weightCollection.weights.resize(totalWeightCount);
} }
float BoneWeight16(const uint16_t value)
{
return static_cast<float>(value) / static_cast<float>(std::numeric_limits<uint16_t>::max());
}
void AddXModelVertexBoneWeights(XModelCommon& out, const XModelSurfs* modelSurfs) void AddXModelVertexBoneWeights(XModelCommon& out, const XModelSurfs* modelSurfs)
{ {
auto& weightCollection = out.m_bone_weight_data; auto& weightCollection = out.m_bone_weight_data;
@ -301,7 +311,7 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -318,9 +328,9 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -338,11 +348,11 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]); const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat)); const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat));
const auto boneWeight3 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};

View File

@ -1,7 +1,6 @@
#include "AssetDumperXModel.h" #include "AssetDumperXModel.h"
#include "Game/IW5/CommonIW5.h" #include "Game/IW5/CommonIW5.h"
#include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h" #include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h" #include "Utils/HalfFloat.h"
@ -120,25 +119,31 @@ namespace
bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
bone.globalRotation = Quaternion32( bone.globalRotation = {
model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]); model->baseMat[boneNum].quat[0],
model->baseMat[boneNum].quat[1],
model->baseMat[boneNum].quat[2],
model->baseMat[boneNum].quat[3],
};
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
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 = Quaternion32(0, 0, 0, 1); bone.localRotation = {0, 0, 0, 1};
} }
else else
{ {
bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0]; bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0];
bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1]; bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1];
bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2]; bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2];
bone.localRotation = Quaternion32(QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]), bone.localRotation = {
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3])); QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3]),
};
} }
out.m_bones.emplace_back(std::move(bone)); out.m_bones.emplace_back(std::move(bone));
@ -253,6 +258,11 @@ namespace
weightCollection.weights.resize(totalWeightCount); weightCollection.weights.resize(totalWeightCount);
} }
float BoneWeight16(const uint16_t value)
{
return static_cast<float>(value) / static_cast<float>(std::numeric_limits<uint16_t>::max());
}
void AddXModelVertexBoneWeights(XModelCommon& out, const XModelSurfs* modelSurfs) void AddXModelVertexBoneWeights(XModelCommon& out, const XModelSurfs* modelSurfs)
{ {
auto& weightCollection = out.m_bone_weight_data; auto& weightCollection = out.m_bone_weight_data;
@ -301,7 +311,7 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -318,9 +328,9 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -338,11 +348,11 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]); const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat)); const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat));
const auto boneWeight3 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};

View File

@ -1,10 +1,8 @@
#include "AssetDumperXModel.h" #include "AssetDumperXModel.h"
#include "Game/T5/CommonT5.h" #include "Game/T5/CommonT5.h"
#include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h" #include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h"
#include "Utils/QuatInt16.h" #include "Utils/QuatInt16.h"
#include "XModel/Export/XModelExportWriter.h" #include "XModel/Export/XModelExportWriter.h"
#include "XModel/Gltf/GltfBinOutput.h" #include "XModel/Gltf/GltfBinOutput.h"
@ -125,25 +123,31 @@ namespace
bone.globalOffset[0] = model->baseMat[boneNum].trans[0]; bone.globalOffset[0] = model->baseMat[boneNum].trans[0];
bone.globalOffset[1] = model->baseMat[boneNum].trans[1]; bone.globalOffset[1] = model->baseMat[boneNum].trans[1];
bone.globalOffset[2] = model->baseMat[boneNum].trans[2]; bone.globalOffset[2] = model->baseMat[boneNum].trans[2];
bone.globalRotation = Quaternion32( bone.globalRotation = {
model->baseMat[boneNum].quat[0], model->baseMat[boneNum].quat[1], model->baseMat[boneNum].quat[2], model->baseMat[boneNum].quat[3]); model->baseMat[boneNum].quat[0],
model->baseMat[boneNum].quat[1],
model->baseMat[boneNum].quat[2],
model->baseMat[boneNum].quat[3],
};
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
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 = Quaternion32(0, 0, 0, 1); bone.localRotation = {0, 0, 0, 1};
} }
else else
{ {
bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0]; bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0];
bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1]; bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1];
bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2]; bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2];
bone.localRotation = Quaternion32(QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]), bone.localRotation = {
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3])); QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3]),
};
} }
out.m_bones.emplace_back(std::move(bone)); out.m_bones.emplace_back(std::move(bone));
@ -267,6 +271,11 @@ namespace
weightCollection.weights.resize(totalWeightCount); weightCollection.weights.resize(totalWeightCount);
} }
float BoneWeight16(const uint16_t value)
{
return static_cast<float>(value) / static_cast<float>(std::numeric_limits<uint16_t>::max());
}
void AddXModelVertexBoneWeights(XModelCommon& out, const XModel* model, const unsigned lod) void AddXModelVertexBoneWeights(XModelCommon& out, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
@ -318,7 +327,7 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -335,9 +344,9 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -355,11 +364,11 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]); const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat)); const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat));
const auto boneWeight3 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};

View File

@ -1,10 +1,8 @@
#include "AssetDumperXModel.h" #include "AssetDumperXModel.h"
#include "Game/T6/CommonT6.h" #include "Game/T6/CommonT6.h"
#include "Math/Quaternion.h"
#include "ObjWriting.h" #include "ObjWriting.h"
#include "Utils/DistinctMapper.h" #include "Utils/DistinctMapper.h"
#include "Utils/HalfFloat.h"
#include "Utils/QuatInt16.h" #include "Utils/QuatInt16.h"
#include "XModel/Export/XModelExportWriter.h" #include "XModel/Export/XModelExportWriter.h"
#include "XModel/Gltf/GltfBinOutput.h" #include "XModel/Gltf/GltfBinOutput.h"
@ -137,25 +135,31 @@ namespace
bone.globalOffset[0] = model->baseMat[boneNum].trans.x; bone.globalOffset[0] = model->baseMat[boneNum].trans.x;
bone.globalOffset[1] = model->baseMat[boneNum].trans.y; bone.globalOffset[1] = model->baseMat[boneNum].trans.y;
bone.globalOffset[2] = model->baseMat[boneNum].trans.z; bone.globalOffset[2] = model->baseMat[boneNum].trans.z;
bone.globalRotation = bone.globalRotation = {
Quaternion32(model->baseMat[boneNum].quat.x, model->baseMat[boneNum].quat.y, model->baseMat[boneNum].quat.z, model->baseMat[boneNum].quat.w); model->baseMat[boneNum].quat.x,
model->baseMat[boneNum].quat.y,
model->baseMat[boneNum].quat.z,
model->baseMat[boneNum].quat.w,
};
if (boneNum < model->numRootBones) if (boneNum < model->numRootBones)
{ {
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 = Quaternion32(0, 0, 0, 1); bone.localRotation = {0, 0, 0, 1};
} }
else else
{ {
bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0]; bone.localOffset[0] = model->trans[boneNum - model->numRootBones][0];
bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1]; bone.localOffset[1] = model->trans[boneNum - model->numRootBones][1];
bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2]; bone.localOffset[2] = model->trans[boneNum - model->numRootBones][2];
bone.localRotation = Quaternion32(QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]), bone.localRotation = {
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][0]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]), QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][1]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3])); QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][2]),
QuatInt16::ToFloat(model->quats[boneNum - model->numRootBones][3]),
};
} }
out.m_bones.emplace_back(std::move(bone)); out.m_bones.emplace_back(std::move(bone));
@ -285,6 +289,11 @@ namespace
weightCollection.weights.resize(totalWeightCount); weightCollection.weights.resize(totalWeightCount);
} }
float BoneWeight16(const uint16_t value)
{
return static_cast<float>(value) / static_cast<float>(std::numeric_limits<uint16_t>::max());
}
void AddXModelVertexBoneWeights(XModelCommon& out, const XModel* model, const unsigned lod) void AddXModelVertexBoneWeights(XModelCommon& out, const XModel* model, const unsigned lod)
{ {
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex]; const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
@ -339,7 +348,7 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -356,9 +365,9 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};
@ -376,11 +385,11 @@ namespace
const auto* boneWeightOffset = &weightCollection.weights[weightOffset]; const auto* boneWeightOffset = &weightCollection.weights[weightOffset];
const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat)); const auto boneIndex0 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat));
const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat)); const auto boneIndex1 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat));
const auto boneWeight1 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]); const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat)); const auto boneIndex2 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat));
const auto boneWeight2 = HalfFloat::ToFloat(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]); const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat)); const auto boneIndex3 = static_cast<int>(surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat));
const auto boneWeight3 = HalfFloat::ToFloat(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{boneIndex0, boneWeight0};

View File

@ -1,7 +1,6 @@
#include "XModelExportWriter.h" #include "XModelExportWriter.h"
#include "Math/Quaternion.h" #include <Eigen>
#include <chrono> #include <chrono>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
@ -61,10 +60,10 @@ protected:
m_stream << std::format("OFFSET {:.6f}, {:.6f}, {:.6f}\n", bone.globalOffset[0], bone.globalOffset[1], bone.globalOffset[2]); m_stream << std::format("OFFSET {:.6f}, {:.6f}, {:.6f}\n", bone.globalOffset[0], bone.globalOffset[1], bone.globalOffset[2]);
m_stream << std::format("SCALE {:.6f}, {:.6f}, {:.6f}\n", bone.scale[0], bone.scale[1], bone.scale[2]); m_stream << std::format("SCALE {:.6f}, {:.6f}, {:.6f}\n", bone.scale[0], bone.scale[1], bone.scale[2]);
const Matrix32 mat = bone.globalRotation.ToMatrix(); const auto mat = Eigen::Quaternionf(bone.globalRotation.w, bone.globalRotation.x, bone.globalRotation.y, bone.globalRotation.z).matrix();
m_stream << std::format("X {:.6f}, {:.6f}, {:.6f}\n", mat.m_data[0][0], mat.m_data[1][0], mat.m_data[2][0]); m_stream << std::format("X {:.6f}, {:.6f}, {:.6f}\n", mat(0, 0), mat(1, 0), mat(2, 0));
m_stream << std::format("Y {:.6f}, {:.6f}, {:.6f}\n", mat.m_data[0][1], mat.m_data[1][1], mat.m_data[2][1]); m_stream << std::format("Y {:.6f}, {:.6f}, {:.6f}\n", mat(0, 1), mat(1, 1), mat(2, 1));
m_stream << std::format("Z {:.6f}, {:.6f}, {:.6f}\n", mat.m_data[0][2], mat.m_data[1][2], mat.m_data[2][2]); m_stream << std::format("Z {:.6f}, {:.6f}, {:.6f}\n", mat(0, 2), mat(1, 2), mat(2, 2));
m_stream << '\n'; m_stream << '\n';
boneNum++; boneNum++;
} }

View File

@ -1,10 +1,10 @@
#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"
#include <Eigen>
#include <format> #include <format>
using namespace gltf; using namespace gltf;
@ -222,20 +222,26 @@ namespace
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]); Eigen::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); Eigen::Quaternionf rotation(bone.globalRotation.w, bone.globalRotation.x, bone.globalRotation.z, -bone.globalRotation.y);
if (bone.parentIndex >= 0) if (bone.parentIndex >= 0)
{ {
const auto& parentBone = xmodel.m_bones[bone.parentIndex]; const auto& parentBone = xmodel.m_bones[bone.parentIndex];
translation -= Vector3f(parentBone.globalOffset[0], parentBone.globalOffset[2], -parentBone.globalOffset[1]); const auto inverseParentRotation =
rotation /= Quaternion32( Eigen::Quaternionf(parentBone.globalRotation.w, parentBone.globalRotation.x, parentBone.globalRotation.z, -parentBone.globalRotation.y)
parentBone.globalRotation.m_x, parentBone.globalRotation.m_z, -parentBone.globalRotation.m_y, parentBone.globalRotation.m_w); .normalized()
.inverse()
.normalized();
translation -= Eigen::Vector3f(parentBone.globalOffset[0], parentBone.globalOffset[2], -parentBone.globalOffset[1]);
translation = inverseParentRotation * translation;
rotation = inverseParentRotation * rotation;
} }
rotation.Normalize(); rotation.normalize();
boneNode.name = bone.name; boneNode.name = bone.name;
boneNode.translation = std::to_array({translation.x(), translation.y(), translation.z()}); boneNode.translation = std::to_array({translation.x(), translation.y(), translation.z()});
boneNode.rotation = std::to_array({rotation.m_x, rotation.m_y, rotation.m_z, rotation.m_w}); boneNode.rotation = std::to_array({rotation.x(), rotation.y(), rotation.z(), rotation.w()});
std::vector<unsigned> children; std::vector<unsigned> children;
for (auto maybeChildIndex = 0u; maybeChildIndex < boneCount; maybeChildIndex++) for (auto maybeChildIndex = 0u; maybeChildIndex < boneCount; maybeChildIndex++)
@ -267,6 +273,7 @@ namespace
skin.joints.emplace_back(boneIndex + m_first_bone_node); skin.joints.emplace_back(boneIndex + m_first_bone_node);
skin.inverseBindMatrices = m_inverse_bind_matrices_accessor; skin.inverseBindMatrices = m_inverse_bind_matrices_accessor;
skin.skeleton = m_first_bone_node;
gltf.skins->emplace_back(std::move(skin)); gltf.skins->emplace_back(std::move(skin));
} }
@ -511,29 +518,28 @@ namespace
auto* inverseBindMatrixData = reinterpret_cast<float*>(&bufferData[currentBufferOffset]); auto* inverseBindMatrixData = reinterpret_cast<float*>(&bufferData[currentBufferOffset]);
for (const auto& bone : xmodel.m_bones) for (const auto& bone : xmodel.m_bones)
{ {
Matrix32 inverseBindMatrix; const auto translation = Eigen::Translation3f(bone.globalOffset[0], bone.globalOffset[2], -bone.globalOffset[1]);
inverseBindMatrix.m_data[0][3] = -bone.globalOffset[0]; const auto rotation = Eigen::Quaternionf(bone.globalRotation.w, bone.globalRotation.x, bone.globalRotation.z, -bone.globalRotation.y);
inverseBindMatrix.m_data[1][3] = -bone.globalOffset[2];
inverseBindMatrix.m_data[2][3] = bone.globalOffset[1];
// In-memory = row major const auto inverseBindMatrix = (translation * rotation).matrix().inverse();
// gltf = column major
inverseBindMatrixData[0] = inverseBindMatrix.m_data[0][0]; // GLTF matrix is column major
inverseBindMatrixData[1] = inverseBindMatrix.m_data[1][0]; inverseBindMatrixData[0] = inverseBindMatrix(0, 0);
inverseBindMatrixData[2] = inverseBindMatrix.m_data[2][0]; inverseBindMatrixData[1] = inverseBindMatrix(1, 0);
inverseBindMatrixData[3] = inverseBindMatrix.m_data[3][0]; inverseBindMatrixData[2] = inverseBindMatrix(2, 0);
inverseBindMatrixData[4] = inverseBindMatrix.m_data[0][1]; inverseBindMatrixData[3] = inverseBindMatrix(3, 0);
inverseBindMatrixData[5] = inverseBindMatrix.m_data[1][1]; inverseBindMatrixData[4] = inverseBindMatrix(0, 1);
inverseBindMatrixData[6] = inverseBindMatrix.m_data[2][1]; inverseBindMatrixData[5] = inverseBindMatrix(1, 1);
inverseBindMatrixData[7] = inverseBindMatrix.m_data[3][1]; inverseBindMatrixData[6] = inverseBindMatrix(2, 1);
inverseBindMatrixData[8] = inverseBindMatrix.m_data[0][2]; inverseBindMatrixData[7] = inverseBindMatrix(3, 1);
inverseBindMatrixData[9] = inverseBindMatrix.m_data[1][2]; inverseBindMatrixData[8] = inverseBindMatrix(0, 2);
inverseBindMatrixData[10] = inverseBindMatrix.m_data[2][2]; inverseBindMatrixData[9] = inverseBindMatrix(1, 2);
inverseBindMatrixData[11] = inverseBindMatrix.m_data[3][2]; inverseBindMatrixData[10] = inverseBindMatrix(2, 2);
inverseBindMatrixData[12] = inverseBindMatrix.m_data[0][3]; inverseBindMatrixData[11] = inverseBindMatrix(3, 2);
inverseBindMatrixData[13] = inverseBindMatrix.m_data[1][3]; inverseBindMatrixData[12] = inverseBindMatrix(0, 3);
inverseBindMatrixData[14] = inverseBindMatrix.m_data[2][3]; inverseBindMatrixData[13] = inverseBindMatrix(1, 3);
inverseBindMatrixData[15] = inverseBindMatrix.m_data[3][3]; inverseBindMatrixData[14] = inverseBindMatrix(2, 3);
inverseBindMatrixData[15] = inverseBindMatrix(3, 3);
inverseBindMatrixData += 16u; inverseBindMatrixData += 16u;
} }

View File

@ -1,35 +0,0 @@
#pragma once
template<typename T> class Matrix
{
public:
T m_data[4][4];
Matrix()
: m_data{
{T(1.0), 0, 0, 0 },
{0, T(1.0), 0, 0 },
{0, 0, T(1.0), 0 },
{0, 0, 0, T(1.0)},
}
{
}
Matrix(T d00, T d01, T d02, T d03, T d10, T d11, T d12, T d13, T d20, T d21, T d22, T d23, T d30, T d31, T d32, T d33)
: m_data{
{d00, d01, d02, d03},
{d10, d11, d12, d13},
{d20, d21, d22, d23},
{d30, d31, d32, d33},
}
{
}
static Matrix<T> Identity()
{
return Matrix();
}
};
typedef Matrix<float> Matrix32;
typedef Matrix<double> Matrix64;

View File

@ -1,186 +0,0 @@
#pragma once
#include "Matrix.h"
#include "Utils/ClassUtils.h"
template<typename T> class Quaternion
{
public:
T m_x;
T m_y;
T m_z;
T m_w;
Quaternion()
{
m_x = T(0);
m_y = T(0);
m_z = T(0);
m_w = T(1);
}
Quaternion(T x, T y, T z, T w)
{
m_x = x;
m_y = y;
m_z = z;
m_w = w;
}
_NODISCARD Matrix<T> ToMatrix() const
{
const T xx = m_x * m_x;
const T xy = m_x * m_y;
const T xz = m_x * m_z;
const T xw = m_x * m_w;
const T yy = m_y * m_y;
const T yz = m_y * m_z;
const T yw = m_y * m_w;
const T zz = m_z * m_z;
const T zw = m_z * m_w;
const T m00 = 1 - 2 * yy - 2 * zz;
const T m01 = 2 * xy - 2 * zw;
const T m02 = 2 * xz + 2 * yw;
const T m10 = 2 * xy + 2 * zw;
const T m11 = 1 - 2 * xx - 2 * zz;
const T m12 = 2 * yz - 2 * xw;
const T m20 = 2 * xz - 2 * yw;
const T m21 = 2 * yz + 2 * xw;
const T m22 = 1 - 2 * xx - 2 * yy;
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));
}
static Quaternion& conj(Quaternion& result)
{
result.m_x = -result.m_x;
result.m_y = -result.m_y;
result.m_z = -result.m_z;
return result;
}
static Quaternion& invert(Quaternion& result)
{
// from game programming gems p198
// do result = conj( q ) / norm( q )
Quaternion::conj(result);
// return if norm() is near 0 (divide by 0 would result in NaN)
T l = result.lengthSquared();
if (l < static_cast<T>(0.0001))
{
return result;
}
T l_inv = static_cast<T>(1.0) / l;
result.m_x *= l_inv;
result.m_y *= l_inv;
result.m_z *= l_inv;
result.m_w *= l_inv;
return result;
}
T lengthSquared() const
{
return Quaternion::dot(*this, *this);
}
T length() const
{
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)
{
const T x2 = lhs.m_w * rhs.m_x + lhs.m_x * rhs.m_w + lhs.m_y * rhs.m_z - lhs.m_z * rhs.m_y;
const T y2 = lhs.m_w * rhs.m_y + lhs.m_y * rhs.m_w + lhs.m_z * rhs.m_x - lhs.m_x * rhs.m_z;
const T z2 = lhs.m_w * rhs.m_z + lhs.m_z * rhs.m_w + lhs.m_x * rhs.m_y - lhs.m_y * rhs.m_x;
const T w2 = lhs.m_w * rhs.m_w - lhs.m_x * rhs.m_x - lhs.m_y * rhs.m_y - lhs.m_z * rhs.m_z;
return Quaternion(x2, y2, z2, w2);
}
friend Quaternion operator/(const Quaternion& lhs, const Quaternion& rhs)
{
Quaternion rhsInv = rhs;
Quaternion::invert(rhsInv);
return lhs * rhsInv;
}
friend Quaternion& operator*=(Quaternion& lhs, const Quaternion& rhs)
{
const T x2 = lhs.m_w * rhs.m_x + lhs.m_x * rhs.m_w + lhs.m_y * rhs.m_z - lhs.m_z * rhs.m_y;
const T y2 = lhs.m_w * rhs.m_y + lhs.m_y * rhs.m_w + lhs.m_z * rhs.m_x - lhs.m_x * rhs.m_z;
const T z2 = lhs.m_w * rhs.m_z + lhs.m_z * rhs.m_w + lhs.m_x * rhs.m_y - lhs.m_y * rhs.m_x;
const T w2 = lhs.m_w * rhs.m_w - lhs.m_x * rhs.m_x - lhs.m_y * rhs.m_y - lhs.m_z * rhs.m_z;
lhs.m_x = x2;
lhs.m_y = y2;
lhs.m_z = z2;
lhs.m_w = w2;
return lhs;
}
friend Quaternion& operator/=(Quaternion& lhs, const Quaternion& rhs)
{
Quaternion rhsInv = rhs;
Quaternion::invert(rhsInv);
lhs *= rhsInv;
return lhs;
}
};
typedef Quaternion<float> Quaternion32;
typedef Quaternion<double> Quaternion64;

View File

@ -1,375 +0,0 @@
#pragma once
#include "Utils/ClassUtils.h"
#include <cassert>
#include <cstddef>
template<typename T> class Vector2
{
T m_value[2];
public:
Vector2()
: m_value{T(0), T(0)}
{
}
Vector2(T x, T y)
: m_value{x, y}
{
}
explicit Vector2(const T* value)
: m_value{value[0], value[1]}
{
}
~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)
{
assert(index < 2);
return m_value[index];
}
_NODISCARD const T& operator()(const size_t index) const
{
assert(index < 2);
return m_value[index];
}
_NODISCARD T& x()
{
return m_value[0];
}
_NODISCARD T& y()
{
return m_value[1];
}
_NODISCARD const T& x() const
{
return m_value[0];
}
_NODISCARD const T& y() const
{
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<double> Vector2d;
template<typename T> class Vector3
{
T m_value[3];
public:
Vector3()
: m_value{T(0), T(0), T(0)}
{
}
Vector3(T x, T y, T z)
: m_value{x, y, z}
{
}
explicit Vector3(const T* value)
: m_value{value[0], value[1], value[2]}
{
}
~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)
{
assert(index < 3);
return m_value[index];
}
_NODISCARD const T& operator()(const size_t index) const
{
assert(index < 3);
return m_value[index];
}
_NODISCARD T& x()
{
return m_value[0];
}
_NODISCARD T& y()
{
return m_value[1];
}
_NODISCARD T& z()
{
return m_value[2];
}
_NODISCARD const T& x() const
{
return m_value[0];
}
_NODISCARD const T& y() const
{
return m_value[1];
}
_NODISCARD const T& z() const
{
return m_value[2];
}
_NODISCARD T& r()
{
return m_value[0];
}
_NODISCARD T& g()
{
return m_value[1];
}
_NODISCARD T& b()
{
return m_value[2];
}
_NODISCARD const T& r() const
{
return m_value[0];
}
_NODISCARD const T& g() const
{
return m_value[1];
}
_NODISCARD const T& b() const
{
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<double> Vector3d;
template<typename T> class Vector4
{
T m_value[4];
public:
Vector4()
: m_value{T(0), T(0), T(0), T(0)}
{
}
Vector4(T x, T y, T z, T w)
: m_value{x, y, z, w}
{
}
explicit Vector4(const T* value)
: m_value{value[0], value[1], value[2], value[3]}
{
}
~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)
{
assert(index < 4);
return m_value[index];
}
_NODISCARD const T& operator()(const size_t index) const
{
assert(index < 4);
return m_value[index];
}
_NODISCARD T& x()
{
return m_value[0];
}
_NODISCARD T& y()
{
return m_value[1];
}
_NODISCARD T& z()
{
return m_value[2];
}
_NODISCARD T& w()
{
return m_value[3];
}
_NODISCARD const T& x() const
{
return m_value[0];
}
_NODISCARD const T& y() const
{
return m_value[1];
}
_NODISCARD const T& z() const
{
return m_value[2];
}
_NODISCARD const T& w() const
{
return m_value[3];
}
_NODISCARD T& r()
{
return m_value[0];
}
_NODISCARD T& g()
{
return m_value[1];
}
_NODISCARD T& b()
{
return m_value[2];
}
_NODISCARD T& a()
{
return m_value[3];
}
_NODISCARD const T& r() const
{
return m_value[0];
}
_NODISCARD const T& g() const
{
return m_value[1];
}
_NODISCARD const T& b() const
{
return m_value[2];
}
_NODISCARD const T& a() const
{
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<double> Vector4d;

1
thirdparty/eigen vendored Submodule

@ -0,0 +1 @@
Subproject commit afb17288cbb5bac779a850e3ec6ba106b7f42c1c

23
thirdparty/eigen.lua vendored Normal file
View File

@ -0,0 +1,23 @@
eigen = {}
function eigen:include(includes)
if includes:handle(self:name()) then
includedirs {
path.join(ThirdPartyFolder(), "eigen", "Eigen")
}
end
end
function eigen:link()
end
function eigen:use()
end
function eigen:name()
return "eigen"
end
function eigen:project()
end