计算机图形学初探——Bresenham直线光栅化算法绘制一条直线(详细版)

开发和运行环境

开发和运行环境为visual studio。使用OpenGL开放式图形库,使用的头文件为#include <GL/glut.h>。

算法的设计思想和实现技术

使用实现Bresenham直线光栅化算法,在此对该算法的原理进行阐述。
算法原理:假定直线的斜率k在0~1之间。此时,只需考虑x方向每次递增1个单位,决定y方向每次递增0或1。
设直线的当前点为(xi,y),对应的当前光栅点为(xi,yi),对于直线为k的直线,易知线上下一个点应该为(xi+1,yi+k),则直线的光栅点为(xi+1,yi)或者(xi+1,yi+1)其中yi是否加一取决于直线与它垂直方向最近的下光栅点的误差d,d的计算方法为
其中y+k为直线上xi+1位置对应的纵坐标,yi为xi处对应的纵坐标,如下图所示。
在这里插入图片描述
如图易知当d<0.5:下一个象素应取右光栅点(xi+1,yi)
当d≥ 0.5:下一个象素应取右上光栅点(xi+1,yi+1)
如果直线的(起)端点在整数点上,误差项d的初值:d0=0x坐标每增加1,d的值相应递增直线的斜率值k,即:d=d+k。一旦d≥ 1,就把它减去1,保证d的相对性,且在
0-1之间。
令e=d-0.5,关于d的判别式和初值可简化成:
e的初值e0= -0.5,增量亦为k;
e<0时,取当前象素(xi,yi)的右方象素(xi+1,yi);
e>0 时,取当前象素( xi,yi) 的右上方象素(xi+1,yi+1);
e=0时,可任取上、下光栅点显示。
据上,可将Bresenham直线光栅化算法简化概括为:
它引入动态误差e,当x方向每次递增1个单位,可根据e的符号决定y方向每次递增0或1。e<0,y方向不递增,e>0,y方向递增1,x方向每次递增1个单位,e = e + k。
因为e是相对量,所以当e>0时,表明e的计值将进入下一个参考点(上升一个光栅
点),此时须:e = e – 1。此时y将上升到下一个光栅处。
若可搞清楚上述原理,此时即可附上代码了


#include <GL/glut.h> 
#include<math.h>
GLfloat pointsize = 1.0f;

void init(void)
{

	glClearColor(0.0, 0.0, 0.0, 0.0);//设置背景颜色为黑色

	glShadeModel(GL_SMOOTH);//设置为光滑明暗模式
	gluOrtho2D(0.0, 200.0, 0.0, 200.0);///*设定映射区域,参数为(minX,maxX,minY,maxY),(minX,minY为原点);(maxX, maxY)为右上角的点* /
}

void Bresenham_drawOneLine(GLint xs, GLint ys, GLint xe, GLint ye) {
	GLint  x = xs;
	GLint  y = ys;
	GLint dx = xe - xs;
	GLint dy = ye - ys;
	GLfloat k = float(dy / dx);
	GLfloat error = k - 0.5;//开始在光栅点处,d=0,下一个点处d=k
	for (int i = 1; i < dx; i++)
	{
		glBegin(GL_LINES);
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex2i(x, y);
		if (error > 0)
		{
			y = y + 1;
			error = error - 1;//由于y上升了	
		}
		x = x + 1;
		error = error + k;
	}
	glEnd();//结束

	glFlush();

	/*OpenGL指令不是立即执行的。它们首先被送到指令缓冲区,然后才被送到硬件执行。

	glFlush都是强制将命令缓冲区的内容提交给硬件执行。*/
}
void Bresenham_Rotationline()
{	glClear(GL_COLOR_BUFFER_BIT);			//清除所有的像素
	glEnable(GL_LINE_STIPPLE);				//点画线模式
	glColor3f(1.0, 0.0, 0.0);					//使用红色绘制该线段
	Bresenham_drawOneLine(0, 0, 100, 100);
	glFlush();
}
int main(int argc, char ** argv)

{

	/*初始化*/

	glutInit(&argc, argv);

	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//单缓冲、RGB模式

	glutInitWindowSize(400, 400);

	glutInitWindowPosition(200, 200);

	glutCreateWindow("Bresenham直线光栅化算法");//窗口标题

	init();

	/*绘制与显示*/

	//glutReshapeFunc(myReshape);//窗口大小发生改变时采取的行为

	glutDisplayFunc(Bresenham_Rotationline);//将图传递给显示窗口,参数是描述的一个程序,即调用这个函数再送到显示窗口

	glutMainLoop();//循环

	return(0);//去掉这个函数,程序窗口一打开就马上关!
}


执行结果如图所示
在这里插入图片描述

对算法的一些改进

对于初值e=dy/dx-0.5可通过左右两边同乘2dx,令NError = 2Error∆x。即可化乘为加。
划线部分代码即转换为

void Bresenham_drawOneLine(GLint xs, GLint ys, GLint xe, GLint ye) {
	GLint  x = xs;
	GLint  y = ys;
	GLint dx = xe - xs;
	GLint dy = ye - ys;
	GLfloat k = float(dy / dx);
	GLfloat Nerror =2*dy - dx;//开始在光栅点处,d=0,下一个点处d=k
	for (int i = 1; i < dx; i++)
	{
		glBegin(GL_LINES);
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex2i(x, y);
		if (Nerror > 0)
		{
			y = y + 1;
			Nerror = Nerror - 2*dx;//由于y上升了	
		}
		x = x + 1;
		Nerror = Nerror + 2*dy;
	}
	glEnd();//结束

	glFlush();

	/*OpenGL指令不是立即执行的。它们首先被送到指令缓冲区,然后才被送到硬件执行。

	glFlush都是强制将命令缓冲区的内容提交给硬件执行。*/
}

一般的Bresenham算法

上述算法为0<k<1的情况,要想使其具有普适性,只需做以下两点改动
1.当直线的斜率|k|>1时,改成y的增量总是1,再用Bresenham误差判别式确定x变量是否需要增加1;(相当于x,y互换)
2.x或y的增量可能是“+1”或“-1”,视直线所在的象限决定。

void Bresenham_drawOneLine(GLint xs, GLint ys, GLint xe, GLint ye) {
	GLint  x = xs;
	GLint  y = ys;
	int  flag;//用以表示是否发生了交换
	GLint dx = abs(xe - xs);
	GLint dy = abs(ye - ys);
	GLint sx = ((xe > xs)?1:-1);
	GLint sy = ((ye > ys)?1:-1);
	if (dy > dx)
	{
		swap(dx, dy);
		flag = 1;
	}
	else
	{
		flag = 0;
	}
	cout << flag;
	GLfloat Nerror =2*dy - dx;//开始在光栅点处,d=0,下一个点处d=k
	for (int i = 1; i < dx; i++)
	{
		glBegin(GL_LINES);
		glColor3f(1.0f, 0.0f, 0.0f);
		//cout << x << y << endl;
		glVertex2i(x, y);
		if (Nerror>=0)
		{
			if (flag)
			{
				x = x + sx;
			}
			else
			{
				y = y + sy;
			}
			Nerror = Nerror - 2*dx;	
		}
		if (flag)
		{
			y = y + sy;
		}
		else
		{
			x = x + sx;
		}
		Nerror = Nerror + 2*dy;
	}
	glEnd();//结束

	glFlush();

	/*OpenGL指令不是立即执行的。它们首先被送到指令缓冲区,然后才被送到硬件执行。

	glFlush都是强制将命令缓冲区的内容提交给硬件执行。*/
}

由此就可以画出各种各样的线喽!

  • 7
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值