前期准备:搭建可以在屏幕上画一个像素的开发环境,我使用OpenGL的glfw库来画点。
为了提高画线算法的可读性,我先把自己使用的画点函数写出来
//点 绘制
/*
point2D是一个包含x,y坐标位置的对象 R,G,B - color pointSize是像素点的大小
*/
void drawPoint(point2D point,float R,float G,float B,float pointSize);
常用的直线生成算法有:DDA算法、中值算法、bresenham算法等等
一、为什么要“光栅化”?
在写算法之前,我们先聊一下什么叫光栅化直线。比如我在屏幕上以x、y同时递增0.01的速度,希望画出一条直线
for(float i=0;i<1;i+=0.01)
{
drawPoint(i,i,1.0, 0.0, 0.0);
}
效果:
但是我们发现这条直线并不“直”,这是因为在计算机的屏幕上,是以类似网格形式的像素点存在的。当我们一以位置(0,0)、(0.01,0.01)(0.02,0.02)(0.03,0.03)...画点时,它不一定会恰好落在我们合适的像素点中,因此直线会产生扭曲。
我们的算法来判断哪个像素点被点亮以接近我们真正的任务,这个过程被称为光栅化。
例如,如我们用DDA画线算法来画这条线,依然以每次0.01的速度递增,图像如下:
我们会发现这条“直线”更“直”,如果我们将像素点调小并将增长速度减小,那么画直线的精度会更大,图像也更接近直线。
这就是软光栅化直线的一个示例。
二、DDA直线生成算法
DDA算法,又称数值微分画线算法,它的算法思想是:
1)每次下一个点距离上一个点X(或Y)方向前进一个距离,另一个方向前进1/k个距离,根据直线的斜率k,确定哪个方向前进1个距离,如果|k|>1,Y前进1个距离,X前进1/k个距离,如果|k|<1,X前进1个距离
2)前进后画点并重进进入步骤1直到画线完成
算法的代码演示
void drawLine_DDA(point2D point1,point2D point2,float R,float G,float B)
{
float dm = 0,dx = 0,dy = 0;
if(fabs(point2.x-point1.x) >= fabs(point2.y-point1.y))
{
dm = fabs(point2.x-point1.x);
}else
{
dm = fabs(point2.y-point1.y);
}
dx = (float)(point2.x-point1.x)/(dm*base);
dy = (float)(point2.y-point1.y)/(dm*base);
for(float i=0;i<dm*base;i++)
{
point2D tempPoint(point1.x,point1.y);
drawPoint(tempPoint,R,G,B,mrender_pointSize);
point1.x+=dx;
point1.y+=dy;
}
}
三、中点直线生成算法