05-primitive-assembly-clipping-viewport
第 5 篇:图元装配、裁剪、投影与视口变换
原文:Part 5
一句话定位
顶点着色完成后,硬件先把顶点组成完整图元,再用齐次裁剪、剔除、透视除法和视口变换,把图元变成适合屏幕空间光栅化的形式。
数据路径
VS 输出
→ 按拓扑装配点/线/三角形
→ 面朝向与用户/视锥剔除
→ 必要时做齐次裁剪并生成新顶点
→ 透视除法 (x,y,z)/w
→ 视口与深度范围变换
→ 屏幕空间图元
实际次序可因优化而调整,但任何调整都必须保持 API 可观察结果。
图元装配
PA 根据 primitive topology 和索引关系读取完整图元。点需要一个顶点、线两个、三角形三个,strip/fan 还要处理复用和绕序。这里体现了为什么 VS 结果要保留足够的标签或顺序信息:着色可乱序完成,图元关系不能丢。
剔除与裁剪不是一回事
- 剔除(cull):整个图元无需继续处理,例如背面剔除或完全落在同一裁剪平面外。
- 裁剪(clip):图元与边界相交,需要计算交点并生成一个或多个新图元。
- 视口/裁剪矩形测试可以提前拒绝明显不可能贡献像素的图元,但不能改变规范要求的覆盖结果。
裁剪比拒绝昂贵,因为它会产生新顶点并插值属性。Guard band 的思路是扩大硬件可安全表示的屏幕区域:大多数越出视口但仍在 guard band 内的图元不必真正裁剪,留给后续视口/剪裁测试拒绝即可;只有超出安全数值范围且仍可能影响视口的图元才进入裁剪器。
齐次空间为什么重要
在透视除法前,裁剪条件可写成关于 x, y, z, w 的线性不等式。先在齐次空间裁剪,再除以 w,能正确处理穿过近裁剪面的图元。若先除法,w 接近零或符号变化会带来巨大坐标和错误拓扑。
裁剪器最难的不是公式本身,而是一致性:共享边必须按完全兼容的规则产生相同交点,否则相邻三角形可能出现裂缝。有限精度、平面顺序、交点方向和舍入选择都可能影响水密性。
透视除法与视口变换
顶点从 clip space 经过 (x/w, y/w, z/w) 到 NDC,再按 viewport 的缩放与偏移映射到屏幕坐标和深度范围。这里的 w 还会在后续透视正确插值中出现,因此不要把它只看作“做一次除法后就丢弃的分量”。
术语对照
| 英文 | 中文 | 区分 |
|---|---|---|
| primitive assembly | 图元装配 | 按拓扑组合顶点 |
| culling | 剔除 | 整体丢弃,不生成新图元 |
| clipping | 裁剪 | 与边界求交,可能生成新顶点 |
| guard band | 保护带 | 减少真正裁剪次数的扩大区域 |
| clip space | 裁剪空间/齐次裁剪空间 | 透视除法之前 |
| NDC | 规范化设备坐标 | 透视除法之后 |
| viewport transform | 视口变换 | NDC 到屏幕/深度范围 |
面向 UMD/KMD 的阅读提示
- UMD 需要把 front-face、cull mode、clip depth convention、viewport 和 scissor 编进状态。
- 查找硬件不原生支持某种裁剪语义时,驱动是否插入 shader lowering 或额外 pass。
- 关注 Vulkan/OpenGL/D3D 在 NDC 的 Y 方向、深度范围和坐标约定上的差异由哪层消解。
- KMD 基本不理解几何语义;若在 KMD 中寻找裁剪算法,通常找错层了。
自测
- 为什么“完全在视口外”通常可直接拒绝,而“跨过近裁剪面”不能只依赖 scissor?
- 为什么相邻三角形分别裁剪时必须保证公共边生成同一个交点?
- API 坐标约定与硬件原生约定不同时,可由矩阵、viewport 状态或 shader 修正;各方案会影响哪些状态?
本篇总结
这一段流水线的任务是把“合法的齐次几何”稳健地变成“数值范围可控、拓扑一致、可做屏幕覆盖测试的图元”。

浙公网安备 33010602011771号