跳到主要内容
腾讯题库 · Q11
先读 30 秒回答

第 11 题 / 50

学习状态 未开始

软遮挡与可见性

面试官问

PDF 第 26 页

如何在 Shader 中实现“动态遮挡剔除”(Soft Occlusion Culling)?请说明其与传统遮挡查询的区别。(冷门题,理清逻辑)

Shader occlusion · shader 对应课程:graphics-debugger

先把问题答上

你可以直接这样回答

约 30 秒

Shader 软遮挡可以读取 scene depth 与 sample depth,按深度差和 softness 生成连续可见度;传统遮挡查询通常返回整物体的可见/不可见并由 CPU/GPU 协同。软遮挡改善边缘,但不自动减少 draw call,必须分别测 overdraw 和提交成本。

这道题真正想听什么?

先确认比较对象和回答边界,再决定要不要展开公式、工程实现或性能取舍。

这里的“软”不是把物体模糊掉,而是让遮挡可见度从硬切变成带证据的权重。Shader 可以读取场景深度,与当前样本深度比较,再按 softness 平滑;传统遮挡查询通常由 CPU/GPU 查询包围体是否被遮挡,结果多是可见/不可见并可能隔帧返回。前者适合像素级柔边,但会付出深度读取和 overdraw;后者更适合整物体剔除,不能直接给每个边缘一条渐变。

把答案讲到 2 分钟面试必答 · 约 2 分钟 · 补足因果、输入和取舍

我会先说明深度预写、深度差和 smoothstep 权重,再强调信息粒度差异:像素 shader 做的是可见度估计,传统 query 做的是对象级剔除。实验固定场景,只改 softness 和 prepass,观察遮挡权重、overdraw、draw calls 与延迟,避免把任何变暗都称为剔除。

面试官可能继续追问什么?补充自测 · 约 3 分钟 · 检查自己是不是真的懂了
  • 问:Soft Occlusion Culling 能省掉整个物体的 draw call 吗? 答:像素 shader 里的权重通常不能在提交前取消整物体;要省提交,需要 CPU/GPU query、层级深度或实例可见性方案。
  • 问:depth prepass 的作用是什么? 答:先写可信深度,给后续遮挡判断和 early-Z 提供证据;它本身也有一次绘制/带宽成本。
  • 因果链: 场景深度 → 样本深度差 → softness 权重 → 片元可见度/overdraw。不能把可见度权重直接当作真正剔除证明。
如果概念还是悬空,就去做实验关键证据 · 约 5–15 分钟 · 预测 → 单变量 → 观察

实验不是第二份答案,它只负责证明答案

如果上面的解释已经听懂,可以直接跳过。卡住时,再沿着这三步把抽象词变成画面证据。

  1. 先猜 这份数据从哪里进入 Shader,经过哪一步,最后改变哪个像素?
  2. 去取证 固定其他条件,只改一个参数。先写下变化,不用“更真实”“更高级”这种空词代替证据。
  3. 再追问为什么 是哪一步造成这个结果?如果结果相反,先检查输入、空间、算法,还是显示输出?
我完全没头绪,给我一个起点

先截下默认状态,只动页面当前开放的那个参数。你只需要说清楚“原来怎样 → 改了什么 → 现在怎样”。

1. 先预测

打开 Rendering Effects Lab,使用透明片与柱子叠放,先把 depthPrepass=trueocclusionSoftness=0.35debugMode=occlusion。预测:增加 softness 会让遮挡边界变柔;关闭 depth prepass 后,遮挡可见度和后续片元工作会更不稳定。把边界想成门缝:深度比较是“谁在门前”,softness 是“门缝从全开到全关的渐变”。

公式的口语翻译:

visibility = smoothstep(-softness, softness, sceneDepth - sampleDepth)

它是在深度差上套一条“缓坡”:差距很大时接近 0/1,接近边缘时连续过渡。它不是传统 occlusion query 的布尔结果,也不是颜色亮度。

老师追问

先别急着查答案: 先追一条数据从输入到像素:它经过哪一步计算,哪一个中间通道会先暴露问题?

为什么: 你刚才的预测依赖哪个前提?如果把“软遮挡与可见性”里最关键的变量或约束关掉,画面/输出会先坏在哪里?

如果结果相反: 先排除哪一层,再谈结论?这个规则的边界是什么?

2. 再动手

软遮挡代码 固定 alpha 与颜色,只改 occlusionSoftness=0/0.35/1;再切换 depthPrepass。到 粒子/性能代码 查看 overdraw,记录边缘质量、遮挡权重和估算成本。最后写一句:当前结果是像素级权重,还是提交级剔除。

3. 最后对证据

softness 为 0 时边界接近硬切,增大后出现连续过渡;拉到 1 会像一层雾,空间关系变弱。关闭预写不一定立刻改变颜色,却可能提高透明 overdraw/可见度误差。occlusion-visibility 只证明当前样本的遮挡估计,不能证明 CPU 已省下 draw call。

答案在代码哪里发生?实现定位 · 约 3 分钟 · 变量、函数和关键行
完整 5 分钟版本面试扩展 · 约 5 分钟 · 项目边界、验证与降级

项目里可把层级遮挡/查询用于整物体剔除,把 shader 软权重留给透明边缘或细小遮挡;移动端优先减少透明层、降低深度分辨率或改用 dither/cutout。要规定深度格式、排序、预写和阴影的边界,并保留 debug/fallback。当前 Lab 的深度与成本为教学近似,不能直接推断真实驱动的 early-Z 行为。

哪些说法最容易答歪?必看陷阱 · 约 1 分钟 · 面试前最后检查
  • 把片元可见度当作 CPU 已跳过 draw call。
  • 把 softness 拉满当抗锯齿,导致所有深度边界雾化。
  • 不检查深度空间/线性化,深度差符号反了。
  • 用增加预写解决所有问题,却忘记它本身的提交和带宽成本。