我正在制作一款软件光栅化器,但遇到了一个小问题:似乎无法实现透视纠正的纹理映射。
我的算法是首先按照
然后,我们从
我理解你在问是否存在z缓冲区问题。
我的算法是首先按照
y
坐标对要绘制的坐标进行排序。这将返回一个最高点、最低点和中心点。然后我使用增量沿着扫描线行走:// ordering by y is put here
order[0] = &a_Triangle.p[v_order[0]];
order[1] = &a_Triangle.p[v_order[1]];
order[2] = &a_Triangle.p[v_order[2]];
float height1, height2, height3;
height1 = (float)((int)(order[2]->y + 1) - (int)(order[0]->y));
height2 = (float)((int)(order[1]->y + 1) - (int)(order[0]->y));
height3 = (float)((int)(order[2]->y + 1) - (int)(order[1]->y));
// x
float x_start, x_end;
float x[3];
float x_delta[3];
x_delta[0] = (order[2]->x - order[0]->x) / height1;
x_delta[1] = (order[1]->x - order[0]->x) / height2;
x_delta[2] = (order[2]->x - order[1]->x) / height3;
x[0] = order[0]->x;
x[1] = order[0]->x;
x[2] = order[1]->x;
然后,我们从
order[0]->y
到 order[2]->y
进行渲染,通过增加 x_start
和 x_end
来实现delta的变化。在渲染顶部时,delta的值是 x_delta[0]
和 x_delta[1]
。在渲染底部时,delta的值是 x_delta[0]
和 x_delta[2]
。然后,我们在线性扫描线上在x_start和x_end之间进行插值处理。UV坐标以相同的方式按y排序,并从开始和结束位置开始,每一步应用delta。
这种方法很好用,但是当我尝试进行透视校正UV映射时就会出问题。基本算法是对于每个顶点,取UV/z
和 1/z
,并在它们之间进行插值处理。对于每个像素,UV坐标变为UV_current * z_current
。 然而,结果如下所示:
倒置的部分告诉您delta何时翻转。如您所见,两个三角形都似乎指向地平线上的不同点。
以下是我用于计算空间中某点Z值的代码:
float GetZToPoint(Vec3 a_Point)
{
Vec3 projected = m_Rotation * (a_Point - m_Position);
// #define FOV_ANGLE 60.f
// static const float FOCAL_LENGTH = 1 / tanf(_RadToDeg(FOV_ANGLE) / 2);
// static const float DEPTH = HALFHEIGHT * FOCAL_LENGTH;
float zcamera = DEPTH / projected.z;
return zcamera;
}
我理解你在问是否存在z缓冲区问题。