boxmoe_header_banner_img

菜就多练喵

文章导读

[C++][图形学]TinyRenderer第一课——画线与线框渲染


avatar
Ib_Mccf 2026年2月27日 13

Bresenham画线算法

void line(int ax, int ay, int bx, int by, TGAImage &framebuffer, TGAColor color)
{
    // 更陡峭时使用y遍历
    bool steep = std::abs(ay - by) > std::abs(ax - bx);
    if (steep)
    {
        // 交换x轴和y轴
        std::swap(ax, ay);
        std::swap(bx, by);
    }
    // 保证 bx >= ax, 遍历从 ax 到 bx
    if (ax > bx)
    {
        std::swap(ax, bx);
        std::swap(ay, by);
    }
    int y = ay;
    int ierror = 0.; 
    //通过x去遍历,保证足够的采样点,使线段连续
    for (int x = ax; x <= bx; x++)
    {
        if (steep)
            framebuffer.set(y, x, color);
        else
            framebuffer.set(x, y, color);
        //将float计算优化为int计算,提升性能
        ierror += 2 * std::abs(by - ay);
        y += (by > ay ? 1 : -1) * (ierror >= bx - ax);
        ierror -= 2 * (bx - ax) * (ierror >= bx - ax);
    }
}

作者的思路是以线段的参数方程入手,如有两个点(ax,ay)和(bx,by),那么该线段上任意一点P = Pa + t * (Pb – Pa),其中t的值为0到1。

现在我们使x从ax到bx逐一像素遍历(需保证ax <=bx),带入上述方程可得x = ax + t * (bx – ax),变换一下得到t = (x – ax) / (bx – ax),以此可以得到当前x对应的y坐标,y = ay + (x – ax) / (bx – ax) * (by – ay)。

但是这种直接计算的方法需要用到浮点数计算,有一定的性能消耗,且浮点数的取整可能会导致线段不连续。

因此通过int运算代替float预算,用int型变量ierror去累计误差值,优化算法的性能并避免线段的离散。



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字

插入代码