想象你是某家大公司的招聘主管。公司放出一个热门岗位,每周有上百份简历涌进来。如果让每个候选人都走完四轮面试、背调、发Offer的全流程,团队早就累垮了。聪明的HR一定会在面试前加一轮“简历初筛”:学历不匹配、经验差距大的,直接婉拒,根本不必进入会议室。图形渲染管线面临的正是同一个问题——三角形被光栅化后产生大量“片元”(屏幕像素的候选者),但其中很多被前方的物体遮挡,永远不会出现在屏幕上。老式渲染管线让每个片元都完成昂贵的着色计算(光照、纹理、阴影)之后,才做深度测试判断是否可见,就像让所有候选人都面完四轮才做背调。Early-Z优化则把深度测试提前到着色之前:被遮挡的片元直接淘汰,根本不进着色器。这就是图形学里的“简历初筛”,一次漂亮的成本手术。

岗位关联

理解“廉价判断前置”的思维,不仅能帮你优化渲染管线,还能迁移到AI推理的粗排/精排架构设计中,让模型把算力花在最有潜力的样本上。

目录
  1. 可视化演示
  2. 渲染管线流程
  3. Z缓冲原理
  4. Early-Z机制
  5. 着色成本对比
  6. 不透明场景收益
  7. 透明物体处理
  8. 工程实践要点
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

渲染管线流程

假如你是一家大型互联网公司的招聘主管,每个岗位每天收到上百份简历。公司的标准流程是:前端HR收集简历(顶点处理),招聘系统按岗位模型筛掉明显不符的候选人(光栅化),剩下的人进入多轮面试(片元着色),最后对通过者做背景调查、发Offer并计入团队名单(深度测试与融合输出)。这个流程中,面试环节的成本最高——资深面试官一小时一小时搭进去,会议室资源被反复占用。

渲染管线与招聘流程高度同构。GPU渲染一个3D三角形时,先由顶点着色器把模型坐标变换到屏幕坐标,相当于把候选人简历归入岗位池;光栅化阶段把三角形离散成屏幕上的像素片元——也就是“屏幕像素的候选者”——相当于从岗位池中筛出候选名单;片元着色器为每一个片元计算颜色,包括光照、纹理、阴影,这是整个管线里指令量最大的环节,好比一场又一场的深度面试;最后,深度测试与颜色混合决定了哪个片元能真正写进帧缓冲,像极了背调后选出唯一人选。

在传统渲染管线中,深度测试被放在片元着色之后。这带来一个巨大的浪费:光栅化可能为同一个像素生成多个片元(多个物体前后重叠),而它们中的大部分会被后面的深度测试判为“不合格”。但这些“不合格者”已经完整执行了昂贵的着色程序,面试官的时间已经被白白消耗。

换句话说,传统管线让每个候选人都走完了全流程才告诉他不合格。如果能在面试前就发现“这个人的简历底色完全不符合岗位要求”,直接婉拒,就能省下大量面试官的时间。这就是Early-Z优化的出发点——在渲染管线上,把“背调/筛选”这个廉价动作提前。

Costrender=∑i=1NfragCshade(i)\displaystyle \text{Cost}_{\text{render}} = \sum_{i=1}^{N_{frag}} C_{\text{shade}}(i)
渲染一帧的总成本,等于所有片元着色开销之和;如果某个片元不进入着色,这一项就是零。
  1. 总成本符号$\text{Cost}_{\text{render}}$ 表示渲染一帧花费的总GPU代价,可以理解为“着色指令数 × 片元数”的累计。
    Costrender=∑i=1NfragCshade(i)\text{Cost}_{\text{render}} = \sum_{i=1}^{N_{frag}} C_{\text{shade}}(i)
  2. 片元下标$N_{frag}$ 是三角形光栅化后产生的所有片元数量,$i$ 从 1 数到 $N_{frag}$,每个片元都占一项。
    1≤i≤Nfrag1 \le i \le N_{frag}
  3. 着色开销项$C_{\text{shade}}(i)$ 是第 $i$ 个片元执行光照、纹理采样等指令的耗时,它是求和中的主要成本来源,而且恒大于零。
    Cshade(i)>0C_{\text{shade}}(i) > 0

Z缓冲原理

