我本质上是想了解在光栅化期间将 float 顶点坐标转换为定点数时 GPU 是如何工作的。
我读了 excellent article这已经解释了很多事情,但它也让我感到困惑。所以文章解释说,因为我们使用 32 位整数和如下形式的边缘函数 (a - b)*(c - d) - (e - f)*(g - h)
,我们被限制在 [-16384,16383] 范围内。我明白我们是如何得到这个数字的。以下是我的问题:
最佳答案
- First, this suggests that vertex coordinates can be negative. However what I don't understand is that technically at that stage vertex coordinates are in raster space, and all triangles should have been clipped before. Thus technically there should only be vertex coordinates in the range [0, image width] for the x-coordinate and [0, image height] for the y-coordinate? So why are coordinates negative?
简短的回答是,虽然三角形已被剪裁,但它们并未被剪裁到视口(viewport)(0,0 - 图像宽度,图像高度)。相反,它们被剪裁到 guard-band裁剪区域,它是一个围绕视口(viewport)的较大矩形。在视口(viewport)之外但在保护带裁剪区域内的顶点坐标可以具有负坐标。
有(至少)三种类型的三角形剪裁。第一个是“分析剪裁”,即当您计算三角形边缘与保护带剪裁区域边缘的交点(如果它们重叠),然后在这些点处切断三角形并将其剩余部分分割为较小的三角形,现在每个都在剪辑区域内。第二种类型是当三角形边界框被裁剪到视口(viewport)以找到在光栅化时迭代的像素范围(注意这不会改变三角形顶点坐标)。第三种类型是文章中描述的逐像素测试,您在屏幕上进行迭代并测试每个像素以查看它是否在三角形内。
最重要的是,根据实现,屏幕中心可以在内部定义为 (0,0) 以用于裁剪计算,这意味着屏幕左侧的任何东西都将具有负 x 坐标.
- So the author explains the range is too limited [-16384,16383]. Indeed if you have a 2048 pixels in width and use 256 sub-pixels then the coordinate of the point in x would need to be 4194048. Thus you would get overflow. The author keeps going and explains how they do it on the GPU to work around this problem, but I simply don't get it. If someone could also explain how it's practically done on the GPU then it would be great.
注意:我不是 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 位)。
关于3d - GPU:将浮点顶点坐标转换为定点。如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28617839/