fix: 金属渲染塑料感——glTF MR 贴图未加载 + UV 翻转错误
- assimp 5.x glTF2 importer 把 MR 合图落在 METALNESS(15)/ DIFFUSE_ROUGHNESS(16),不是 UNKNOWN(18)——此前 metallic 恒 0 全走电介质路径。槽位查找改为优先级数组(先到先得) - glTF 的 UV 本就是左上原点,aiProcess_FlipUVs 会把全部贴图上下 颠倒(法线/MR 分布全反)——按扩展名区分 flip - 材质加载 INFO 日志(贴图槽缺失会静默退化默认纹理,留诊断锚点)
This commit is contained in:
@@ -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<Mesh> 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<aiTextureType, u32> 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<Mesh> Model::ProcessMesh(aiMesh* mesh, const aiScene* scene)
|
||||
}
|
||||
}
|
||||
|
||||
// 材质加载可见性:贴图槽缺失/路径解析错误会静默退化成默认
|
||||
// 纹理(金属全没 → 塑料感),这里留下诊断锚点
|
||||
ENGINE_INFO("Material '{}': albedo={} normal={} MR={} emissive={}",
|
||||
material->GetName().C_Str(),
|
||||
texPaths[Material::Albedo].empty() ? "<none>"
|
||||
: texPaths[Material::Albedo],
|
||||
texPaths[Material::Normal].empty() ? "<none>"
|
||||
: texPaths[Material::Normal],
|
||||
texPaths[Material::MetallicRoughness].empty() ? "<none>"
|
||||
: texPaths[Material::MetallicRoughness],
|
||||
texPaths[Material::Emissive].empty() ? "<none>"
|
||||
: texPaths[Material::Emissive]);
|
||||
|
||||
// PBR 因子(glTF2 材质属性;旧资产无此键 → 默认电介质 0/0.5)
|
||||
ai_real metallic = 0.0f, roughness = 0.5f;
|
||||
material->Get(AI_MATKEY_METALLIC_FACTOR, metallic);
|
||||
|
||||
Reference in New Issue
Block a user