openGL一之直线DDA,正负法,Bresenham算法,圆弧正负法,Bresenham算法

实验目的:

1.  掌握OpenGL环境的配置方法。

2.  熟悉OpenGL应用程序基础架构。

3.  熟练掌握简单OpenGL应用程序的建立、调试与运行。

4.  培养良好的编程习惯和风格,并且学习撰写实验报告。

实验步骤与内容:

1. 实现直线的DDA算法、正负法、Bresenham算法。

实验核心代码如下:

//直线DDA法
void dda(float x1, float y1,float  x2 ,float y2 ) {
	float k, i;
	float x, y, dx, dy;
	k = fabsf(x2 - x1);//这里用fabsf,这里可以取浮点数的绝对值
	if (fabsf(y2 - y1) > k)
		k =fabsf(y2 - y1);
	dx = float(x2 - x1) / k;
	dy = float(y2 - y1) / k;
	x = float(x1);
	y = float(y1);
	for (i = 0.0; i < k; i++) {
		glVertex2f(x, y);
		x = x + dx;//----q1
		y = y + dy;//----q2
	}
}

测试方法:

void Display1(void) {
	glClear(GL_COLOR_BUFFER_BIT);//注意这几个glClear等函数放的位置
	glPointSize(2.0);
	glColor3f(1.0, 0.0, 0.0);/*用红色绘制对象*/
	glBegin(GL_POINTS);
	dda(-250, 300, 300, 200);
	dda(-50, -100, 300, 250);
	dda(-500,0,0,-400);
	dda(-570, 0, 570, 0); //x轴
	dda(0, -570, 0, 570); //y轴
	glEnd();
	glFlush();
}

实验结果:


1.2 正负法:

//直线正负法
void MidpointLine(float xs, float ys, float xe, float ye) {
	float a, b, dt1, dt2, d, x, y;
	float absY = ye - ys;
	float absX = xe - xs;
	//采用对称的方法来绘画其他象限的图案
	if ((fabsf(absY) > fabsf(absX)) && absX>0 && absY>0) {//斜率大于1
		float  m = ys;
		ys = xs;
		xs = m;
		float n = ye;
		ye = xe;
		xe = n;
	}
	else if (absY<0 && absX>0 && (fabsf(absY) <= fabs(absX))) {//斜率-1到0
		ys = -ys;
		ye = -ye;
	}
	else if (absY<0 && absX>0 && (fabsf(absY)>fabs(absX))) {//斜率小于-1
		float  m = ys;
		ys = xs;
		xs = -m;
		float n = ye;
		ye = xe;
		xe = -n;
		/*printf("xs=%f\n", xs);
		printf("ys=%f\n", ys);
		printf("xe=%f\n", xe);
		printf("ye=%f\n", ye);*/

	}
	else {//斜率0到1
		  //do nothing 
	}
	a = ys - ye;
	b = xe - xs;
	d = 2 * a + b;
	dt1 = 2 * a;
	dt2 = 2 * (a + b);
	x = xs; y = ys;
	ManyGlVertex2f(absX, absY, x, y);
	while (x < xe) {
		if (d < 0) {
			x++;
			y++;
			d = d + dt2;
		}
		else {
			x++; d = d + dt1;
		}
		ManyGlVertex2f(absX, absY, x, y); //调用ManyGlVertex2f()函数
		
	}
	float maxY = getMax(ys, ye);
	float minY = getMin(ys, ye);
	//画竖直的线
	if (xs == xe) {
		for (float i = minY; i <=maxY; i++) {
			glVertex2f(xs, i);
		}
	}
	
}

其中ManyGlVertex2f(absX,absY, x, y);函数代码如下:

void ManyGlVertex2f(float absX,float absY,float x,float y) {
	if ((fabsf(absY) > fabsf(absX)) && absX>0 && absY>0) {//斜率大于1
		glVertex2f(y, x);
	}
	else if (absY<0 && absX>0 && (fabsf(absY) <= fabs(absX))) {//斜率-1到0
		glVertex2f(x, -y);
	}
	else if (absY<0 && absX>0 && (fabsf(absY)>fabs(absX))) {//斜率小于-1
		//printf("到这了\n");
		glVertex2f(y, -x);
	}
	else {//斜率0到1
		glVertex2f(x, y);
	}
}

测试方法:

void Display1(void) {
	glClear(GL_COLOR_BUFFER_BIT);//注意这几个glClear等函数放的位置
	glPointSize(2.0);
	glColor3f(1.0, 0.0, 0.0);/*用红色绘制对象*/
	glBegin(GL_POINTS);
	MidpointLine(-250, 250, 350, 200);
	MidpointLine(50, -150, 350, 250);
	MidpointLine(-450,50,0,400);
	MidpointLine(-570, 0, 570, 0);//x轴
	MidpointLine(0, -570, 0, 570);//y轴
	glEnd();
	glFlush();
}

