我最近一直在用 C 语言开发 3D 软件渲染器,并且我已经成功地使一些形状和线框正常工作。
但是我现在已经开始光栅化了,但似乎无法让它工作。我目前正在尝试将 2 个立方体放入世界中,一个绿色,一个蓝色。然而,当我尝试使用扫描线光栅化进行光栅化时,与绿色和蓝色立方体相同的 Y 位置内到处都有绿色和蓝色水平线。立方体的大部分颜色都正确,但仍然有一堆线条。 我遇到的另一个问题是,如果这些水平线中的任何一条到达屏幕的顶部或底部,那么渲染器会立即崩溃。 最后,如果我移动光标,线条会稍微闪烁。这很奇怪,因为我的程序根本不接受鼠标的输入。
代码:
void FillInPolygon(struct Triangle triangle, const int WINDOWHEIGHT, Color color) {
int buf_x0[WINDOWHEIGHT],buf_x1[WINDOWHEIGHT]; //These arrays will store the X start and X end of the lines
LineDrawerForBuffer(buf_x0, buf_x1, triangle.v0.xProj, triangle.v0.yProj, triangle.v1.xProj, triangle.v1.yProj); //Line drawer will get the edges of the triangle
LineDrawerForBuffer(buf_x0, buf_x1, triangle.v1.xProj, triangle.v1.yProj, triangle.v2.xProj, triangle.v2.yProj);
LineDrawerForBuffer(buf_x0, buf_x1, triangle.v2.xProj, triangle.v2.yProj, triangle.v0.xProj, triangle.v0.yProj);
int Ay = triangle.v0.yProj; //Y position of where the first vertex of the triangle is in 2d space
int By = triangle.v1.yProj; //Y position of the second
int Cy = triangle.v2.yProj; //Y position of the third
for (int y=Min(Ay,By,Cy);y<=Max(Ay,By,Cy);y++)
DrawLine(buf_x0[y], y, buf_x1[y], y, color); //Draws a horizontal line between the X start and X end of the lines
}
LineDrawerForBuffer():
void LineDrawerForBuffer(int *buf_x0, int *buf_x1, int x1, int y1, int x2, int y2) {
//Modified version of Bresenham's Line Drawing Algorithm, this one is capable of drawing lines in all directions
int y = y1;
int x = x1;
int dx = Abs(x2-x1);
int dy = Abs(y2-y1);
int s1 = Sign(x2-x1);
int s2 = Sign(y2-y1);
bool interchange;
if (dy > dx) {
int t = dx;
dx = dy;
dy = t;
interchange = true;
}
else {
interchange = false;
}
int e = 2*dy-dx;
int a = 2*dy;
int b = 2*dy-2*dx;
if ((dy < 0 && !interchange) || (dx < 0 && interchange)) {
buf_x0[y] = x;
}
else if ((dy > 0 && !interchange) || (dx > 0 && interchange)) {
buf_x1[y] = x;
}
else if ((dy == 0 && !interchange) || (dx == 0 && interchange)) {
buf_x0[y] = x;
buf_x1[y] = x;
}
for (int i = 0; i<dx; i++) {
if (e < 0) {
if (interchange) y = y + s2;
else x = x + s1;
e = e + a;
}
else {
y = y + s2;
x = x + s1;
e = e + b;
}
if ((dy < 0 && !interchange) || (dx < 0 && interchange)) {
buf_x0[y] = x;
}
else if ((dy > 0 && !interchange) || (dx > 0 && interchange)) {
buf_x1[y] = x;
}
else if ((dy == 0 && !interchange) || (dx == 0 && interchange)) {
buf_x0[y] = x;
buf_x1[y] = x;
}
}
}
一些附加信息: 渲染器使用弱透视投影,并且 我正在使用 Raylib 打开一个窗口并在其上绘图。
我尝试过摆弄线抽屉以及位置如何存储在数组中以及数组的大小。但目前还没有解决这个问题。
编辑:我已经通过使用 calloc 分配 buf_x0 和 buf_x1 设法修复了各处闪烁的细线。然而现在它是一条大线,其高度与它来自的立方体的高度相同。蓝色立方体还有一条奇怪的细线从右侧伸出。
我也相当确定问题不在于我提供给光栅化器的多边形和顶点,因为当我使用内置的 Raylib 函数处理三角形时,它工作得很好。
我通过更改写入 buf_x0 和 buf_x1 的代码设法使光栅化器正常工作。而不是使用
if ((dy < 0 && !interchange) || (dx < 0 && interchange)) {
buf_x0[y] = x;
}
else if ((dy > 0 && !interchange) || (dx > 0 && interchange)) {
buf_x1[y] = x;
}
else if ((dy == 0 && !interchange) || (dx == 0 && interchange)) {
buf_x0[y] = x;
buf_x1[y] = x;
}
在 for 循环中及其之前。现在我在 for 循环的开头有一个 if 语句,如下所示:
if ((y >= 0) && (y < WINDOWHEIGHT))
{
if (x < buf_x0[y]) buf_x0[y] = x;
if (x > buf_x1[y]) buf_x1[y] = x;
}
这与在 FillInPolygon 函数中声明 buf_x0 和 buf_x1 后右侧的循环一起。该循环将 pos_x0 中的每个值初始化为 INT_MAX,并将 pos_x1 中的每个值初始化为 INT_MIN。我相信立方体的线条偏离一侧的原因是由于 pos_x0 被初始化为 0,以及用于写入数组的 if 语句实际上并未写入 buf_x0 (经过一些测试后发现)。意味着光栅化器将尝试从 x: 0 绘制到多边形的另一端。我写入 buf 数组的新方法还解决了以下问题:如果任何多边形的顶点位于屏幕上方或下方,我的程序就会崩溃。问题不在于 DrawLine 函数,而在于 LineDrawerForBuffer 函数。当 Y 低于 0 或高于 WINDOWHEIGHT 时,将会读取 buf 数组中不存在的索引,从而导致程序崩溃。至少我很确定是这样。