feat: 透明材质 alpha blending——独立队列 + 线性 over 混合 + 距离排序
透明来源:glTF alphaMode=BLEND(解析期读取,OBJ/FBX 恒不透明—— 资产格式定义写死);MASK 后续演进。Material 加透明语义(入缓存键), 程序化测试资产 CreateTransparentPlane(RGBA 纯色纹理)。 SceneRenderer:透明材质实例收集进独立 scratch(仅主视图,不投 阴影——alpha 阴影后续演进),batch 按平均距离降序排序(远→近, batchMats 同步重排),SSBO 扁平化顺序 = 排序后顺序。 ForwardPass 两段绘制:不透明(无混合 + 深度写)→ 透明(Shader Object 动态状态切 SRC_ALPHA/ONE_MINUS_SRC_ALPHA 线性 over + 深度 只测不写);velocity 附件透明段直写(透明表面 velocity 即自身运动)。 frag alpha = albedo 贴图 a 直通,预乘在 tonemap 段(hard constraint 不变)。已知边界:TAA alpha 时域混合(透明边缘几帧渐显);同 batch 多实例不做实例级排序。
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/GltfMaterial.h> // AI_MATKEY_GLTF_ALPHAMODE
|
||||
|
||||
#include <meshoptimizer.h>
|
||||
|
||||
@@ -81,15 +82,19 @@ void Model::InitDefaultTextures()
|
||||
Model::Model(Device& device, MemoryAllocator& allocator,
|
||||
DescriptorManager& descriptorManager,
|
||||
vk::DescriptorSetLayout textureLayout,
|
||||
ProceduralTag, f32 halfSize, const std::array<u8, 3>& color)
|
||||
ProceduralTag, f32 halfSize, const std::array<u8, 4>& rgba,
|
||||
bool transparent)
|
||||
: m_Device(device)
|
||||
, m_Allocator(allocator)
|
||||
, m_DescriptorManager(descriptorManager)
|
||||
, m_TextureLayout(textureLayout)
|
||||
{
|
||||
// 纯色 1x1 贴图(albedo 兜底)
|
||||
// 纯色贴图(albedo 兜底;alpha 非全 1 时为半透明材质)
|
||||
InitDefaultTextures();
|
||||
auto tex = Texture::CreateSolidColor(device, allocator, color[0], color[1], color[2]);
|
||||
auto tex = (rgba[3] == 255)
|
||||
? Texture::CreateSolidColor(device, allocator, rgba[0], rgba[1], rgba[2])
|
||||
: Texture::CreateSolidColorRGBA(device, allocator,
|
||||
rgba[0], rgba[1], rgba[2], rgba[3]);
|
||||
|
||||
// XZ 平面,法线 +Y,从上往下看 CCW 绕序
|
||||
const f32 h = halfSize;
|
||||
@@ -104,7 +109,7 @@ Model::Model(Device& device, MemoryAllocator& allocator,
|
||||
|
||||
// 材质/纹理生命周期随模型(缓存持有)
|
||||
std::string paths[Material::kSlotCount] = {"", "", "", ""};
|
||||
Material* mat = GetOrCreateMaterial(paths, MaterialParams{}); // 全默认材质
|
||||
Material* mat = GetOrCreateMaterial(paths, MaterialParams{}, transparent);
|
||||
|
||||
m_Meshes.push_back(CreateScope<Mesh>(
|
||||
m_Device, m_Allocator, vertices, lodIndices, mat));
|
||||
@@ -118,7 +123,20 @@ Scope<Model> Model::CreatePlane(Device& device, MemoryAllocator& allocator,
|
||||
{
|
||||
return Scope<Model>(new Model(device, allocator, descriptorManager,
|
||||
textureLayout, ProceduralTag{},
|
||||
halfSize, std::array<u8, 3>{r, g, b}));
|
||||
halfSize, std::array<u8, 4>{r, g, b, 255},
|
||||
false));
|
||||
}
|
||||
|
||||
Scope<Model> Model::CreateTransparentPlane(
|
||||
Device& device, MemoryAllocator& allocator,
|
||||
DescriptorManager& descriptorManager,
|
||||
vk::DescriptorSetLayout textureLayout,
|
||||
f32 halfSize, u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
return Scope<Model>(new Model(device, allocator, descriptorManager,
|
||||
textureLayout, ProceduralTag{},
|
||||
halfSize, std::array<u8, 4>{r, g, b, a},
|
||||
true));
|
||||
}
|
||||
|
||||
ParsedModel Model::ParseFromDisk(const std::string& path)
|
||||
@@ -245,9 +263,10 @@ Texture* Model::GetOrLoadTexture(const std::string& rawPath, bool srgb)
|
||||
}
|
||||
|
||||
Material* Model::GetOrCreateMaterial(const std::string paths[Material::kSlotCount],
|
||||
const MaterialParams& params)
|
||||
const MaterialParams& params,
|
||||
bool transparent)
|
||||
{
|
||||
const std::string key = Material::MakeCacheKey(paths, params);
|
||||
const std::string key = Material::MakeCacheKey(paths, params, transparent);
|
||||
if (auto it = m_MaterialCache.find(key); it != m_MaterialCache.end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
@@ -267,7 +286,7 @@ Material* Model::GetOrCreateMaterial(const std::string paths[Material::kSlotCoun
|
||||
|
||||
auto mat = CreateScope<Material>(
|
||||
m_Device, m_Allocator, m_DescriptorManager, m_TextureLayout,
|
||||
textures, params);
|
||||
textures, params, transparent);
|
||||
Material* ptr = mat.get();
|
||||
m_MaterialCache.emplace(key, std::move(mat));
|
||||
return ptr;
|
||||
@@ -391,6 +410,14 @@ ParsedMesh Model::ProcessMesh(const aiMesh* mesh, const aiScene* scene,
|
||||
material->Get(AI_MATKEY_ROUGHNESS_FACTOR, roughness);
|
||||
params.factors = glm::vec4(static_cast<f32>(metallic),
|
||||
static_cast<f32>(roughness), 0.0f, 0.0f);
|
||||
|
||||
// glTF alphaMode:BLEND = 半透明(透明绘制队列 + 深度只测不写)。
|
||||
// MASK(alpha cutout)暂按不透明——需要 alpha test,后续演进。
|
||||
// OBJ/FBX 无此键 → 恒不透明(资产格式定义写死)
|
||||
aiString alphaMode;
|
||||
if (material->Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode) == AI_SUCCESS) {
|
||||
out.transparent = (alphaMode == aiString("BLEND"));
|
||||
}
|
||||
} else {
|
||||
f32 roughnessFactor = 1.0f;
|
||||
if (texPaths[Material::MetallicRoughness].empty()) {
|
||||
@@ -409,6 +436,7 @@ ParsedMesh Model::ProcessMesh(const aiMesh* mesh, const aiScene* scene,
|
||||
out.texPaths[slot] = std::move(texPaths[slot]);
|
||||
}
|
||||
out.params = params;
|
||||
// out.transparent 已在 glTF 分支读取
|
||||
|
||||
// ---- LOD 链(解析期生成,worker 线程免费时间):----
|
||||
// LOD0 = 原始;每级目标索引数减半,相对误差 1e-2。顶点共享,
|
||||
|
||||
Reference in New Issue
Block a user