feat: 解析式 PBR(Cook-Torrance GGX,metallic-roughness 工作流)

- 修 void* 指针算术警告(Texture::InitFromDds)
- Material:slot2 语义切为 metallicRoughness(glTF 约定 G=粗糙度
  B=金属度)+ 新增材质因子参数 UBO(binding 4,per-slot ring,
  创建时写死,metallic/roughness 因子乘 MR 贴图)
- simple_shader.frag:Blinn-Phong → Cook-Torrance(GGX 分布 +
  Smith 几何 + Schlick Fresnel,k=(r+1)²/8 解析光源版);金属不参与
  漫反射;环境光暂为常数(IBL 后续)
- Model:读 aiTextureType_UNKNOWN(glTF MR 落点)+ AI_MATKEY_
  METALLIC/ROUGHNESS_FACTOR(旧资产缺键退化为电介质 0/0.5);
  材质缓存键含因子
- main.cpp:演示场景换回 backpack(旧资产走因子路径验证 PBR 全链路)
- 旧 specular 贴图不再使用(语义被 MR 取代)
This commit is contained in:
2026-09-23 18:01:14 +08:00
parent 2c4efc5165
commit 89bf4256e8
23 changed files with 449 additions and 371 deletions
+22 -11
View File
@@ -38,13 +38,13 @@ Model::~Model() = default;
void Model::InitDefaultTextures()
{
// 各材质槽位的兜底纹理(1x1,开销可忽略):
// albedo 白(受光) / normal 平法线 (0.5,0.5,1) / specular 黑 / emissive 黑
// albedo 白 / MR 平参数(roughness 0.5, metallic 0)/ emissive 黑
m_DefaultTextures[Material::Albedo] =
Texture::CreateSolidColor(m_Device, m_Allocator, 255, 255, 255);
m_DefaultTextures[Material::MetallicRoughness] =
Texture::CreateSolidColor(m_Device, m_Allocator, 0, 128, 0, false);
m_DefaultTextures[Material::Normal] =
Texture::CreateSolidColor(m_Device, m_Allocator, 128, 128, 255, false);
m_DefaultTextures[Material::Specular] =
Texture::CreateSolidColor(m_Device, m_Allocator, 0, 0, 0, false);
m_DefaultTextures[Material::Emissive] =
Texture::CreateSolidColor(m_Device, m_Allocator, 0, 0, 0);
}
@@ -74,7 +74,7 @@ Model::Model(Device& device, MemoryAllocator& allocator,
// 材质/纹理生命周期随模型(缓存持有)
std::string paths[Material::kSlotCount] = {"", "", "", ""};
Material* mat = GetOrCreateMaterial(paths); // 全默认材质
Material* mat = GetOrCreateMaterial(paths, MaterialParams{}); // 全默认材质
m_Meshes.push_back(CreateScope<Mesh>(
m_Device, m_Allocator, vertices, indices, mat));
@@ -148,9 +148,10 @@ Texture* Model::GetOrLoadTexture(const std::string& rawPath, bool srgb)
return ptr;
}
Material* Model::GetOrCreateMaterial(const std::string paths[Material::kSlotCount])
Material* Model::GetOrCreateMaterial(const std::string paths[Material::kSlotCount],
const MaterialParams& params)
{
const std::string key = Material::MakeCacheKey(paths);
const std::string key = Material::MakeCacheKey(paths, params);
if (auto it = m_MaterialCache.find(key); it != m_MaterialCache.end()) {
return it->second.get();
}
@@ -169,7 +170,8 @@ Material* Model::GetOrCreateMaterial(const std::string paths[Material::kSlotCoun
}
auto mat = CreateScope<Material>(
m_Device, m_DescriptorManager, m_TextureLayout, textures);
m_Device, m_Allocator, m_DescriptorManager, m_TextureLayout,
textures, params);
Material* ptr = mat.get();
m_MaterialCache.emplace(key, std::move(mat));
return ptr;
@@ -225,18 +227,20 @@ Scope<Mesh> Model::ProcessMesh(aiMesh* mesh, const aiScene* scene)
}
}
// 读取材质纹理路径(4 槽:albedo/normal/specular/emissive)
// 读取材质纹理路径(PBR metallic-roughness 槽位)+ 金属度/粗糙度因子
std::string texPaths[Material::kSlotCount];
MaterialParams params;
if (mesh->mMaterialIndex >= 0) {
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
const std::filesystem::path modelDir =
std::filesystem::path(m_ModelPath).parent_path();
// glTF 的 metallicRoughness 贴图落在 aiTextureType_UNKNOWN
const std::pair<aiTextureType, u32> slots[] = {
{aiTextureType_DIFFUSE, Material::Albedo},
{aiTextureType_NORMALS, Material::Normal},
{aiTextureType_SPECULAR, Material::Specular},
{aiTextureType_UNKNOWN, Material::MetallicRoughness},
{aiTextureType_EMISSIVE, Material::Emissive},
};
@@ -247,10 +251,17 @@ Scope<Mesh> Model::ProcessMesh(aiMesh* mesh, const aiScene* scene)
texPaths[slot] = (modelDir / path.C_Str()).string();
}
}
// PBR 因子(glTF2 材质属性;旧资产无此键 → 默认电介质 0/0.5)
ai_real metallic = 0.0f, roughness = 0.5f;
material->Get(AI_MATKEY_METALLIC_FACTOR, metallic);
material->Get(AI_MATKEY_ROUGHNESS_FACTOR, roughness);
params.factors = glm::vec4(static_cast<f32>(metallic),
static_cast<f32>(roughness), 0.0f, 0.0f);
}
// 材质缓存:同贴图组合 → 同一 Material(一个描述符集),mesh 数 ≠ 集数
Material* mat = GetOrCreateMaterial(texPaths);
// 材质缓存:同贴图组合+因子 → 同一 Material(一个描述符集)
Material* mat = GetOrCreateMaterial(texPaths, params);
return CreateScope<Mesh>(
m_Device, m_Allocator, vertices, indices, mat);