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:
@@ -15,6 +15,9 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#include <chrono>
|
||||
@@ -350,23 +353,34 @@ namespace Engine
|
||||
lodSlots[lod] = batchIdx;
|
||||
s.result.batches.push_back({mesh.get(), 0, 0, lod});
|
||||
s.batchMats.emplace_back();
|
||||
s.batchDistSum.push_back(0.0f);
|
||||
}
|
||||
// 实例归入自己的 batch(mesh 分组),保证同 batch
|
||||
// 实例在扁平化后连续——firstInstance 语义的前提
|
||||
const u32 bi = batchIdx - 1;
|
||||
s.result.batches[bi].count++;
|
||||
s.batchMats[bi].push_back({t.World(), prevWorld});
|
||||
s.batchDistSum[bi] += dist; // 透明排序用
|
||||
s.result.instanceCount++;
|
||||
++totalInstances;
|
||||
};
|
||||
|
||||
tryAppend(m_MainScratch, mainFrustum, mainLod);
|
||||
for (u32 c = 0; c < kMaxCascades; ++c) {
|
||||
if (!cascVis[c]) continue; // 粗剔除已判不可见
|
||||
// 级联降级:越远的级联覆盖范围越大,用越低的 LOD
|
||||
//(阴影本来就是低频信息,误差可接受);开关关闭 = 恒 LOD0
|
||||
tryAppend(m_CascScratch[c], cascFrustum[c],
|
||||
m_LodEnabled ? std::min(c, kMeshLodCount - 1) : 0u);
|
||||
// 透明材质 → 独立队列(主视图,混合绘制 + 排序;
|
||||
// 不进阴影——alpha 阴影复杂度高收益低,注释后续演进)
|
||||
const bool isTransparentMesh =
|
||||
mesh->GetMaterial()->IsTransparent();
|
||||
ViewScratch& mainTarget = isTransparentMesh
|
||||
? m_TranslucentScratch : m_MainScratch;
|
||||
|
||||
tryAppend(mainTarget, mainFrustum, mainLod);
|
||||
if (!isTransparentMesh) {
|
||||
for (u32 c = 0; c < kMaxCascades; ++c) {
|
||||
if (!cascVis[c]) continue; // 粗剔除已判不可见
|
||||
// 级联降级:越远的级联覆盖范围越大,用越低的 LOD
|
||||
//(阴影本来就是低频信息,误差可接受);开关关闭 = 恒 LOD0
|
||||
tryAppend(m_CascScratch[c], cascFrustum[c],
|
||||
m_LodEnabled ? std::min(c, kMeshLodCount - 1) : 0u);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -393,6 +407,44 @@ namespace Engine
|
||||
appendView(m_Frame.shadowCascades[c], m_CascScratch[c]);
|
||||
}
|
||||
|
||||
// ---- 5. 透明批次排序:平均距离降序(远 → 近),连同实例列表同步重排
|
||||
{
|
||||
auto& tb = m_TranslucentScratch.result.batches;
|
||||
if (tb.size() > 1) {
|
||||
std::vector<u32> order(tb.size());
|
||||
std::iota(order.begin(), order.end(), 0);
|
||||
std::sort(order.begin(), order.end(), [&](u32 a, u32 b) {
|
||||
return m_TranslucentScratch.batchDistSum[a] / tb[a].count >
|
||||
m_TranslucentScratch.batchDistSum[b] / tb[b].count;
|
||||
});
|
||||
CullResult sorted;
|
||||
sorted.instanceCount = m_TranslucentScratch.result.instanceCount;
|
||||
std::vector<ViewScratch::InstanceMatrices> sortedMats;
|
||||
std::vector<f32> sortedDist;
|
||||
for (const u32 i : order) {
|
||||
sorted.batches.push_back(tb[i]);
|
||||
sortedDist.push_back(m_TranslucentScratch.batchDistSum[i]);
|
||||
for (auto& m : m_TranslucentScratch.batchMats[i]) {
|
||||
sortedMats.push_back(std::move(m));
|
||||
}
|
||||
}
|
||||
m_TranslucentScratch.result = std::move(sorted);
|
||||
m_TranslucentScratch.batchDistSum = std::move(sortedDist);
|
||||
// batchMats 按新分组的 count 顺序切分重装(保留容量)
|
||||
m_TranslucentScratch.batchMats.assign(
|
||||
m_TranslucentScratch.result.batches.size(), {});
|
||||
u32 offset = 0;
|
||||
for (size_t i = 0; i < m_TranslucentScratch.result.batches.size(); ++i) {
|
||||
const u32 n = m_TranslucentScratch.result.batches[i].count;
|
||||
m_TranslucentScratch.batchMats[i].assign(
|
||||
std::make_move_iterator(sortedMats.begin() + offset),
|
||||
std::make_move_iterator(sortedMats.begin() + offset + n));
|
||||
offset += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
appendView(m_Frame.translucentView, m_TranslucentScratch);
|
||||
|
||||
// 帧末滚动时域状态:cur → prev(每帧重建,销毁的实体自动清出)
|
||||
m_PrevWorlds.swap(m_CurWorlds);
|
||||
m_CurWorlds.clear();
|
||||
|
||||
Reference in New Issue
Block a user