2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-09-12 19:47:27 +00:00

chore: backwards compatibility for old xmodel exports

This commit is contained in:
Jan Laupetin
2025-08-19 13:31:46 +01:00
parent 1b6c58d843
commit fed6e2f845
4 changed files with 80 additions and 37 deletions

View File

@@ -138,8 +138,9 @@ namespace
class GltfLoaderImpl final : public Loader class GltfLoaderImpl final : public Loader
{ {
public: public:
explicit GltfLoaderImpl(const Input* input) GltfLoaderImpl(const Input& input, const bool useBadRotationFormulas)
: m_input(input) : m_input(input),
m_bad_rotation_formulas(useBadRotationFormulas)
{ {
} }
@@ -449,7 +450,7 @@ namespace
return std::nullopt; return std::nullopt;
} }
static void ApplyNodeMatrixTRS(const JsonNode& node, float (&localOffsetRhc)[3], float (&localRotationRhc)[4], float (&scaleRhc)[3]) void ApplyNodeMatrixTRS(const JsonNode& node, float (&localOffsetRhc)[3], float (&localRotationRhc)[4], float (&scaleRhc)[3])
{ {
const auto matrix = Eigen::Matrix4f({ const auto matrix = Eigen::Matrix4f({
{(*node.matrix)[0], (*node.matrix)[4], (*node.matrix)[8], (*node.matrix)[12]}, {(*node.matrix)[0], (*node.matrix)[4], (*node.matrix)[8], (*node.matrix)[12]},
@@ -460,29 +461,45 @@ namespace
Eigen::Affine3f transform(matrix); Eigen::Affine3f transform(matrix);
const auto translation = transform.translation(); const auto translation = transform.translation();
localOffsetRhc[0] = translation.x(); localOffsetRhc[0] = translation.x();
localOffsetRhc[1] = translation.y(); localOffsetRhc[1] = translation.y();
localOffsetRhc[2] = translation.z(); localOffsetRhc[2] = translation.z();
if (m_bad_rotation_formulas)
RhcToLhcCoordinates(localOffsetRhc);
const auto rotation = transform.rotation(); const auto rotation = transform.rotation();
const auto rotationQuat = Eigen::Quaternionf(rotation); const auto rotationQuat = Eigen::Quaternionf(rotation);
localRotationRhc[0] = rotationQuat.x(); if (!m_bad_rotation_formulas)
localRotationRhc[1] = rotationQuat.y(); {
localRotationRhc[2] = rotationQuat.z(); localRotationRhc[0] = rotationQuat.x();
localRotationRhc[3] = rotationQuat.w(); localRotationRhc[1] = rotationQuat.y();
localRotationRhc[2] = rotationQuat.z();
localRotationRhc[3] = rotationQuat.w();
}
else
{
// Backwards compatibility
localRotationRhc[0] = rotationQuat.x();
localRotationRhc[1] = -rotationQuat.z();
localRotationRhc[2] = rotationQuat.y();
localRotationRhc[3] = rotationQuat.w();
}
scaleRhc[0] = matrix.block<3, 1>(0, 0).norm(); scaleRhc[0] = matrix.block<3, 1>(0, 0).norm();
scaleRhc[1] = matrix.block<3, 1>(0, 1).norm(); scaleRhc[1] = matrix.block<3, 1>(0, 1).norm();
scaleRhc[2] = matrix.block<3, 1>(0, 2).norm(); scaleRhc[2] = matrix.block<3, 1>(0, 2).norm();
} }
static void ApplyNodeSeparateTRS(const JsonNode& node, float (&localOffsetRhc)[3], float (&localRotationRhc)[4], float (&scaleRhc)[3]) void ApplyNodeSeparateTRS(const JsonNode& node, float (&localOffsetRhc)[3], float (&localRotationRhc)[4], float (&scaleRhc)[3])
{ {
if (node.translation) if (node.translation)
{ {
localOffsetRhc[0] = (*node.translation)[0]; localOffsetRhc[0] = (*node.translation)[0];
localOffsetRhc[1] = (*node.translation)[1]; localOffsetRhc[1] = (*node.translation)[1];
localOffsetRhc[2] = (*node.translation)[2]; localOffsetRhc[2] = (*node.translation)[2];
if (m_bad_rotation_formulas)
RhcToLhcCoordinates(localOffsetRhc);
} }
else else
{ {
@@ -493,10 +510,21 @@ namespace
if (node.rotation) if (node.rotation)
{ {
localRotationRhc[0] = (*node.rotation)[0]; if (!m_bad_rotation_formulas)
localRotationRhc[1] = (*node.rotation)[1]; {
localRotationRhc[2] = (*node.rotation)[2]; localRotationRhc[0] = (*node.rotation)[0];
localRotationRhc[3] = (*node.rotation)[3]; localRotationRhc[1] = (*node.rotation)[1];
localRotationRhc[2] = (*node.rotation)[2];
localRotationRhc[3] = (*node.rotation)[3];
}
else
{
// Backwards compatibility
localRotationRhc[0] = (*node.rotation)[0];
localRotationRhc[1] = -(*node.rotation)[2];
localRotationRhc[2] = (*node.rotation)[1];
localRotationRhc[3] = (*node.rotation)[3];
}
} }
else else
{ {
@@ -520,15 +548,15 @@ namespace
} }
} }
static bool ConvertJoint(const JsonRoot& jRoot, bool ConvertJoint(const JsonRoot& jRoot,
const JsonSkin& skin, const JsonSkin& skin,
XModelCommon& common, XModelCommon& common,
const unsigned skinBoneOffset, const unsigned skinBoneOffset,
const unsigned nodeIndex, const unsigned nodeIndex,
const std::optional<unsigned> parentIndex, const std::optional<unsigned> parentIndex,
const Eigen::Vector3f& parentTranslationEigenRhc, const Eigen::Vector3f& parentTranslationEigenRhc,
const Eigen::Quaternionf& parentRotationEigenRhc, const Eigen::Quaternionf& parentRotationEigenRhc,
const float (&parentScale)[3]) const float (&parentScale)[3])
{ {
if (!jRoot.nodes || nodeIndex >= jRoot.nodes->size()) if (!jRoot.nodes || nodeIndex >= jRoot.nodes->size())
return false; return false;
@@ -555,7 +583,8 @@ namespace
bone.scale[0] = localScaleRhc[0] * parentScale[0]; bone.scale[0] = localScaleRhc[0] * parentScale[0];
bone.scale[1] = localScaleRhc[1] * parentScale[1]; bone.scale[1] = localScaleRhc[1] * parentScale[1];
bone.scale[2] = localScaleRhc[2] * parentScale[2]; bone.scale[2] = localScaleRhc[2] * parentScale[2];
RhcToLhcScale(bone.scale); if (!m_bad_rotation_formulas)
RhcToLhcScale(bone.scale);
const Eigen::Vector3f localTranslationEigen(localOffsetRhc[0], localOffsetRhc[1], localOffsetRhc[2]); const Eigen::Vector3f localTranslationEigen(localOffsetRhc[0], localOffsetRhc[1], localOffsetRhc[2]);
const Eigen::Quaternionf localRotationEigen(localRotationRhc[3], localRotationRhc[0], localRotationRhc[1], localRotationRhc[2]); const Eigen::Quaternionf localRotationEigen(localRotationRhc[3], localRotationRhc[0], localRotationRhc[1], localRotationRhc[2]);
@@ -566,13 +595,15 @@ namespace
bone.globalOffset[0] = globalTranslationEigenRhc.x(); bone.globalOffset[0] = globalTranslationEigenRhc.x();
bone.globalOffset[1] = globalTranslationEigenRhc.y(); bone.globalOffset[1] = globalTranslationEigenRhc.y();
bone.globalOffset[2] = globalTranslationEigenRhc.z(); bone.globalOffset[2] = globalTranslationEigenRhc.z();
RhcToLhcCoordinates(bone.globalOffset); if (!m_bad_rotation_formulas)
RhcToLhcCoordinates(bone.globalOffset);
bone.globalRotation.x = globalRotationEigenRhc.x(); bone.globalRotation.x = globalRotationEigenRhc.x();
bone.globalRotation.y = globalRotationEigenRhc.y(); bone.globalRotation.y = globalRotationEigenRhc.y();
bone.globalRotation.z = globalRotationEigenRhc.z(); bone.globalRotation.z = globalRotationEigenRhc.z();
bone.globalRotation.w = globalRotationEigenRhc.w(); bone.globalRotation.w = globalRotationEigenRhc.w();
RhcToLhcQuaternion(bone.globalRotation); if (!m_bad_rotation_formulas)
RhcToLhcQuaternion(bone.globalRotation);
if (node.children) if (node.children)
{ {
@@ -587,7 +618,7 @@ namespace
return true; return true;
} }
static bool ConvertSkin(const JsonRoot& jRoot, const JsonSkin& skin, XModelCommon& common) bool ConvertSkin(const JsonRoot& jRoot, const JsonSkin& skin, XModelCommon& common)
{ {
if (skin.joints.empty()) if (skin.joints.empty())
return true; return true;
@@ -683,7 +714,7 @@ namespace
{ {
const void* embeddedBufferPtr = nullptr; const void* embeddedBufferPtr = nullptr;
size_t embeddedBufferSize = 0u; size_t embeddedBufferSize = 0u;
if (!m_input->GetEmbeddedBuffer(embeddedBufferPtr, embeddedBufferSize) || embeddedBufferSize == 0u) if (!m_input.GetEmbeddedBuffer(embeddedBufferPtr, embeddedBufferSize) || embeddedBufferSize == 0u)
throw GltfLoadException("Buffer tried to access embedded data when there is none"); throw GltfLoadException("Buffer tried to access embedded data when there is none");
m_buffers.emplace_back(std::make_unique<EmbeddedBuffer>(embeddedBufferPtr, embeddedBufferSize)); m_buffers.emplace_back(std::make_unique<EmbeddedBuffer>(embeddedBufferPtr, embeddedBufferSize));
@@ -763,7 +794,7 @@ namespace
JsonRoot jRoot; JsonRoot jRoot;
try try
{ {
jRoot = m_input->GetJson().get<JsonRoot>(); jRoot = m_input.GetJson().get<JsonRoot>();
} }
catch (const nlohmann::json::exception& e) catch (const nlohmann::json::exception& e)
{ {
@@ -793,7 +824,7 @@ namespace
} }
private: private:
const Input* m_input; const Input& m_input;
std::vector<ObjectToLoad> m_load_objects; std::vector<ObjectToLoad> m_load_objects;
std::unordered_map<AccessorsForVertex, unsigned> m_vertex_offset_for_accessors; std::unordered_map<AccessorsForVertex, unsigned> m_vertex_offset_for_accessors;
std::vector<std::unique_ptr<Accessor>> m_accessors; std::vector<std::unique_ptr<Accessor>> m_accessors;
@@ -804,7 +835,7 @@ namespace
}; };
} // namespace } // namespace
std::unique_ptr<Loader> Loader::CreateLoader(const Input* input) std::unique_ptr<Loader> Loader::CreateLoader(const Input& input, bool useBadRotationFormulas)
{ {
return std::make_unique<GltfLoaderImpl>(input, useBadRotationFormulas); return std::make_unique<GltfLoaderImpl>(input, useBadRotationFormulas);
} }

View File

@@ -19,6 +19,13 @@ namespace gltf
Loader& operator=(const Loader& other) = default; Loader& operator=(const Loader& other) = default;
Loader& operator=(Loader&& other) noexcept = default; Loader& operator=(Loader&& other) noexcept = default;
static std::unique_ptr<Loader> CreateLoader(const Input* input); /**
* \brief Creates a loader capable of loading gltf-like files
* \param input The gltf input
* \param useBadRotationFormulas Old versions used bad formulas for converting into gltf space. Set to \c true to use them for loading to preserve
* backwards compatibility.
* \return
*/
static std::unique_ptr<Loader> CreateLoader(const Input& input, bool useBadRotationFormulas);
}; };
} // namespace gltf } // namespace gltf

View File

@@ -57,7 +57,8 @@ namespace
{ {
public: public:
XModelLoader(MemoryManager& memory, ISearchPath& searchPath, ZoneScriptStrings& scriptStrings) XModelLoader(MemoryManager& memory, ISearchPath& searchPath, ZoneScriptStrings& scriptStrings)
: m_memory(memory), : m_gltf_bad_rotation_formulas(false),
m_memory(memory),
m_search_path(searchPath), m_search_path(searchPath),
m_script_strings(scriptStrings) m_script_strings(scriptStrings)
{ {
@@ -97,12 +98,14 @@ namespace
jRoot.at("_type").get_to(type); jRoot.at("_type").get_to(type);
jRoot.at("_version").get_to(version); jRoot.at("_version").get_to(version);
if (type != "xmodel" || version != 1u) if (type != "xmodel" || version < 1u || version > 2u)
{ {
std::cerr << std::format("Tried to load xmodel \"{}\" but did not find expected type material of version 1\n", xmodel.name); std::cerr << std::format("Tried to load xmodel \"{}\" but did not find expected type material of version 1 or 2\n", xmodel.name);
return false; return false;
} }
m_gltf_bad_rotation_formulas = version == 1u;
const auto jXModel = jRoot.get<JsonXModel>(); const auto jXModel = jRoot.get<JsonXModel>();
return CreateXModelFromJson(jXModel, xmodel, context, registration); return CreateXModelFromJson(jXModel, xmodel, context, registration);
} }
@@ -119,7 +122,7 @@ namespace
std::cerr << std::format("Cannot load xmodel \"{}\": {}\n", xmodel.name, message); std::cerr << std::format("Cannot load xmodel \"{}\": {}\n", xmodel.name, message);
} }
static std::unique_ptr<XModelCommon> LoadModelByExtension(std::istream& stream, const std::string& extension) std::unique_ptr<XModelCommon> LoadModelByExtension(std::istream& stream, const std::string& extension) const
{ {
if (extension == ".glb") if (extension == ".glb")
{ {
@@ -127,7 +130,7 @@ namespace
if (!input.ReadGltfData(stream)) if (!input.ReadGltfData(stream))
return nullptr; return nullptr;
const auto loader = gltf::Loader::CreateLoader(&input); const auto loader = gltf::Loader::CreateLoader(input, m_gltf_bad_rotation_formulas);
return loader->Load(); return loader->Load();
} }
@@ -137,7 +140,7 @@ namespace
if (!input.ReadGltfData(stream)) if (!input.ReadGltfData(stream))
return nullptr; return nullptr;
const auto loader = gltf::Loader::CreateLoader(&input); const auto loader = gltf::Loader::CreateLoader(input, m_gltf_bad_rotation_formulas);
return loader->Load(); return loader->Load();
} }
@@ -1072,6 +1075,8 @@ namespace
return true; return true;
} }
bool m_gltf_bad_rotation_formulas;
std::vector<XSurface> m_surfaces; std::vector<XSurface> m_surfaces;
std::vector<Material*> m_materials; std::vector<Material*> m_materials;

View File

@@ -690,7 +690,7 @@ namespace
jRoot["$schema"] = "http://openassettools.dev/schema/xmodel.v1.json"; jRoot["$schema"] = "http://openassettools.dev/schema/xmodel.v1.json";
jRoot["_type"] = "xmodel"; jRoot["_type"] = "xmodel";
jRoot["_version"] = 1; jRoot["_version"] = 2;
jRoot["_game"] = GAME_LOWER; jRoot["_game"] = GAME_LOWER;
m_stream << std::setw(4) << jRoot << "\n"; m_stream << std::setw(4) << jRoot << "\n";