【问题标题】:What is the interval when rasterizing primitives光栅化图元时的间隔是多少
【发布时间】:2013-05-15 13:42:44
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 你想做什么?

标签: opengl graphics rasterizing


【解决方案1】:

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

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

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

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

但是在考虑纹理时,会出现另一个问题,即插值。虽然从 (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 的坐标或 0.255 的 texCoords,但这仍然不是问题,因为我们离“捕捉”到相邻像素或纹素的点很远(假设我们使用最近的过滤,但即使使用线性过滤,您通常不会注意到与确切纹理颜色的差异)。

虽然对于 line 示例很难说,由于精度、舍入和实现问题,它是从 (0,0)(0,9) 还是从 (-1,0)(-1,9) (因此被剪掉了) , 甚至倾斜,你应该使用(0.5,0.5)(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)。这应该为您提供图元的像素和纹素精确光栅化以及问题中描述的半开间隔。但请始终记住,在这种情况下,光栅化多边形的角像素与其顶点角不匹配(向内移动了半个像素)。对于纹理,这与过滤规则很好地发挥了作用,但对于其他属性,如颜色,这意味着矩形的左下角像素不会完全具有(什么是 "exactly" 在这个有限的 -无论如何精度上下文?)左下顶点的颜色。但是,对于线条,它们确实会匹配(尽可能)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-22
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多