如何在半整数像素中心光栅化OpenGL三角形
OpenGL像素/片段在概念上是以半整数像素为中心的1x1正方形。OpenGL 4.5规范规定: 片段位于其左下角,位于整数上 网格坐标。光栅化操作也指片段的 中心,从其左下角(和)偏移(1/2,1/2 所以位于半整数坐标上) 光栅化器通常假定像素中心位于整数网格上。由于我正在尝试实现一个正确的OpenGL三角形填充,我想知道下面的过程是否合理 让我们以一个简单的三角形为例,其剪辑坐标为(-1,-1),(+1,-1),(0,+1),如下图左侧所示(假设正交投影且z=0)。假设我们有一个(小5x5帧缓冲区),我们通过如何在半整数像素中心光栅化OpenGL三角形,opengl,pixel,rasterizing,rasterize,Opengl,Pixel,Rasterizing,Rasterize,OpenGL像素/片段在概念上是以半整数像素为中心的1x1正方形。OpenGL 4.5规范规定: 片段位于其左下角,位于整数上 网格坐标。光栅化操作也指片段的 中心,从其左下角(和)偏移(1/2,1/2 所以位于半整数坐标上) 光栅化器通常假定像素中心位于整数网格上。由于我正在尝试实现一个正确的OpenGL三角形填充,我想知道下面的过程是否合理 让我们以一个简单的三角形为例,其剪辑坐标为(-1,-1),(+1,-1),(0,+1),如下图左侧所示(假设正交投影且z=0)。假设我们有一个(小5x5
glViewport(0,0,5,5)
将三角形映射到该缓冲区,如右图所示,在设备坐标中生成三角形,顶点为(0,0)、(5,0)、(2.5,5)
正如您所看到的,中心位于三角形内的13个片段(图像中的着色像素)应由光栅化器生成。请注意,碎片中心位于半整数坐标上。要实现OpenGL规范,这就是结果所需要的
扫描线多边形填充将确定扫描线与三角形相交的x跨度,但扫描线的y值为半整数,如下图所示:
硬件/固件光栅化器将假定像素中心位于整数网格上,因为这是执行填充的最有效方式。在下图中,我将三角形的设备坐标移动了(-0.5,-0.5),以将中心放置在整数网格上:
请注意,像素中心现在确实位于整数网格上。该光栅化器只需将(0.5,0.5)添加回每个片段中心,然后再传递给片段着色器。至少这是我的计划
处理纹理坐标似乎是直截了当的。想象我指定的纹理坐标(0,0)、(1,0)、(0.5,1),如下所示。左边的图像使用半整数像素中心(OpenGL方式),右边的图像使用整数像素中心(硬件方式)。纹理坐标(该问题的任何附加片段属性)最终都具有相同的值——即,无需执行任何特殊操作
那么我的方法似乎正确吗
- 将(-0.5,-0.5)添加到每个碎片坐标
- 使用硬件高效填充
- 生成碎片中心时,将(0.5,0.5)添加回,然后
- 不要担心其他片段属性(它们只是起作用)
ceil(y)
找到分数y值后面的下一个扫描行,这可以在浮点或定点中轻松完成,如truncate(y+0.9999)
——在具有16位分数的定点中,这只是(y+0x0FFFF)>>16
。对于半整数扫描行,您可以减去0.5,执行ceil运算,然后再加上1/2。先做一次减法似乎比较容易。我看你已经完全理解了数学。但你仍然有心理障碍。您仍然认为1整数增量==1像素。你必须认为整数双像素=1像素。使用固定点坐标,始终移动1位。CPU不太关心写i+=1还是i+=2。是的,这些机器通常有一条递增指令,但通常只是解码为add1的微码。当涉及到OpenGL时,目标是GPU实现,所以根本不涉及任何软件。是的,有OpenGL光栅化器的软件实现,但这些通常是回退。对于专用硬件来说,没有更简单或更难的算术运算。@datenwolf是的,无论是哪种方式,添加都是微不足道的。对于整数像素中心,我可以在spanx
asceil(x)
(例如,在扫描线上y=4
,span[1.75,2.75]
的第一个整数是ceil(1.75)=2
。如果我使用半整数像素,那么我会将前半整数>=x作为ceil(x+0.5)-0.5
(例如,在扫描线上y=4.5
span[2.25,2.75]
上的前半个整数是ceil(2.25+0.5)-0.5=2.5
)。定点((x+0x17FFF)>>16)