通过最小闭环工程发现第2个绘制结果[192502192023] 中的代码忽略了一个问题:直线垂直时,直线斜率就不存在,算法就无法绘制出正确的三角形。
为了解决这一问题,给出如下的优化:
// 声明直线方程的两个变量k,b。比如k_p0p2是指直线p0p2的斜率
float k_p0p2 = 0, b_p0p2 = 0, k_p0p1 = 0, b_p0p1 = 0, k_p1p2 = 0, b_p1p2 = 0;
int i;// 声明循环控制变量i
#define UNEXIST -99999
vector<vector<float>> memo1, memo2;// 将vector作为全局变量使用
int Y;// 声明直线Y
// 进阶版算法
// FIX:解决了直线斜率不存在(垂直)无法绘制的问题
// 优化点:排除三点一线的情况
// 优化点:删除全局变量j,保留i
// 优化点:将memo改成全局变量,将直线Y改成全局变量,减少gc
void scanline_185002232023(Vec2i p0, Vec2i p1, Vec2i p2, TGAImage& image, TGAColor color)
{
if(p0.y == p1.y == p2.y || p0.x == p1.x == p2.x) return;
// 更新全局变量的值
memo1 = memo2 = {};
k_p0p1 = k_p0p2 = k_p1p2 = 0;
b_p0p1 = b_p0p2 = b_p1p2 = 0;
if (p1.y > p0.y) swap(p1, p0);
if (p2.y > p0.y) swap(p2, p0);
if (p2.y > p1.y) swap(p2, p1);
// 若某线段与X轴垂直,标记为不存在
if (p0.x == p1.x) k_p0p1 = b_p0p1 = UNEXIST;
if (p0.x == p2.x) k_p0p2 = b_p0p2 = UNEXIST;
if (p1.x == p2.x) k_p1p2 = b_p1p2 = UNEXIST;
if (k_p0p1 != UNEXIST)
{
k_p0p1 = 1.0 * (p0.y - p1.y) / (p0.x - p1.x);
b_p0p1 = p0.y - k_p0p1 * p0.x;
}
if (k_p0p2 != UNEXIST)
{
k_p0p2 = 1.0 * (p0.y - p2.y) / (p0.x - p2.x);
b_p0p2 = p2.y - k_p0p2 * p2.x;
}
if (k_p1p2 != UNEXIST)
{
k_p1p2 = 1.0 * (p1.y - p2.y) / (p1.x - p2.x);
b_p1p2 = p1.y - k_p1p2 * p1.x;
}
// 当p0p1为垂直线,只需要计算y = Y与直线p0p2的交点的横坐标 Y - b_p0p2) / k_p0p2
if (k_p0p1 == UNEXIST && k_p0p2 != UNEXIST)
{
for (Y = p0.y; Y >= p1.y; --Y) {
memo1.push_back({ 1.0f * p0.x , (Y - b_p0p2) / k_p0p2 });
}
}
else if (k_p0p1 != UNEXIST && k_p0p2 == UNEXIST)
{
for (Y = p0.y; Y >= p1.y; --Y) {
memo1.push_back({ (Y - b_p0p1) / k_p0p1 , 1.0f * p0.x });
}
}
else
{
for (Y = p0.y; Y >= p1.y; --Y) {
memo1.push_back({ (Y - b_p0p1) / k_p0p1 , (Y - b_p0p2) / k_p0p2 });
}
}
// 绘制上半个三角形
i = 0;
for (Y = p0.y; Y >= p1.y; --Y) {
line_rough(memo1[i][0], Y, memo1[i][1], Y, image, color);
i++;
}
if (k_p1p2 == UNEXIST && k_p0p2 != UNEXIST)
{
for (Y = p1.y; Y >= p2.y; --Y) {
memo2.push_back({ p2.x * 1.0f , (Y - b_p0p2) / k_p0p2 });
}
}
else if (k_p1p2 != UNEXIST && k_p0p2 == UNEXIST)
{
for (Y = p1.y; Y >= p2.y; --Y) {
memo2.push_back({ (Y - b_p1p2) / k_p1p2 , p2.x * 1.0f });
}
}
else
{
for (Y = p1.y; Y >= p2.y; --Y) {
memo2.push_back({ (Y - b_p1p2) / k_p1p2 , (Y - b_p0p2) / k_p0p2 });
}
}
// 绘制下半段
i = 0;
for (Y = p1.y; Y >= p2.y; --Y) {
line_rough(memo2[i][0], Y, memo2[i][1], Y, image, color);
i++;
}
}
这是一个用于绘制三角形的扫描线算法函数**scanline_185002232023**,具体实现步骤如下:
line_rough**来绘制扫描线。绘制结果:
这次的绘制是正确的。