实验结果:

1.3 Bresenham算法:

//直线Bresenham法
void Bresenham(float xs, float ys, float xe, float ye) {
	float absY = ye - ys;
	float absX = xe - xs;
	//采用对称的方法来绘画其他象限的图案
	if ((fabsf(absY) > fabsf(absX)) && absX>0 && absY>0) {//斜率大于1
		float  m = ys;
		ys = xs;
		xs = m;
		float n = ye;
		ye = xe;
		xe = n;
	}
	else if (absY<0 && absX>0 && (fabsf(absY) <= fabs(absX))) {//斜率-1到0
		ys = -ys;
		ye = -ye;
	}
	else if (absY<0 && absX>0 && (fabsf(absY)>fabs(absX))) {//斜率小于-1
		float  m = ys;
		ys = xs;
		xs = -m;
		float n = ye;
		ye = xe;
		xe = -n;
		/*printf("xs=%f\n", xs);
		printf("ys=%f\n", ys);
		printf("xe=%f\n", xe);
		printf("ye=%f\n", ye);*/

	}
	else {//斜率0到1
		  //do nothing 
	}
	float dx = xe - xs;
	float dy = ye - ys;
	float m = (double)dy / (double)dx;
	float e = m - 0.5;
	float x, y;
	x = xs;
	y = ys;
	for (int i = 0; i < dx; i++) {
		ManyGlVertex2f(absX, absY, x, y); //调用ManyGlVertex2f()函数
		if (e >= 0) {
			y = y + 1; e = e - 1;
		}
		x = x + 1; e = e + m;
	}
	
	//画竖直的线
	if (xs == xe) {
		float maxY = getMax(ys, ye);
		float minY = getMin(ys, ye);
		for (float i = minY; i <= maxY; i++) {
			glVertex2f(xs, i);
		}
	}
}

其中调用的ManyGlVertex2f()的代码和直线正负法中调用的ManyGlVertex2f()的方法一样。

测试方法:

void Display1(void) {
	glClear(GL_COLOR_BUFFER_BIT);//注意这几个glClear等函数放的位置
	glPointSize(2.0);
	glColor3f(1.0, 0.0, 0.0);/*用红色绘制对象*/
	glBegin(GL_POINTS);
	Bresenham(250, 250, 350, 200);
	Bresenham(50,150, 350, 250);
	Bresenham(-450,50,0,-400);
	Bresenham(-570, 0, 570, 0);//x轴
	Bresenham(0, -570, 0, 570);//y轴
	glEnd();
	glFlush();
}

实验结果:

2. 实现圆弧的正负法和Bresenham算法。

2.1圆弧正负法

//正负法
void pnarc(float radius,float m,float n) {
	float x, y, f;
	x = 0; y = 0 + radius; f = 0;
	while (y > 0) {
		glVertex2f(x+m, y+n);
		glVertex2f(-x+m, y+n);
		glVertex2f(-x+m,- y+n);
		glVertex2f(x+m, -y+n);
		if (f > 0) {
			f = f - 2 * y + 1; y = y - 1;
		}
		else {
			f = f + 2*x + 1; x = x + 1;
		}
	}
	if (y == 0) {
		glVertex2f(x + m, y + n);
		glVertex2f(-x + m, y + n);
		glVertex2f(-x + m, -y + n);
		glVertex2f(x + m, -y + n);

	}
}
测试方法:

void Display1(void) {
	glClear(GL_COLOR_BUFFER_BIT);//注意这几个glClear等函数放的位置
	glPointSize(2.0);
	glColor3f(1.0, 0.0, 0.0);/*用红色绘制对象*/
	glBegin(GL_POINTS);
	pnarc(150, -250, 250);
	pnarc(150, 250, 250);
	pnarc(150, 250, -250);
	pnarc(150, -250, -250);
	
	Bresenham(-570, 0, 570, 0);//x轴
	Bresenham(0, -570, 0, 570);//y轴
	glEnd();
	glColor3f(0, 1, 0);
	glBegin(GL_POINTS);
	pnarc(150, 0, 0);
	glEnd();

	glFlush();
}

实验结果:


2.2圆弧Bresenham算法

