GPU Gems 2 · Chapter 42. Conservative Rasterization
把像素覆盖从采样点问题改写成 cell 区域问题,用 conservative rasterization 为碰撞、遮挡与可见性测试提供不漏的候选。
学习目标
- 能解释为什么标准 rasterization 可能漏掉像素 cell 与三角形的几何重叠,以及 overestimated 和 underestimated 的区别
- 能修改 Conservative Rasterization Lab 的覆盖模式、三角形角度和鲁棒性参数,观察候选 cell、漏检风险与额外候选的变化
- 能回答:面对碰撞检测、遮挡剔除和可见性测试,什么时候应该接受 conservative 候选并把精确交集留给 CPU?
先别只问“采样点有没有落进去”
把屏幕想成铺满小方格的地砖,三角形是一块从上方落下的薄纸。普通检查只在每块地砖的一个固定点戳一下;纸片擦过地砖边缘,却可能刚好避开那个点。
本章解决的问题是:怎样把“纸片和方格有无重叠”变成一个不会漏掉边缘情况的 GPU 测试?如果仍只依赖固定采样点,碰撞、遮挡和阴影加速都可能把真实相交误判成不相交;单纯提高分辨率只能降低概率,不能给出保证。
1. pixel cell:把采样点换成一个小区域
↡像素周围代表该像素的矩形区域;保守覆盖判断只关心三角形是否与这个矩形相交。标准 rasterization 通常依据一个或少数 sample point 决定是否生成 fragment。可是离散网格真正代表的是一个 cell,而不是 cell 中的某个点。三角形只要碰到 cell 的一条边,就已经是几何上的相交;固定采样点没有落在三角形内部,并不能推翻这个事实。
↡按照 pixel cell 的区域覆盖来生成候选 fragment 的光栅化方法;它用可控的多报换取对相交关系的保证。本章主要讨论 overestimated 版本:只要三角形与 cell 的交集非空,就把该像素列为候选。underestimated 版本则更严格,只保留整个 cell 都在三角形内部的像素。前者适合“不能漏”的初筛,后者适合“不能多”的内含测试。
↡把 polygon 按 pixel cell 向外扩张,使所有相交 cell 都落入扩张后的区域。 ↡把 polygon 按 pixel cell 向内收缩,只保留完全位于 polygon 内的 cell。2. semidiagonal:把区域测试改成顶点偏移
↡从 pixel cell 中心指向四个角的四个向量;它们决定顶点需要向哪些方向移动,才能覆盖 cell 的边界。对凸三角形做 overestimated 覆盖,可以把 pixel cell 沿每条边扫过去;更适合 GPU 的等价做法是:把每个顶点沿四个 semidiagonal 的方向移动,再对生成点取 convex hull。这样,原本的“矩形和三角形是否相交”被改写成一个扩大 polygon 的普通点内测试。
一个顶点连接两条边。若两条边的法线落在同一象限,只需要一个偏移点;若在相邻象限,需要两个;若在对向象限,需要三个。GPU 顶点程序不能动态创建顶点,所以第一种算法按最坏情况复制每个输入顶点三次,再用退化三角形折叠掉不需要的点。
↡覆盖目标区域的凸边界 polygon;在本章的第一种算法中,它由顶点偏移后的点取 convex hull 得到。// WebGL2 风格伪代码:根据两条边法线的象限选择偏移点
float dp = dot(semidiagonal0, semidiagonal1);
vec2 diagonal;
if (dp > 0.0) {
diagonal = semidiagonal0;
} else if (dp < 0.0) {
diagonal = localIndex == 0 ? semidiagonal0 : semidiagonal1;
} else {
diagonal = localIndex == 1
? betweenQuadrants(semidiagonal0, semidiagonal1)
: semidiagonal0;
}
clipPosition.xy += halfPixel * diagonal * clipPosition.w;代码在 clip space 中运行,而不是直接改 window space:顶点程序发生在裁剪和透视除法之前。只要近裁剪面没有把边切进视锥,window-space 的几何直觉就能通过齐次坐标中的平面表达保留下来。
3. 两种 GPU 算法:少顶点还是少 overdraw
第一种算法构造最优 bounding polygon,填充率好,但每个输入顶点都要复制,几何处理和数据设置成本高。第二种算法只在顶点程序中生成一个 bounding triangle,再把它与最优 polygon 的轴对齐包围盒结合,在 fragment 程序中丢弃落在 AABB 外的片元。
第二种算法的优点是顶点工作少,缺点是锐角三角形会被一个很宽的 triangle 包住,产生大量 overdraw。Chapter 42 的取舍不是“永远选最优 polygon”:高端 GPU 可能更能承受顶点复制,而较老硬件可能更容易受 vertex limit 约束;三角形形状和目标分辨率也会改变答案。
4. robustness 与 conservative depth:把错误控制在边界内
两种算法都会遇到数值和几何退化。最优 polygon 在 tessellation 后可能改变朝向;bounding triangle 的平面交点在 near-degenerate triangle 上会受到浮点精度影响。可以设置一个小的 ε:当三角形到视点的有符号距离小于 ε 时,退回标准 rasterization 和剔除路径,避免用不稳定的交点继续扩张。
↡为每个 pixel cell 选择足够安全的最大或最小深度边界;zmax 不小于精确深度,zmin 不大于精确深度。碰撞和遮挡测试还需要深度上的保守性。overestimating rasterizer 可以写入 zmin 或 zmax,再配合 depth test 和 occlusion query 得到候选关系;它不负责最终精确交点,只保证不会因为一个过于乐观的深度而漏掉可能遮挡或碰撞的对象。
先猜一猜:在下面的实验中,把三角形角度调得更尖,哪种算法更容易生成额外候选?打开 near-degenerate 开关后,为什么应该用 ε 回退,而不是继续相信精确的 plane intersection?
三步验收:从 cell 定义到安全候选
第一步:明确 pixel cell 与覆盖方向
先区分 sample point 和 pixel cell,再决定目标是 overestimated 的“不漏”还是 underestimated 的“不多”。把 dilation/erosion 当成两种区域定义,而不是两个采样质量档位。
本章小结
- pixel cell 区域测试比固定 sample point 更能表达真实覆盖。
- overestimated 保证相交候选不漏,underestimated 保证 cell 完全在内。
- semidiagonal 偏移与 convex hull 把区域膨胀变成顶点程序。
- 最优 polygon 与 bounding triangle 分别交换 geometry 与 fill rate。
- conservative depth 和 ε 回退把数值风险变成可控候选。
练习
问题 1|选择覆盖定义。 碰撞检测、阴影可见性初筛和“完全位于多边形内”的选区判断,分别更适合 overestimated 还是 underestimated?说明后续是否还需要精确测试。
问题 2|修改 Demo 代码。 为 Conservative Rasterization Lab 增加 algorithm 开关:optimal-polygon 使用低 overdraw 估算,bounding-triangle 使用更高 fill rate 估算;当角度小于阈值时,显示为什么第二种路径要提高候选数量。
问题 3|部署选型。 目标 GPU 顶点吞吐强、fragment 填充压力大,或者相反时,如何在两种算法之间做选择?为什么不能把“九个顶点最坏情况”直接视为第一种算法的固定成本?
名词解释
本章出现的专业名词,用大白话再讲一遍。
- pixel cell
- conservative rasterization
- overestimated
- underestimated
- semidiagonal
- bounding polygon
- conservative depth