Z-Buffer(深度缓冲)可以理解成公司的一张“已录用名单”。屏幕上的每一个像素都对应一个“岗位名额”,名单上记录了该岗位目前最有竞争力的候选人的核心参数——他的“深度值”。深度值越小,代表这个候选人离镜头越近,在遮挡关系中越有优势。

在计算机图形学中,Z-Buffer是一块与屏幕分辨率等大的内存区域,每个像素位置保存一个浮点数,代表已绘制片元的深度。渲染每个新片元时,GPU会取出该像素的旧深度,与当前片元的深度比较,决定“谁更靠近镜头”。这个比较操作本身非常快,远比着色便宜得多。

深度比较的核心规则是:新片元的深度值若小于缓冲中记录的值,则通过测试,并把自己的深度值写回缓冲;否则判定为被遮挡,直接丢弃。这个“越小越靠前”的约定在主流图形API中都是默认行为,也可以根据需求调整比较函数。

有了这份“录用名单”,渲染器才知道每个像素位最终的胜者是谁。而在Early-Z优化中,这份名单更是提前拦截不合格候选人的依据——没有它,提前淘汰就无从谈起。

ztest={Pass,zfrag<zbufFail,zfrag≥zbuf\displaystyle z_{test} =\begin{cases}\text{Pass}, & z_{frag} < z_{buf} \\\text{Fail}, & z_{frag} \ge z_{buf}\end{cases}
当一个片元的深度比Z-Buffer中记录的深度更小时,它通过测试;否则被判定为被遮挡。
  1. 片元深度$z_{frag}$ 是当前片元在屏幕像素上的深度值,越小代表离相机越近,相当于候选人的“竞争力评分”。
    zfrag∈[0,1]z_{frag} \in [0, 1]
  2. 缓冲深度$z_{buf}$ 是Z-Buffer中该像素当前记录的深度,相当于录用名单上已有的最佳候选人成绩。
    zbuf=历史最优深度z_{buf} = \text{历史最优深度}
  3. 比较规则只有当片元深度严格小于缓冲深度时才通过测试;否则被判定为被遮挡。
    zfrag<zbuf⇒Passz_{frag} < z_{buf} \Rightarrow \text{Pass}
  4. 通过后写回通过测试的片元会更新$z_{buf}$,把更小的深度值写回名单,保证名单始终记录最近者。
    zbuf←zfragz_{buf} \leftarrow z_{frag}

Early-Z机制

终于回到Early-Z本身。它的核心思想极其朴素:与其让所有候选人都走完昂贵的面试流程再在背调环节淘汰,不如在面试前就做一轮简历初筛。简历不符合硬性要求的候选人,直接不进入面试环节。这样省下的不只是“最后一轮背调”,而是整个面试过程的全部开销。

在GPU硬件上,Early-Z(也常称为提前深度测试)把深度测试从片元着色之后挪到了片元着色之前。光栅化产生片元后,先用Z-Buffer做一次快速深度比较;如果这个片元的深度不比缓冲中已有的值更小,说明它被前方物体完全遮挡,GPU直接丢弃它,不进入片元着色器。只有通过预测试的片元,才会去执行昂贵的光照和纹理采样。

这一优化对硬件是透明的,不需要程序员手写if语句。GPU在片元着色阶段之前插入一个深度测试单元,消耗微乎其微。代价是,一旦深度值无法在着色前确定,Early-Z就退化为普通深度测试,没有任何收益。

就像招聘主管在门禁处刷一下简历:数据库里显示“学历不符”,候选人连会议室都进不来。Early-Z让不合格的片元被挡在着色器门外,而真正通过初筛的片元才享有完整的面试——着色与混合。

Cfrag={Shade(⋅),zfrag<zbufDiscard,zfrag≥zbuf\displaystyle C_{frag} =\begin{cases}\text{Shade}(\cdot), & z_{frag} < z_{buf} \\\text{Discard}, & z_{frag} \ge z_{buf}\end{cases}
深度测试通过才执行着色;测试失败则直接丢弃片元——这是Early-Z与普通深测的本质区别。
  1. 着色分支当 $z_{frag} < z_{buf}$ 时,片元通过预测试,进入片元着色器执行光照、纹理等计算。
    Shade(⋅)  只在通过后执行\text{Shade}(\cdot) \; \text{只在通过后执行}
  2. 丢弃分支当 $z_{frag} \ge z_{buf}$ 时,片元被前方物体遮挡,GPU直接丢弃,不执行任何着色指令。
    Discard  ⇒  Cshade=0\text{Discard} \; \Rightarrow \; C_{\text{shade}} = 0
  3. 等号含义这个式子描述的是“片元最终经历的处理”,而不是颜色值本身;丢弃分支意味着那一项渲染成本被完全省去。
    Cfrag=实际发生的着色成本C_{frag} = \text{实际发生的着色成本}

着色成本对比

一个岗位收到100份简历,最终录用1人。如果让100个人都完成四轮大面试,成本是 100 × 4 小时;如果先初筛掉80人,只有20人进入面试,成本变成 20 × 4 小时。Early-Z省下的,正是那80人根本不会发生的面试开销。

片元着色是一种非常昂贵的操作。一次完整的着色往往包含多次纹理采样、法线变换、光照模型计算、雾效、阴影贡献等,每个片元可能执行几十到几百条GPU指令。而深度比较只需要一两条指令。所以,在着色前多花一条指令的巨大收益,是省下整段着色程序。

我们用 $N_{total}$ 表示光栅化生成的全部片元数,$N_{pass}$ 表示最终通过深度测试的可见片元数。Early-Z的节省比例是 $1 - N_{pass}/N_{total}$。在不透明场景中,被遮挡的片元往往占大多数,因此这个比例通常超过50%。

回到招聘比喻:如果初筛能精准过滤掉60%的候选人,你省下的就不只是60%的面试官工时,而是60%的会议室预定、差旅报销、面试反馈表。着色器也是一样——省下的片元越多,GPU越有余力提高分辨率、增加特效或降低功耗。

Saving=1−NpassNtotal\displaystyle \text{Saving} = 1 - \frac{N_{pass}}{N_{total}}
节省率 = 1 − 可见片元占比。被剔除的片元越多,着色器越清闲。
  1. 全部片元$N_{total}$ 是光栅化后产生的全部片元数量,包含大量被遮挡的不可见片元。
    Ntotal=光栅化输出片元总数N_{total} = \text{光栅化输出片元总数}
  2. 可见片元$N_{pass}$ 是通过深度测试、真正需要着色的可见片元数量。
    Npass≤NtotalN_{pass} \le N_{total}
  3. 节省计算用 1 减去可见片元占比,就得到被Early-Z拦截的片元比例;不透明场景中通常 $\ge 50\%$。
    Saving=1−NpassNtotal\text{Saving} = 1 - \frac{N_{pass}}{N_{total}}

不透明场景收益

简历初筛有效的前提是岗位标准非常清晰:学历要求、工作年限、技术栈都明确,系统才能一把尺子量到底。不透明物体正是渲染世界里的“标准岗”——它不透明,意味着一旦前面的物体覆盖了后面的物体,后面的物体就一定不可见,深度比较可以给出确定性的答案。

在不透明场景中,Early-Z表现最佳。原因是每个不透明物体只会占用屏幕上的像素,并且完全阻断后方物体的可见性。GPU只要按“从近到远”的顺序绘制场景,Z-Buffer会迅速被最近的表面占据,远处的片元几乎全部在预测试阶段被拒绝。

实践中,游戏引擎通常先做深度预通道(Pre-Z pass),或者直接把不透明物体按深度排序。这样Early-Z的命中率极高。渲染中的统计表明,在不透明场景中利用Early-Z可减少50%以上的片元处理量,部分深度复杂的场景甚至更高。

招聘主管最喜欢的也是这种“标准岗”:需求明了,初筛靠谱,候选人来多少都能快速过滤。想让Early-Z发挥最大价值,就尽量让场景保持“不透明”——把特殊物体交给特殊流程处理。

Npass≤12Ntotal\displaystyle N_{pass} \le \frac{1}{2} N_{total}
在不透明场景的典型渲染中,可见片元不超过一半,这意味着至少一半片元可以被Early-Z拦截。
  1. 全部片元$N_{total}$ 是光栅化产生的全部片元总数,包括大量被前方不透明表面遮挡的部分。
    Ntotal=全部片元N_{total} = \text{全部片元}
  2. 可见片元$N_{pass}$ 是最终通过深度测试的可见片元数量,它只占全部片元的一部分。
    Npass=可见片元N_{pass} = \text{可见片元}
  3. 不等式含义$\frac{1}{2} N_{total}$ 是典型的分界线;不透明场景中可见片元通常不超过一半。
    NpassNtotal≤50%\frac{N_{pass}}{N_{total}} \le 50\%

透明物体处理

不是所有岗位都能用简历初筛一刀切。比如公司要招一个“既懂算法又懂业务的复合型人才”,硬性条件变得模糊;又比如你是透过公司玻璃幕墙看外面的风景——玻璃本身是透明的,后面的风景必须透过来。这时候,“谁挡了谁就淘汰”的逻辑就失效了。

透明物体在渲染中不能简单按深度淘汰。半透明片元后面的物体依然可见,需要把透明片元的颜色与后方颜色做混合。如果Early-Z把透明片元当成遮挡物剔除,画面就会错误地缺少玻璃的色泽和表面的高光。

因此,使用Early-Z时,渲染器一般对透明物体做特殊处理:关闭严格深度比较,或者将透明物体排在不透明物体之后,按从远到近的顺序做alpha混合。每个透明片元都要走到混合阶段,才能产生正确的半透明效果。

这就像玻璃幕墙前的保安:他不能一看见后面有人就告诉访客“请回吧”,而要等访客走近、看清楚身份,再放行或拦下。透明物体的片元需要“走近看”——带着透明度进行混合计算,所以Early-Z在它们面前只能谨慎行事。

Cout=Csrc⋅αsrc+Cdst⋅(1−αsrc)\displaystyle C_{out} = C_{src} \cdot \alpha_{src} + C_{dst} \cdot (1 - \alpha_{src})
透明片元的最终颜色由“自身颜色 × 不透明度 + 背景颜色 × (1 − 不透明度)”混合得到。
  1. 源颜色$C_{src}$ 是正在绘制的透明片元经着色计算后的颜色,它位于混合操作的前景层。
    Csrc⋅αsrcC_{src} \cdot \alpha_{src}
  2. 目标颜色$C_{dst}$ 是帧缓冲中已存在的背景颜色,通常是先前已经绘制的不透明物体。
    Cdst⋅(1−αsrc)C_{dst} \cdot (1 - \alpha_{src})
  3. 透明度权重$\alpha_{src}$ 是源片元的透明度,0 表示全透明,1 表示不透明。
    0≤αsrc≤10 \le \alpha_{src} \le 1
  4. 混合输出两项相加得到最终像素颜色;因为透明片元必须参与混合计算,所以不能像不透明片元那样被Early-Z提前剔除。
    Cout=Csrc⋅αsrc+Cdst⋅(1−αsrc)C_{out} = C_{src} \cdot \alpha_{src} + C_{dst} \cdot (1 - \alpha_{src})

工程实践要点

一个成熟的招聘主管会把面试流程写成SOP:初筛标准、面试轮次、背调时机,每个环节都有明确的负责人。图形学工程实践也一样,要保证Early-Z真正生效,必须守住几条纪律。

第一,不要关闭深度写入。深度写入是Z-Buffer保持准确的前提,写入关闭后名单永远空白,Early-Z的预测试自然失效。第二,不要在片元着色器中修改深度值。着色器一旦改写深度,预测试时的深度就与最终深度不一致,提前判断失真。第三,控制渲染顺序,先画不透明、再画透明,并尽量近到远。

对于性能验证,用GPU厂商提供的Profiler(如RenderDoc、NSight)对比开启和关闭Early-Z时的片元着色计数。如果着色数量没有明显下降,先检查深度状态和场景中是否有透明物体或深度修改。

说到底,Early-Z是一套需要纪律背书的优化策略:标准清晰(不透明)、名单常新(深度写入开启)、不搞特例(不改深度)。守住这三条,它就能稳定地把大量无效片元挡在着色器门外——就像一位擅长初筛的招聘主管,让公司的每场面试都花在值得的人身上。

EarlyZ有效  ⟺  深度写入开∧不透明∧¬深度修改\displaystyle \text{EarlyZ}_{有效} \iff \text{深度写入开} \land \text{不透明} \land \neg \text{深度修改}
Early-Z有效的三个必要条件:深度写入开启、几何体不透明、着色器不修改最终深度。
  1. 深度写入开保证Z-Buffer持续更新,录用名单始终反映当前最佳候选人。
    深度写入开⇒zbuf 保持最新\text{深度写入开} \Rightarrow z_{buf} \text{ 保持最新}
  2. 不透明物体只有不透明表面才能用深度比较完全判断遮挡,透明物体需要混合处理。
    不透明⇒深度比较可信\text{不透明} \Rightarrow \text{深度比较可信}
  3. 无深度修改片元着色器不修改输出深度,预测试时的深度与最终深度一致,判断才可靠。
    ¬深度修改⇒zpre=zfinal\neg \text{深度修改} \Rightarrow z_{pre} = z_{final}

AI 应用场景

大型游戏场景渲染优化

阶段:渲染管线片元处理优化

解决的问题:传统方式在植被密集、角色重叠的开放世界中,让所有片元都做完整着色,GPU压力大、帧率不稳。Early-Z先把不可见片元挡在着色器外,让GPU预算花在真正可见的像素上,就像招聘主管把面试时间留给最有希望的候选人。

具体案例:某开放世界游戏在森林场景中开启Early-Z后,片元着色请求数下降约60%,在高密度植被区域帧率提升15%以上。

AR/VR实时渲染优化

阶段:低延迟渲染优化

解决的问题:AR/VR需要在极短时间内完成两幅高分辨率画面的渲染,任何多余着色都会推高延迟。通过Early-Z提前剔除遮挡物,把节省的时间用于更高刷新率或更精细的着色。

具体案例:某AR头显在室内场景透视渲染中,利用Early-Z剔除被墙体和桌椅遮挡的片元,单帧渲染耗时降低约30%,帮助设备稳定达到90Hz刷新率目标。

AI数据可视化大屏渲染

阶段:可视化渲染性能优化

解决的问题:数据大屏用WebGL绘制成千上万重叠的散点、柱状图,普通绘制会浪费大量片元着色。借鉴Early-Z“先测深度再着色”的思路,可以剔除被上层图形完全覆盖的像素,让大屏交互保持流畅。

具体案例:某BI产品在大数据散点图中按深度值排序绘制,配合Early-Z将片元着色量减少约50%,缩放和刷选交互不再卡顿。

Python 演示

python63 行
import random  def shade_fragment(frag):    """模拟一次昂贵的片元着色:执行光照+纹理映射"""    x, y, z, r, g, b = frag    light = 1.0 / (0.5 + z * z)    return (min(255, int(r * light * 255)),            min(255, int(g * light * 255)),            min(255, int(b * light * 255)))  def late_z_rendering(fragments):    """常规管线:先着色,后深度测试"""    zbuffer = {}    framebuffer = {}    shade_count = 0    for frag in fragments:        x, y, z = frag[0], frag[1], frag[2]        shaded = shade_fragment(frag)  # 昂贵计算,无条件执行        shade_count += 1        if z < zbuffer.get((x, y), float('inf')):            zbuffer[(x, y)] = z            framebuffer[(x, y)] = shaded    return framebuffer, shade_count  def early_z_rendering(fragments):    """Early-Z管线:先深度测试,通过才着色"""    zbuffer = {}    framebuffer = {}    shade_count = 0    for frag in fragments:        x, y, z = frag[0], frag[1], frag[2]        if z >= zbuffer.get((x, y), float('inf')):            continue  # 被遮挡,跳过昂贵着色        shaded = shade_fragment(frag)  # 只有通过测试的片元才执行        shade_count += 1        zbuffer[(x, y)] = z        framebuffer[(x, y)] = shaded    return framebuffer, shade_count  def main():    random.seed(2024)    fragments = []    for _ in range(2000):        x = random.randint(0, 15)        y = random.randint(0, 15)        z = random.uniform(0.5, 10.0)        fragments.append((x, y, z, random.random(), random.random(), random.random()))     fb_late, n_late = late_z_rendering(fragments)    fb_early, n_early = early_z_rendering(fragments)     print(f"Late-Z  着色次数: {n_late}")    print(f"Early-Z 着色次数: {n_early}")    print(f"节省比例: {(n_late - n_early) / n_late * 100:.1f}%")    print(f"像素结果保持一致: {fb_late == fb_early}")  if __name__ == "__main__":    main()
目的:在一个16×16像素的小型帧缓冲上渲染2000个随机片元,对比常规管线和Early-Z管线的着色次数,并验证两种方式最终画面完全一致。
  1. z = random.uniform(0.5, 10.0)生成随机深度,模拟物体离相机不同距离,深度小者更靠近镜头。
  2. if z < zbuffer.get((x, y), float('inf')):深度测试;用无穷大作为初始深度,表示该像素还没有任何片元。
  3. if z >= zbuffer.get((x, y), float('inf')): continueEarly-Z的核心:被遮挡的片元直接跳过着色,不再执行昂贵的 shade_fragment。
  4. shaded = shade_fragment(frag)只有通过深度测试的片元才执行昂贵的光照与纹理计算,这是两种管线成本差异的关键。
  5. fb_late == fb_early校验两个渲染流程产出的帧缓冲完全相同,说明Early-Z只省开销、不改画面。

常见误区

误区“只要在引擎里勾选Early-Z,不管什么场景帧率都能翻倍。上次我开了Early-Z画面却闪烁,是不是优化太激进了?”

正解Early-Z只在“深度值可以在着色前确定”的场景高效。对透明物体和着色器改写深度的情况,它都会失效或降级。画面闪烁通常来自深度状态设置错误,而不是优化“太激进”。就像简历初筛只适用于岗位标准明确的招聘,遇到“复合型岗位”就不好使了。

为何常见:把Early-Z理解成无条件的通用性能优化,忽略了其成立的前置条件。

误区“开启Early-Z之后,场景的遮挡关系会变化吧?我之前画的物体好像变透明了。”

正解Early-Z与常规管线的渲染结果完全相同,它只是把深度测试前移,剔除对象完全由同一个深度比较逻辑决定。如果渲染结果变化,一定是深度状态设置错误,而不是优化本身导致。这相当于简历初筛没有改变录用标准,只是提前淘汰了不合格者。

为何常见:以为“优化流程”等于“改变流程”,混淆了性能优化与功能改动。

误区“都提前剔除片元了,Z缓冲还有用吗?直接删掉还能省内存。”

正解Early-Z完全依赖Z-Buffer做深度比较。若没有Z-Buffer记录当前可见深度,Early-Z就无法判断该不该剔除。Z-Buffer像“已录用名单”,名单都没有了,怎么知道该不该让下一位面试者进来?

为何常见:习惯性认为“优化”就是减少数据结构,忽略了Z-Buffer是深度判断的基准。

误区“为了做特殊效果我关闭了深度写入,反正我只是不更新深度而已,Early-Z怎么会失效?”

正解关闭深度写入后,Z-Buffer永远保持初始值(通常是远平面),所有片元都能通过深度测试,Early-Z的“初筛”变成空转,等于所有片元都去着色。这就像录用名单永远是空白,每个来面试的人都要走完全流程。

为何常见:只看到“写入”影响Z-Buffer内容,没意识到Early-Z的提前判断依赖这份名单的持续更新。

面试题

Q1. Early-Z优化主要在哪一步之前执行深度测试?

单选题 · easy

  • A.顶点着色阶段之前
  • B.光栅化操作之前
  • C.片元着色阶段之前← 正确答案
  • D.帧缓冲输出之前

答案:C。Early-Z发生在片元着色器执行之前,用Z-Buffer完成快速深度比较。顶点着色和光栅化都在它之前,帧缓冲输出在它之后。类比简历初筛:先看简历(深度测试),再安排面试(着色),而不是面完所有人才做背调。

Q2. Early-Z优化必须依赖哪种缓冲?

单选题 · easy

  • A.Z缓冲作为深度名单← 正确答案
  • B.颜色缓冲存储像素
  • C.模板缓冲做特效
  • D.顶点缓冲存几何

答案:A。Early-Z的“简历初筛”要读取已录用名单——也就是Z-Buffer。没有Z-Buffer就没有深度比较的基准。颜色缓冲存最终画面,模板缓冲做特殊掩码,顶点缓冲存几何数据,都与提前深度判断无关。

Q3. 哪种操作会导致Early-Z优化失效?

单选题 · mid

  • A.关闭深度缓冲的写入← 正确答案
  • B.先渲染不透明的物体
  • C.按由近到远的顺序画
  • D.开启深度测试功能

答案:A。关闭深度写入后,Z-Buffer永远保持初始值,所有片元都能通过深度测试,Early-Z退化为空转。先渲染不透明物体、按近到远排序、开启深度测试都有助于Early-Z生效,就像录用名单必须实时更新,初筛才有意义。

Q4. 不透明场景中Early-Z可减少多少片元处理量?

单选题 · mid

  • A.约百分之十的片元量
  • B.约百分之三十的处理
  • C.减少百分之五十以上← 正确答案
  • D.最多只能节省一成五

答案:C。工程统计表明,在不透明场景中开启Early-Z可减少50%以上的片元处理量。选项A、B、D把数值说得过低,不符合典型数据。因为不透明场景中大量片元被前方表面遮挡,Early-Z可以精准拦截它们。

Q5. 透明物体为何不能用Early-Z直接剔除?

单选题 · mid

  • A.因为透明物也需要绘制
  • B.需保留后方视线穿透← 正确答案
  • C.因为透明物体无需深度
  • D.透明物体总是离相机近

答案:B。透明物体像玻璃窗,后方的景色要透过来,画面必须保留这种“穿透”效果。Early-Z做深度比较时若直接剔除透明片元,画面就会缺少玻璃层。因此透明片元不能简单淘汰,而要走从远到近排序并混合的特殊路径。

Q6. 着色器内修改深度值会带来什么影响?

单选题 · hard

  • A.加深了深度测试的准确
  • B.让颜色缓冲的数据清零
  • C.提前的深度测试将失真← 正确答案
  • D.使顶点着色阶段加速

答案:C。片元着色器中改写深度值(如gl_FragDepth)后,最终深度与Early-Z预测试时的深度可能不一致。预测试的结论就会失真,优化效果被破坏。这也解释了为何“着色器不修改深度”是Early-Z生效的必要条件。

Q7. Early-Z能生效的必要条件有哪些?

多选题 · mid

  • A.深度测试处于开启状态← 正确答案
  • B.深度写入必须正常开启← 正确答案
  • C.着色器不修改输出深度← 正确答案
  • D.场景中只有透明物体

答案:ABC。Early-Z生效需要三个条件:开启深度测试(才有比较动作)、开启深度写入(保证Z-Buffer名单准确)、着色器不修改输出深度(保证预判可信)。场景全是透明物体时,Early-Z无法有效剔除,D不符。

Q8. 渲染透明物体时正确的做法是?

多选题 · mid

  • A.先渲染不透明几何体← 正确答案
  • B.透明物体从远到近排序← 正确答案
  • C.必要时关闭早测通道← 正确答案
  • D.透明物体和背景都绘制

答案:ABC。常规做法是先渲染不透明物体,再按从远到近排序绘制透明物体,必要时关闭Early-Z通道,因为透明片元需要参与alpha混合、不能简单剔除。D选项说法过于笼统,没有体现透明渲染的关键约束。

Q9. 片元着色阶段昂贵的主要原因是?

单选题 · easy

  • A.要执行光照纹理采样← 正确答案
  • B.要执行顶点坐标矩阵
  • C.要读取显示器的刷新
  • D.要生成位图字体数据

答案:A。片元着色器要为每个像素片元执行光照计算、纹理采样、阴影贡献等大量指令,因此是整个管线的成本大头。顶点坐标矩阵变换发生在顶点阶段,显示刷新和字体生成与GPU片元着色无关。

Q10. 关于Early-Z优化,下列说法正确的有哪些?

多选题 · hard

  • A.它不会改变最终渲染画面← 正确答案
  • B.它在像素着色前做测试← 正确答案
  • C.近到远渲染时效率更高← 正确答案
  • D.它能完全取代深度缓冲

答案:ABC。A正确,Early-Z只改变性能、不改变结果;B正确,它在像素着色之前做深度测试;C正确,场景由近到远绘制时Z-Buffer更快收敛、剔除率更高;D错误,Early-Z的本质是“先读Z-Buffer做判断”,完全离不开深度缓冲。