GPU绘制的三角形宽度为何为15像素而非预期的16像素?
GPU光栅化中三角形像素数量差异的原因解析
核心原因:光栅化的像素覆盖规则与边方程约束
你遇到的问题本质是GPU光栅化时的像素采样逻辑和三角形边方程的实际覆盖范围共同作用的结果,而非简单的线性坐标映射。
1. 坐标转换与像素的离散特性
160×160的颜色附件中,NDC空间([-1,1])到屏幕像素的映射关系为:屏幕浮点坐标 = (NDC坐标 + 1) × 80
每个像素占据的浮点坐标区间为[i, i+1)(i为0~159的像素索引),GPU默认以像素中心(即i+0.5)作为采样点判断是否被三角形覆盖。
你的三角形顶点NDC坐标为(-1.0,1.0)、(-0.9,0.9)、(-0.8,1.0),转换为屏幕浮点坐标后:
- 顶点A:(0.0, 160.0)
- 顶点B:(8.0, 152.0)
- 顶点C:(16.0, 160.0)
2. 三角形边方程的实际覆盖范围
该三角形的三条边方程(NDC空间)为:
- AB边:
x + y = 0,内部区域满足x + y ≤ 0 - BC边:
x - y = -1.8,内部区域满足x - y ≥ -1.8 - AC边:
y = 1.0,内部区域满足y ≤ 1.0
在接近顶部的扫描线(如NDC y=0.99,对应屏幕浮点y=159.2),代入边方程可得x的有效范围是-0.99 ≤ x ≤ -0.81,转换为屏幕浮点x是0.8 ≤ x ≤ 15.2。此时:
- 屏幕x=0.8属于像素0的区间,但像素0的中心是0.5,对应NDC x=-0.99375,满足
x + y ≤0,会被覆盖; - 屏幕x=15.2属于像素15的区间,但像素15的中心是15.5,对应NDC x=-0.80625,代入
x + y = -0.80625 + 0.99 = 0.18375 >0,不满足内部条件,不会被覆盖。
因此该扫描线实际覆盖的像素为x0到x14,共15个像素——这就是你看到的结果。
3. GPU光栅化的关键规则:左上规则
为避免相邻三角形重复绘制边缘像素,GPU遵循左上规则:
- 当三角形的边与像素边缘重合时,仅当边是三角形的上边(三角形在边下方)或左边(三角形在边右侧)时,该像素才会被计入。
你的三角形AC边是顶部的水平边,但该边仅包含两个顶点,无内部像素;而接近顶部的有效扫描线中,右边缘的采样点(像素15的中心)不满足边方程的内部约束,因此不会被覆盖。
参考算法与公式
- 屏幕坐标转换公式:
screen_fx = (ndc_x + 1) × (width/2)screen_fy = (ndc_y + 1) × (height/2)(若API采用y向下为正,则公式为screen_fy = (1 - ndc_y) × (height/2)) - 边方程判断:对于三角形顶点A(x1,y1)、B(x2,y2),边AB的方程为
(y2-y1)(x-x1) - (x2-x1)(y-y1) = 0,内部区域通过代入测试点判断符号确定。 - 像素覆盖规则:GPU光栅化核心遵循扫描线算法与左上规则,通过判断像素中心是否在三角形内部(满足所有边方程约束)来决定是否绘制。
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

