我基本上试图理解在光栅化过程中将浮点顶点坐标转换为定点数时GPU是如何工作的。
我读了这篇excellent article,它解释了很多东西,但它也让我感到困惑。因此,本文解释了因为我们使用32位整数和边函数,其形式如下(a - b)*(c - d) - (e - f)*(g - h)
,我们仅限于范围[-16384,16383]。我理解我们如何得到这个数字。以下是我的问题:
答案 0 :(得分:3)
- 首先,这表明顶点坐标可以是负的。然而我不明白的是,技术上在那个阶段顶点坐标在光栅空间中,并且所有三角形之前都应该被剪裁。因此,从技术上讲,x坐标的范围[0,图像宽度]和y坐标的[0,图像高度]应该只有顶点坐标?为什么坐标为负?
醇>
简短的回答是,虽然三角形已被剪裁,但它们尚未被剪切到视口(0,0 - 图像宽度,图像高度)。相反,它们被裁剪到guard-band剪裁区域,这是一个围绕视口的较大矩形。位于视口外但在保护带剪切区域内的顶点坐标可以具有负坐标。
有(至少)三种类型的三角形剪辑。第一个是“分析裁剪”,当你计算三角形边缘与保护带剪辑区域边缘的交点时,如果它们重叠,然后在这些点处切掉三角形并将其余部分细分为更小的三角形,现在每个都在剪辑区域内。第二种类型是在对着视口剪切三角形边界框时,在光栅化时找到要迭代的像素范围(注意这不会改变三角形顶点坐标)。第三种类型是文章中描述的每像素测试,您在屏幕上迭代并测试每个像素以查看它是否在三角形内。
除此之外,根据实现情况,屏幕中心可以在内部定义为(0,0)以进行剪辑计算,这意味着屏幕左侧的任何内容都将显示为负数x坐标。
- 所以作者解释说范围太有限[-16384,16383]。实际上,如果你的宽度为2048像素并使用256个子像素,那么x中点的坐标需要为4194048.这样你就会溢出。作者继续说明他们是如何在GPU上解决这个问题的,但我根本就没有得到它。如果有人也能解释它在GPU上的实际效果,那就太棒了。
醇>
注意:我不是GPU工程师,因此这只是一个高级概念性答案:
本文中给出的解释中的关键短语是增量评估。看看orient2d
等式:
int orient2d(const Point2D& a, const Point2D& b, const Point2D& c)
{
return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
}
点a
和b
是三角形顶点,而点c
是屏幕坐标。对于给定的三角形,当您迭代屏幕坐标范围时,三角形顶点将保持不变,只有点c
发生变化。增量评估意味着您只需计算上次评估等式时的变化。
假设我们一次评估等式并得到结果w0
:
w0 = (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x);
然后c.x
增加量s
(每像素一步)。 w0
的新值将是:
w0_new = (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x+s-a.x);
从第二个等式中减去第一个等式,得到:
w0_new - w0 = -(b.y-a.y)*s;
-(b.y-a.y)*s
是给定三角形的常量值,因为s
每次都是相同的量(一个像素),而a
和b
已经提到过不变的。我们可以计算一次并将其存储在变量中(称之为w0_step
)然后计算减少到:
w0_new = w0 + w0step;
您可以对w1
和w2
执行此操作,并对c.y
步骤执行类似操作。这允许更精确的原因是每像素方程不再包含定点乘法,这是导致溢出的原因。 GPU可以每个三角形进行一次高精度计算(例如64位),然后每个像素执行一次精度较低(例如32位)。