feat: LOD 网格分级——meshopt 解析期简化 + 按距离/级联选级
vendored meshoptimizer 1.2(submodule 环境故障改直接 vendor)。Mesh 多 LOD:各级索引连续拼进同一 index buffer(共享顶点,LodRange 区间 选择),解析期 meshopt_simplify 生成链(LOD0=原始,每级目标减半, 相对误差 1e-2,小网格复用上级);都在 worker 线程,加载零额外卡顿。 SceneRenderer 按 (mesh, LOD) 聚合 batch(lookup key = 指针<<8|lod): 主视图按屏占比近似 radius/dist 选级(阈值 10/20 倍半径);阴影级联 按级联序降级(越远越简)。Draw 按 batch.lod 选索引区间。 A/B 对比(100 背包 10×10,RTX 5060 Laptop,vsync off): - 纯背包:LOD 开 93-95 fps / 关 90-107 fps —— 无显著差异 - 加 SunTemple:LOD 开 52-56 / 关 51-55 —— 无显著差异 结论:当前场景瓶颈不在顶点数(5060 顶点吞吐富余),LOD 基础设施 保留(几何复杂资产/低端 GPU/更大场景生效),帧率问题转向 Tracy GPU 时间线定位真实瓶颈。 坑:LodRange 记录"LOD 不足复用最后一级"时 first 不得继续累加 (buffer 无重复数据,累加必越界——VUID-08798 抓的)。
This commit is contained in:
@@ -297,7 +297,19 @@ namespace Engine
|
||||
glm::vec3(t.World() * glm::vec4(bounds.center, 1.0f));
|
||||
const f32 worldRadius = bounds.radius * worldScale;
|
||||
|
||||
auto tryAppend = [&](ViewScratch& s, const Frustum& frustum) {
|
||||
// LOD 选级:屏占比近似 = radius/距离(主视图按实例距离;
|
||||
// 阈值 10/20 倍半径,可调)
|
||||
const f32 dist =
|
||||
glm::length(worldCenter - camTransform->GetPosition());
|
||||
u32 mainLod = 0;
|
||||
if (dist >= worldRadius * 20.0f) {
|
||||
mainLod = 2;
|
||||
} else if (dist >= worldRadius * 10.0f) {
|
||||
mainLod = 1;
|
||||
}
|
||||
|
||||
auto tryAppend = [&](ViewScratch& s, const Frustum& frustum,
|
||||
u32 lod) {
|
||||
if (!frustum.IntersectsSphere(worldCenter, worldRadius)) {
|
||||
return;
|
||||
}
|
||||
@@ -309,10 +321,12 @@ namespace Engine
|
||||
// 单实体时两序号恰好恒等,多实体共享 mesh 后分叉
|
||||
// → batches[worldsIdx] 越界)。batch.first(GPU
|
||||
// firstInstance 基址)才是 worlds 索引,语义别混
|
||||
const u64 key =
|
||||
(reinterpret_cast<u64>(mesh.get()) << 8) | lod;
|
||||
const auto [it, inserted] = s.lookup.emplace(
|
||||
mesh.get(), static_cast<u32>(s.result.batches.size()));
|
||||
key, static_cast<u32>(s.result.batches.size()));
|
||||
if (inserted) {
|
||||
s.result.batches.push_back({mesh.get(), 0, 0});
|
||||
s.result.batches.push_back({mesh.get(), 0, 0, lod});
|
||||
s.batchWorlds.emplace_back();
|
||||
s.batchPrevWorlds.emplace_back();
|
||||
}
|
||||
@@ -326,9 +340,12 @@ namespace Engine
|
||||
++totalInstances;
|
||||
};
|
||||
|
||||
tryAppend(m_MainScratch, mainFrustum);
|
||||
tryAppend(m_MainScratch, mainFrustum, mainLod);
|
||||
for (u32 c = 0; c < kMaxCascades; ++c) {
|
||||
tryAppend(m_CascScratch[c], cascFrustum[c]);
|
||||
// 级联降级:越远的级联覆盖范围越大,用越低的 LOD
|
||||
//(阴影本来就是低频信息,误差可接受)
|
||||
tryAppend(m_CascScratch[c], cascFrustum[c],
|
||||
std::min(c, kMeshLodCount - 1));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user