1

通常在计算机科学的时候我有东西从ab间隔是[a, b)。栅格化几何图元时是否如此?

例如,当我有一条从位置开始并在位置(0, 0)结束的线时,当使用平行投影和 1 个 GPU 单元映射到屏幕上的 1 个像素时,(0, 10)该线是否包含点?(0, 10)

编辑:相同条件下的相同问题,但对于纹理:

如果我将纹理映射到从使用到映射2x2的四边形上,它将是“像素完美”,屏幕上一个像素上的纹理一个像素,还是将纹理缩放?如果间隔是四边形将是 3x3 并且必须缩放纹理......(0, 0)(2, 2)(0, 0)(1, 1)[0, 2]

稍后编辑:这可能会有所帮助:http: //msdn.microsoft.com/en-us/library/windows/desktop/bb219690%28v=vs.85%29.aspx

4

1 回答 1

5

首先,这完全取决于所使用的特定光栅化框架(例如 OpenGL、Direct3D、GDI、...),所以我将根据被标记的问题来回答这个问题opengl

这不是一个简单的问题,因为通常绘制的图元(或更确切地说是其片段)的实际窗口坐标不是整数,而是浮点或定点坐标,这是在一堆(可能不精确)变换之后产生的(不是全部可以使用着色器自定义标识,尤其是从标准化设备坐标到窗口坐标的固定功能视口转换)。因此,即使您将转换管道配置为直接在窗口空间中指定顶点坐标,也不要期望生成的片段的窗口坐标在所有情况下都是完美的整数。如果需要,请查看此问题及其答案,以了解更多有关 OpenGL 转换管道的信息。

然后它取决于原始类型。对于多边形(三角形/四边形),如果片段的中心位于多边形顶点的窗口坐标所定义的多边形边界内,则光栅器会检查每个片段。(0,0)因此,如果我们有一个从窗口坐标到的矩形(嗯,两个三角形,但我们只是把它当作矩形),(2,2)它将覆盖一个 2x2 区域,因为只有片段(0,0)(具有中心坐标(0.5,0.5))和(1,1)(具有中心坐标(1.5,1.5)),并且它们的组合位于矩形内。

对于线来说,它有点复杂,使用所谓的“钻石退出规则”。我不会在这里详细讨论这一点,但对于水平或垂直线,这本质上意味着最后一个像素也是排他的。但实际上这也意味着整数窗口坐标最不适合用于线条,因为由于转换管道中的舍入问题,很难决定这样的片段属于哪个像素,因为线条的“判定阈值”为整数片段边界,而不是多边形的中心。

但是在考虑纹理时,会出现另一个问题,即插值。虽然从(0,0)到的四边形(2,2)将覆盖 2x2 像素区域,但变量的值(在图元中插值的顶点属性,如颜色或纹理坐标)是从实际的窗口坐标插值的。因此,像素(0,0)(对应于中心坐标为 的片段(0.5,0.5))不会具有左下四边形顶点的精确值,而是以片段大小的一半插入内部的值(对于其他角也是如此)。

那么同样重要的是 OpenGL 如何过滤纹理。使用线性过滤时,为纹理中心(即(i+0.5)/size)处的纹理坐标和纹理大小的整数除数(即i/size) 将导致相邻纹素颜色之间的中途混合。而当使用最近邻采样代替时(在尝试做像素或纹素精确的事情时建议这样做),浮点纹理坐标被四舍五入(地板操作),因此决定颜色是否为的“决策阈值”来自一个纹素或其邻居的纹素位于纹素边界(因此纹理大小的整数除数作为纹理坐标)。因此,建议在纹素中心进行采样,同时使用线性过滤(这在工作像素精确时又不建议使用)和最近过滤,因为这减少了由于不精确和舍入误差而从一个纹素“翻转”到另一个纹素的机会纹理坐标插值。


因此,让我们看一下您的特定示例。我们有一个带坐标的四边形

(0,2) - (2,2)
  |       |
(0,0) - (2,0)

和纹理坐标

(0,1) - (1,1)
  |       |
(0,0) - (1,0)

因此,如果这些位置已经在窗口/视口空间中给出,则会导致具有中心的片段

(0.5,1.5) (1.5,1.5)
(0.5,0.5) (1.5,0.5)

覆盖,表示 2x2-[0,1]-像素正方形。插值后这些片段的纹理坐标将是

(0.25,0.75) (0.75,0.75)
(0.25,0.25) (0.75,0.25)

对于 2x2 纹理,它们确实位于纹素中心。所以一切都很好。可能存在舍入和精度错误,导致例如1.999或 texCoords 的坐标0.255,但这仍然不是问题,因为我们远离我们将“捕捉”到相邻像素或纹素的点(假设我们使用最近的过滤,但即使使用线性过滤,您通常也不会注意到与确切纹理颜色的差异)。

虽然对于 line 示例很难说,由于精度、舍入和实现问题,它是否会从(0,0)to(0,9)或 from (-1,0)to (-1,9)(因此被剪掉),或者甚至是倾斜的,你应该使用(0.5,0.5)and (0.5,10.5),这肯定会导致从(0,0)到的一行(0,9)


综上所述,OpenGL 并不是真正为完全像素精确操作而设计的,但只要小心,它就可以实现。但是为了达到最佳效果,您应该首先配置您的转换以直接在窗口坐标中指定顶点位置,例如

glViewport(0, 0, width, height);
glOrtho(0, width, 0, height, -1, 1); //or something similar when using shaders

然后对于多边形,使用纹理大小的整数位置和整数除数作为纹理坐标(并使用GL_NEAREST过滤)。但是对于线条,使用半像素位置(即i+0.5)和纹素中心作为纹理坐标(即(i+0.5)/size)。这应该为您提供图元的像素和纹素精确光栅化以及问题中描述的半开间隔。但请始终记住,在这种情况下,光栅化多边形的角像素与其顶点角不匹配(向内移动了半个像素)。对于纹理,这与过滤规则很好地配合,但对于其他属性,如颜色,这意味着矩形的左下角像素不会完全(什么是“完全”无论如何在这个有限精度的上下文中?)左下顶点的颜色。但是,对于线条,它们确实会匹配(尽可能)。

于 2013-05-15T15:03:21.477 回答