Fix some import bugs / add support for separated model + anim file

This commit is contained in:
2026-06-22 01:37:16 +02:00
parent 7e5536a02f
commit 6f679e7329
10 changed files with 1514 additions and 34 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,138 @@
#ifndef MODELDOCUTILS_H
#define MODELDOCUTILS_H
#include "destrum/Util/ModelDoc.h"
#include "spdlog/spdlog.h"
#include <algorithm>
#include <filesystem>
#include <initializer_list>
#include <optional>
#include <stdexcept>
#include <string>
namespace ModelDocUtils {
inline const ModelDoc::MeshPrimitive& GetFirstPrimitiveOrThrow(
const ModelDoc::ModelAsset& model,
const std::string& debugName
) {
if (model.primitives.empty()) {
throw std::runtime_error("ModelDoc loaded no mesh primitives for: " + debugName);
}
return model.primitives.front();
}
inline const ModelDoc::MeshPrimitive& GetFirstSkinnedPrimitiveOrFirstOrThrow(
const ModelDoc::ModelAsset& model,
const std::string& debugName
) {
if (model.primitives.empty()) {
throw std::runtime_error("ModelDoc loaded no mesh primitives for: " + debugName);
}
const auto it = std::find_if(
model.primitives.begin(),
model.primitives.end(),
[](const ModelDoc::MeshPrimitive& primitive) {
return primitive.skinned;
}
);
return it != model.primitives.end() ? *it : model.primitives.front();
}
inline glm::vec3 GetImportedBaseColor(
const ModelDoc::ModelAsset& model,
const ModelDoc::MeshPrimitive& primitive,
const glm::vec3& fallback = glm::vec3(1.0f)
) {
if (primitive.materialIndex == ModelDoc::InvalidIndex ||
primitive.materialIndex >= model.materials.size()) {
return fallback;
}
return glm::vec3(model.materials[primitive.materialIndex].baseColor);
}
inline std::string GetImportedMaterialName(
const ModelDoc::ModelAsset& model,
const ModelDoc::MeshPrimitive& primitive,
const std::string& fallback
) {
if (primitive.materialIndex == ModelDoc::InvalidIndex ||
primitive.materialIndex >= model.materials.size()) {
return fallback;
}
const auto& material = model.materials[primitive.materialIndex];
return material.name.empty() ? fallback : material.name;
}
inline std::optional<std::string> FindFirstTexturePath(
const ModelDoc::ModelAsset& model,
const ModelDoc::MeshPrimitive& primitive,
std::initializer_list<ModelDoc::TextureSemantic> preferredSemantics
) {
if (primitive.materialIndex == ModelDoc::InvalidIndex ||
primitive.materialIndex >= model.materials.size()) {
return std::nullopt;
}
const auto& material = model.materials[primitive.materialIndex];
for (const auto semantic : preferredSemantics) {
for (const auto& texture : material.textures) {
// gfxDevice.loadImageFromFile currently expects a real file path.
// Embedded GLB textures like "*0" need extraction/support in GfxDevice first.
if (texture.semantic == semantic && !texture.embedded && !texture.path.empty()) {
return texture.path;
}
}
}
return std::nullopt;
}
inline std::filesystem::path PickTexturePath(
const ModelDoc::ModelAsset& model,
const ModelDoc::MeshPrimitive& primitive,
const std::filesystem::path& fallbackPath
) {
const auto importedTexturePath = FindFirstTexturePath(
model,
primitive,
{
ModelDoc::TextureSemantic::BaseColor,
ModelDoc::TextureSemantic::Diffuse
}
);
if (importedTexturePath.has_value()) {
return std::filesystem::path(*importedTexturePath);
}
spdlog::info("Using fallback path {}", fallbackPath.string());
return fallbackPath;
}
inline void LogModelDocSummary(
const ModelDoc::ModelAsset& model,
const std::string& label
) {
spdlog::info(
"Loaded {} | primitives: {} | materials: {} | animations: {} | skinned: {}",
label,
model.primitives.size(),
model.materials.size(),
model.animations.size(),
model.IsSkinned()
);
}
} // namespace ModelDocUtils
#endif // MODELDOCUTILS_H
@@ -768,6 +768,35 @@ static SkinnedModel LoadSkinnedModel(const std::string& path) {
return model;
}
struct LoadedMesh {
CPUMesh mesh;
std::vector<std::string> diffuseTexturePaths;
};
static std::vector<std::string> LoadMaterialTexturePaths(
const aiScene* scene,
const aiMesh* mesh,
aiTextureType type,
const std::filesystem::path& modelDir
) {
std::vector<std::string> paths;
if (mesh->mMaterialIndex >= scene->mNumMaterials)
return paths;
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
for (unsigned int i = 0; i < material->GetTextureCount(type); ++i) {
aiString texPath;
if (material->GetTexture(type, i, &texPath) == AI_SUCCESS) {
auto fullPath = modelDir / texPath.C_Str();
paths.push_back(fullPath.generic_string());
}
}
return paths;
}
} // namespace ModelLoader
#endif // MODELLOADER_H