我必须编写自己的软件3d栅格化器,到目前为止,我已经能够将由三角形构成的3d模型投影到2d空间中:
我旋转,平移和投影点,以获得每个三角形的二维空间表示。然后,我取了3个三角形点,并实施了扫描线算法(使用线性插值法)以找到沿三角形边缘(左右)的所有点[x] [y],以便可以水平扫描三角形,一行一行地填充像素
这可行。除了我还必须实现z缓冲。这意味着,知道三角形的3个顶点的旋转平移后的z坐标后,我必须对使用扫描线算法找到的所有其他点的z坐标进行插值。
这个概念似乎很清楚,我首先通过以下计算得出Za和Zb:
var Z_Slope = (bottom_point_z - top_point_z) / (bottom_point_y - top_point_y);
var Za = top_point_z + ((current_point_y - top_point_y) * Z_Slope);
然后,对于每个Zp,我都会在水平方向执行相同的插值:
var Z_Slope = (right_z - left_z) / (right_x - left_x);
var Zp = left_z + ((current_point_x - left_x) * Z_Slope);
并且如果当前z在该索引处比前一个z更接近查看器,则将颜色写入颜色缓冲区,并将新z写入z缓冲区。(我的坐标系是x:左->右; y:上->下; z:脸部->电脑屏幕;)
问题是,它陷入了困境。该项目在这里,如果您选择“ Z缓冲”单选按钮,您将看到结果...(请注意,我在“ Z缓冲”模式下使用了画家的算法(仅绘制线框)用于调试)
PS:我在这里读到,z = 1/z
在进行插值之前,必须将z转换为它们的倒数(即)。我尝试过,看来没有变化。我想念什么?(任何人都可以澄清,确切地说,您必须将z变成1 / z的位置,以及将z变成1 / z的位置。)
[编辑]以下是有关我获得的最大和最小z值的一些数据:
max z: 1; min z: -1; //<-- obvious, original z of the vertices of the triangles
max z: 7.197753398761272; min z: 3.791703256899924; //<-- z of the points that were drawn to screen (you know, after rotation, translation), by the scanline with zbuffer, gotten with interpolation but not 1/z.
max z: 0.2649908532179404; min z: 0.13849507306889008;//<-- same as above except I interpolated 1/z instead of z.
//yes, I am aware that changing z to 1/z means flipping the comparison in the zBuffer check. otherwise nothing gets drawn.
在进行艰苦的调试之前,有人可以确认我到目前为止的概念是正确的吗?
[EDIT2]
我已经解决了z缓冲问题。事实证明,绘制顺序根本没有搞乱。z坐标正在正确计算。
问题是,为了提高帧速率,我每4个像素绘制4px / 4px的框,而不是屏幕上的实际像素。所以我每像素绘制16px,但是只检查了其中一个的z缓冲区。我真是个傻瓜。
TL / DR:问题仍然存在:如何/为什么/何时使用Z的倒数(如1 / z)代替Z?因为现在,一切都可以进行。(没有明显差异)。