//Bresenham法
void bresenham_arc(float R,float m,float n) {
	float x, y, d;
	x = 0; y = R; d = 3 - 2 * R;
	while (x < y) {
		glVertex2f(x+m, y+n);
		glVertex2f(y+m, x+n);
		glVertex2f(y + m, -x + n);
		glVertex2f(x + m, -y + n);
		glVertex2f(-x + m, -y + n);
		glVertex2f(-y + m, -x + n);
		glVertex2f(-y + m, x + n);
		glVertex2f(-x + m, y + n);
		if (d < 0)
			d = d + 4 * x + 6;
		else {
			d = d + 4 * (x - y) + 10;
			y = y - 1;
		}
		x = x + 1;

	}
	if (x == y) {
		glVertex2f(x + m, y + n);
		glVertex2f(y + m, x + n);
		glVertex2f(y + m, -x + n);
		glVertex2f(x + m, -y + n);
		glVertex2f(-x + m, -y + n);
		glVertex2f(-y + m, -x + n);
		glVertex2f(-y + m, x + n);
		glVertex2f(-x + m, y + n);
	}
}

测试方法:

void Display1(void) {
	glClear(GL_COLOR_BUFFER_BIT);//注意这几个glClear等函数放的位置
	glPointSize(2.0);
	glColor3f(1.0, 0.0, 0.0);/*用红色绘制对象*/
	glBegin(GL_POINTS);
	bresenham_arc(150, -150, 100);
	bresenham_arc(150, 150, 100);
	bresenham_arc(150, 150, -100);
	bresenham_arc(150, -150, -100);
	
	Bresenham(-570, 0, 570, 0);//x轴
	Bresenham(0, -570, 0, 570);//y轴
	glEnd();
	glColor3f(0, 1, 0);
	glBegin(GL_POINTS);
	pnarc(150, 0, 0);
	glEnd();

	glFlush();
}

实验结果:


3. 利用上述完成的算法绘制中国象棋的棋盘和棋子。

//调用以上函数绘制中国象棋的棋盘和棋子
void Display(void) {
	glClear(GL_COLOR_BUFFER_BIT);//注意这几个glClear等函数放的位置
	glPointSize(2.0);
	glColor3f(0.0, 0.0, 0.0);/*用红色绘制对象*/
	glBegin(GL_POINTS);
	for (float i = -360; i <= 360; i += 80) {
		dda(-360, i, 360, i);
	}
	for (float i = -360; i <= 360; i += 90) {
		dda(i, 40, i, 360);
	}
	for (float i = -360; i <= 360; i += 90) {
		dda(i, -40, i, -360);
	}
	dda(-360, -40, -360, 40);
	dda(360, -40, 360, 40);
	float b = 90, c = 200, d = 360;
	dda(-b, c, b, d);
	dda(-b, d, b, c);
	dda(-b, -d, b, -c);
	dda(-b, -c, b, -d);
	glEnd();
	//画象棋图上的圆
	glColor3f(1.0, 0.0, 0.0);
	glBegin(GL_POINTS);
	float R = 28;
	for (float i = -360; i <= 360; i += 90) {
		pnarc(R, i, 360);
		pnarc(R, i, -360);
	}
	for (float i = -360; i <= 360; i += 180) {
		pnarc(R, i, 40);
		pnarc(R, i, -40);
	}
	for (float i = -270; i <= 320; i += 540) {
		pnarc(R, i, 200);
		pnarc(R, i, -200);
	}
	glEnd();
	//最外侧直线
	glPointSize(3.0);
	glColor3f(0.0, 0.0, 0.0);
	glBegin(GL_POINTS);
	float a = 380;
	dda(-a, a, a, a);
	dda(a, a, a, -a);
	dda(a, -a, -a, -a);
	dda(-a, -a, -a, a);
	glEnd();
	glFlush();
}

结果:

4.以下是属性设置函数和主函数main()

//设置属性
void myinit(void) {
	/*设置属性*/
	glClearColor(1.0, 1.0, 1.0, 1.0);/*白色背景*/
	/*建立视图*/
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(-570.0, 570.0, -570.0, 570.0);//二维视图区域*
	glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char * argv[])
 {
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
 glutInitWindowPosition(20, 40);//设置位置
 glutInitWindowSize(680, 680);//设置高宽
 glutCreateWindow("第一个OpenGL程序");
 myinit();
 glutDisplayFunc(&Display);
 glutMainLoop();
 return 0;
 }

结论分析与体会:

  此次实验着重独立完成直线和圆弧的各种生成算法,这也是我们学习计算机图形学的目的,我们不仅要会使用openGL,更要懂得其内部实现算法,通过此次的实验课程,我们可以很清晰明了的了解具体实现。其实最有难度的还是前面的算法,只要完成了前面的算法,后面的棋盘绘画就比较容易了。整体来说,此次实验难度并不大,当然期间也遇到许多的小问题,不过最后问题都已解决。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值