据我了解,在OpenGL中,多边形通常被剪裁在剪辑空间中,并且只有那些三角形(或三角形的一部分,如果剪切过程将它们分开)在与+ - w的比较中存活下来。然后,这需要实现多边形裁剪算法,例如Sutherland-Hodgman。
我正在实现自己的CPU光栅化器,现在我想避免这样做。我有可用的顶点的NDC坐标(不是真的标准化,因为我没有剪辑任何东西所以位置可能不在范围[-1,1]中)。我想为所有像素插值这些值,并且只绘制NDC坐标在x,y和z维度中落在[-1,1]内的像素。然后我会另外进行深度测试。
这会有用吗?如果是的话插值是什么样的?我可以使用OpenGl spec描述的here(第427页14.9)公式进行属性插值吗?或者,我应该使用公式14.10,它用于所有3个坐标的深度(z)插值(我真的不明白为什么在那里使用不同的坐标)?
更新 我尝试用两种方法插入每个像素的NDC值:
w0, w1, w2
是顶点的重心权重。
1)float x_ndc = w0 * v0_NDC.x + w1 * v1_NDC.x + w2 * v2_NDC.x;
float y_ndc = w0 * v0_NDC.y + w1 * v1_NDC.y + w2 * v2_NDC.y;
float z_ndc = w0 * v0_NDC.z + w1 * v1_NDC.z + w2 * v2_NDC.z;
2)
float x_ndc = (w0*v0_NDC.x/v0_NDC.w + w1*v1_NDC.x/v1_NDC.w + w2*v2_NDC.x/v2_NDC.w) /
(w0/v0_NDC.w + w1/v1_NDC.w + w2/v2_NDC.w);
float y_ndc = (w0*v0_NDC.y/v0_NDC.w + w1*v1_NDC.y/v1_NDC.w + w2*v2_NDC.y/v2_NDC.w) /
(w0/v0_NDC.w + w1/w1_NDC.w + w2/v2_NDC.w);
float z_ndc = w0 * v0_NDC.z + w1 * v1_NDC.z + w2 * v2_NDC.z;
剪辑+深度测试总是如下所示:
if (-1.0f < z_ndc && z_ndc < 1.0f && z_ndc < currentDepth &&
1.0f < y_ndc && y_ndc < 1.0f &&
-1.0f < x_ndc && x_ndc < 1.0f)
情况1)对应于使用等式14.10进行插值。情况2)对应于使用等式14.9进行插值。
结果documented in gifs on imgur. 1)当第二个立方体在相机后面或进入立方体时发生奇怪的事情。 2)奇怪的瑕疵是不可见的,但随着相机接近顶点,它们开始消失。并且因为这是perspective correct interpolation of attributes顶点(靠近相机?)具有更大的权重,所以一旦顶点被剪切,该信息就被强调地插入三角形像素。
所有这些都是预期的还是我做错了什么?
答案 0 :(得分:2)
我认为没有任何理由说这不起作用。但它会比传统剪辑慢一些。请注意,您可能会遇到靠近投影中心的三角形的问题,因为它们会非常小并且可能会导致重心坐标计算出现问题。
等式14.9和14.10之间的差异在于,深度基本上是z / w(并重新映射到[0,1])。由于透视分割已经发生,因此在插值期间必须将其分开。
答案 1 :(得分:2)
除非三角形在相机空间Z中达到或超过0,否则不必严格剪切近平面。一旦发生这种情况,均匀坐标数学就会变得奇怪。
如果大多数硬件在剪辑空间外延伸超过屏幕宽度,或者如果它们越过摄像机-Z为零,则大多数硬件只会限制三角形。这种剪辑被称为“保护带剪辑”,它节省了很多性能,因为剪辑不便宜。
所以是的,数学可以正常工作。在设置扫描线时,您必须做的主要事情是确定每个扫描线在屏幕上的开始/结束位置。插值数学是相同的。