我正在制作一个软件光栅化器,我遇到了一些障碍:我似乎无法使透视校正纹理映射起作用。
我的算法是先按y
对坐标进行排序。这将返回最高,最低和中心点。然后我使用delta's遍历扫描线:
// 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是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
。但是,这就是结果:
反转部分会告诉您三角形的翻转位置。如您所见,这两个三角形似乎都朝向地平线中的不同点。
这是我用来计算空间中某点的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缓冲区问题吗?
答案 0 :(得分:4)
答案 1 :(得分:0)
我不知道我可以帮助解决您的问题,但我当时阅读的关于软件渲染的最佳书籍之一可由Michael Abrash在线Graphics Programming Black Book获取。
答案 2 :(得分:0)
如果要插入1/z
,则需要将UV/z
乘以z
,而不是1/z
。假设你有这个:
UV = UV_current * z_current
且z_current
正在插入1/z
,您应该将其更改为:
UV = UV_current / z_current
然后您可能希望将z_current
重命名为one_over_z_current
。