给定起点和终点,直线的光栅化算法要找出哪些像素应该被着色。简单起见,这里假设。
一、直观的方法
当直线的斜率时,直线在向的变化速率小于在方向上的变化速率,因此可以遍历到间的每一个,计算对应的值并将其四舍五入画点。算法伪代码如下:
k = (y2 - y1) / (x2 - x1)
y = y1
for x = x1 to x2
draw_point(x, round(y))
y += k
而当时,必须交换和的地位——遍历的取值,每次迭代计算对应的。
二、Bresenham算法
假设,每当时,对应的要绘制点的坐标要么保持不变,要么增加1或减小1(简单起见,这里假设,即只可能不变或增加1)。我们需要给出一个判断条件,判断什么时候该增加1、什么时候该保持不变。
常见的方法是使用中点进行比较(有一种所谓“中点画线法”,其原理和Bresenham算法本质上是相同的)。假设保持不变时绘制的点坐标为,那么增加1时坐标应为,容易知道连接这两个点的线段的中点为。现假设直线与的交点坐标为,那么就可以将与之比较——若,就保持不变,否则增加1。这样判断的结果是我们总是选择离精确点更近的那个像素进行着色。
由于每一轮迭代中的增量都是1,因此的增量是。我们维护一个变量,表示的值。每次迭代都减小,一旦发现小于零,就意味着应当使增加1,对应地的值也要加1。算法伪代码如下:
k = (y2 - y1) / (x2 - x1) d = 0.5 n = y1 for m = x1 to x2 draw_point(m, n) d -= k if(d < 0.0) n += 1 d += 1
更进一步地,可以通过用(x2 - x1)与之相乘的方法来消除上面的算法中与d有关的浮点操作,这样就彻底消灭了浮点运算而仅剩对整数的操作。即:
2_delta_y = 2 * (y2 - y1) 2_delta_x = 2 * (x2 - x1) d = x2 - x1 n = y1 for m = x1 to x2 draw_point(m, n) d -= 2_delta_y if(d < 0) d += 2_delta_x n += 1