diff --git a/Engine/src/Renderer/Model.cpp b/Engine/src/Renderer/Model.cpp index 3a2a2ee..1715da1 100644 --- a/Engine/src/Renderer/Model.cpp +++ b/Engine/src/Renderer/Model.cpp @@ -94,10 +94,24 @@ void Model::LoadModel(const std::string& path) { m_ModelPath = path; + // UV 翻转按格式区分: + // OBJ/FBX —— v 原点在底部,需翻到左上惯例(配合"v=0=图像顶"采样) + // glTF/GLB —— UV 本就是左上原点(v=0=图像顶),翻转会把所有 + // 贴图上下颠倒(法线/MR 全反 = 塑料感元凶) + const std::string lower = [&] { + std::string s = path; + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { return std::tolower(c); }); + return s; + }(); + const bool isGltf = lower.size() >= 5 && + (lower.rfind(".gltf") == lower.size() - 5 || + lower.rfind(".glb") == lower.size() - 4); + Assimp::Importer importer; const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | - aiProcess_FlipUVs | + (isGltf ? 0 : aiProcess_FlipUVs) | aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace | // 法线贴图 TBN aiProcess_JoinIdenticalVertices); @@ -236,15 +250,22 @@ Scope Model::ProcessMesh(aiMesh* mesh, const aiScene* scene) const std::filesystem::path modelDir = std::filesystem::path(m_ModelPath).parent_path(); - // glTF 的 metallicRoughness 贴图落在 aiTextureType_UNKNOWN + // glTF2 贴图在 assimp 5.x 的落点:MR 合图 → METALNESS(15)/ + // DIFFUSE_ROUGHNESS(16)(同图双槽);baseColor → BASE_COLOR(12)。 + // 先到先得,数组顺序即优先级 const std::pair slots[] = { - {aiTextureType_DIFFUSE, Material::Albedo}, - {aiTextureType_NORMALS, Material::Normal}, - {aiTextureType_UNKNOWN, Material::MetallicRoughness}, - {aiTextureType_EMISSIVE, Material::Emissive}, + {aiTextureType_DIFFUSE, Material::Albedo}, + {aiTextureType_BASE_COLOR, Material::Albedo}, + {aiTextureType_NORMALS, Material::Normal}, + {aiTextureType_METALNESS, Material::MetallicRoughness}, + {aiTextureType_DIFFUSE_ROUGHNESS, Material::MetallicRoughness}, + {aiTextureType_UNKNOWN, Material::MetallicRoughness}, + {aiTextureType_EMISSIVE, Material::Emissive}, + {aiTextureType_EMISSION_COLOR, Material::Emissive}, }; for (const auto& [type, slot] : slots) { + if (!texPaths[slot].empty()) continue; // 高优先级已命中 aiString path; if (material->GetTexture(type, 0, &path) == AI_SUCCESS && path.length > 0) { @@ -252,6 +273,19 @@ Scope Model::ProcessMesh(aiMesh* mesh, const aiScene* scene) } } + // 材质加载可见性:贴图槽缺失/路径解析错误会静默退化成默认 + // 纹理(金属全没 → 塑料感),这里留下诊断锚点 + ENGINE_INFO("Material '{}': albedo={} normal={} MR={} emissive={}", + material->GetName().C_Str(), + texPaths[Material::Albedo].empty() ? "" + : texPaths[Material::Albedo], + texPaths[Material::Normal].empty() ? "" + : texPaths[Material::Normal], + texPaths[Material::MetallicRoughness].empty() ? "" + : texPaths[Material::MetallicRoughness], + texPaths[Material::Emissive].empty() ? "" + : texPaths[Material::Emissive]); + // PBR 因子(glTF2 材质属性;旧资产无此键 → 默认电介质 0/0.5) ai_real metallic = 0.0f, roughness = 0.5f; material->Get(AI_MATKEY_METALLIC_FACTOR, metallic);