day2:画一条线
第一天我们搭建了 C++
的运行环境并画了一个点,根据 点 → 线 → 面
的顺序,今天我们讲讲如何画一条直线。
本文主要讲解直线绘制算法的推导和思路(莫担心,只涉及到一点点的中学数学知识),最后会给出代码实现,大家放心的看下去就好。
1.DDA 直线算法
1.1 简单实现
我们先来回顾一下中学的几何知识,如何在二维平面内表示一条直线?最常见的就是斜截式了:
其中斜率是 ,直线在 轴上的截距是 。
斜截式在数学上是没啥问题的,但是在实际的工程项目中,因为硬件资源是有限的,我们不可能也没必要表示一条无限长度的直线,现实往往是已知一条线段的起点 和终点 ),然后把它画出来。
这时候用两点式表示一根直线是最方便的:
把上面的式子稍作变形,可以把 和 用参数 表示:
这时候我们只要取不同的 ,就可以得出对应的 x 和 y。
按照以上的思路,我们可以用代码实现一下。C++
的实现也很简单,如下所示(dl 表示 ):
void line(
int x1, int y1,
int x2, int y2,
TGAImage &image, TGAColor color) {
const float dl = 0.01;
int dx = x2 - x1;
int dy = y2 - y1;
for (float t=0.0; t<1.0; t+=dl) {
int x = x1 + dx * t;
int y = y1 + dy * t;
image.set(x, y, color);
}
}
这个是直线算法的初步实现,只能说「能用」,地位和排序算法里的「冒泡排序」一样,目的达到了,但是性能不太好:
-
每画一个点,都要运行两次乘法
-
大量使用浮点运算(众所周知,)
-
如果
dl
取的比较小,会导致一个像素点会被绘制多次,重复计算 -
如果
dl
取的比较大,会导致直线断掉
1.2 优化
下面我们就一步一步优化上面的算法。
首先我们注意到,对于屏幕绘制直线这个场景,理论上是连续的,但实际是离散的。
比如说 从