計算機圖形學OpenGL學習實驗二——Bresenham畫線算法的模擬

  • 寫在開頭:

相關實驗是學校開設課程的相關實驗,本人所作較爲粗淺,若有同校師弟瀏覽,望看懂借鑑而非照搬全抄。


  • 實驗目的:

理解Bresenham畫線算法


  • 實驗內容:

用Bresenham畫線算法實現水平、垂直、斜率大於1、斜率小於1、斜率爲正、斜率爲負等各種情況(不能直接調用OpenGL畫線函數)。


  • 實現效果及步驟(或流程)

實現效果:

         繪製了一個大小爲40 × 40 網格圖(座標爲0~39),用以模擬屏幕像素。以(20,20)爲中心,繪製了六條“直線”。這些“直線”模擬了當屏幕像素點被放大至肉眼可見時,Bresenham算法繪製直線時的繪製情況。

實現流程:

       首先判斷斜率是否小於1,如果是則計算p值(p=2dy –dx),而後選擇起點並繪製起點;接着判斷斜率正負,如果爲正,則x遞增1,通過p值判斷y值,並且計算相應的p值,否則x遞減1。

       如果斜率大於1,則將求p值公式x、y互換,並且將x遞增或遞減的變化過程改爲y遞增或遞減。

具體流程見下圖。


  • 創新設計和實現方法

創新設計:

        使用正方形塊模擬屏幕像素點,繪製屏幕網格圖,展示Bresenham算法選點的過程。

實現方法:

    1.網格的繪製:

        設置矩形塊爲線性填充,使用二維數組blocks[40][40]存儲矩形塊,取blocks[x][y],即代表取屏幕座標(x,y)。

相關代碼如下:

void initBlocks() {

glPolygonMode(GL_FRONT, GL_LINE);

GLint x = 0, y = 0;

glColor3f(0.0, 0.0, 1.0);

//初始化矩形塊座標

for (int i = 0; i < 40; i++) {

       for (int j = 0; j < 40; j++) {

              blocks[i][j].point[0] = x;

              blocks[i][j].point[1] = y;

              y +=  10;

       }

       y = 0;

       x += 10;

}

//繪製矩形

for (int i = 0; i < 40; i++) {

       for (int j = 0; j < 40; j++) {

              glRecti(blocks[i][j].point[0], blocks[i][j].point[1],

                     blocks[i][j].point[0] + 10, blocks[i][j].point[1] + 10);

       }

}

glFlush();

}

 

2.繪製“像素點”

        如果需要繪製點(x,y),那麼繪製矩形塊blocks[x][y]即可。

        相關代碼如下:

//選取像素塊

void setPixel(GLint x, GLint y) {

glPolygonMode(GL_FRONT, GL_FILL);//設置矩形爲填充模式

glColor3f(0.0, 1.0, 0.0);

glRecti(blocks[x][y].point[0], blocks[x][y].point[1],

blocks[x][y].point[0] + 10, blocks[x][y].point[1] + 10);

glFlush();

}

  • 源代碼
#include <GL/glut.h>
#include <iostream>

void bresenham(GLint x1, GLint y1, GLint x2, GLint y2);
GLsizei winWidth = 400, winHeight = 400;

//“像素塊”
struct block {
	GLint point[2];
};

block blocks[40][40];

//初始化像素塊
void initBlocks() {
	glPolygonMode(GL_FRONT, GL_LINE);
	GLint x = 0, y = 0;
	glColor3f(0.0, 0.0, 1.0);
	for (int i = 0; i < 40; i++) {
		
		for (int j = 0; j < 40; j++) {
			
			blocks[i][j].point[0] = x;
			blocks[i][j].point[1] = y;
			y +=  10;
		}
		y = 0;
		x += 10;
	}
	for (int i = 0; i < 40; i++) {
		for (int j = 0; j < 40; j++) {
			glRecti(blocks[i][j].point[0], blocks[i][j].point[1],
				blocks[i][j].point[0] + 10, blocks[i][j].point[1] + 10);
		}
	}
	//調試用
	//for (int i = 0; i < 40; i++) {

	//	for (int j = 0; j < 40; j++) {
	//		std::cout << i << ","  <<j <<" (" << blocks[i][j].point[0] << ","
	//		    << blocks[i][j].point[1] << ")" << " ";
	//	}
	//	std::cout << std::endl;
	//}
	glFlush();

}

//選取像素塊
void setPixel(GLint x, GLint y) {
	//glBegin(GL_POINTS); 
	//	glVertex2i(x, y);
	//glEnd();
	glPolygonMode(GL_FRONT, GL_FILL);
	glColor3f(0.0, 1.0, 0.0);
	std::cout << "(" << blocks[x][y].point[0] << "," << blocks[x][y].point[1] << ")" << " ";
	glRecti(blocks[x][y].point[0], blocks[x][y].point[1],
		blocks[x][y].point[0] + 10, blocks[x][y].point[1] + 10);
	glFlush();
}

void init(void) {
	glClearColor(1.0, 1.0, 1.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}

void displayFcn() {
	initBlocks();
	glColor3f(0.0, 1.0, 0.0);
	
	bresenham(5,20,35,20);//水平線段
	bresenham(20,5,20,35);//垂直線段
	bresenham(5, 13, 35, 27);//斜率介於0到1之間的直線
	bresenham(5, 27, 35, 13);//斜率介於-1到0之間的直線
	bresenham(13, 35, 27, 5);//斜率小於-1的直線
	bresenham(27, 35, 13, 5);//斜率大於-1的直線

}


void bresenham(GLint x1, GLint y1, GLint x2, GLint y2) {
	GLint dx_sigend = x1 - x2, dy_sigend = y1 - y2;
	GLint dx = fabs(dx_sigend), dy = fabs(dy_sigend);
	GLint twoDy = 2 * dy, twoDx = 2 * dx;
	GLint twoDyMinusDx = 2 * (dy - dx),twoDxMinusDy = 2 * (dx - dy);
	GLint p;
	GLint x, y;

	// 判斷斜率是否大於1
	if (dy < dx) {
		p = twoDy - dx;
		//判斷斜率正負
		if ((dx_sigend < 0 && dy_sigend < 0) || (dx_sigend > 0 && dy_sigend > 0)) {
			//判斷所給點的起點
			if (x1 > x2) {
				x = x2;
				y = y2;
				x2 = x1;
			}
			else {
				x = x1;
				y = y1;
			}
			setPixel(x, y);

			while (x < x2) {
				x++;
				if (p < 0) {
					p += twoDy;
				}
				else {
					++y;
					p += twoDyMinusDx;
				}
				setPixel(x, y);
			}
		}
		else {
			//判斷所給點的起點
			if (x1 < x2) {
				x = x2;
				y = y2;
				x2 = x1;
			}
			else {
				x = x1;
				y = y1;
			}
			setPixel(x, y);

			while (x > x2) {
				x--;
				if (p < 0) {
					p += twoDy;
				}
				else {
					++y;
					p += twoDyMinusDx;
				}
				setPixel(x, y);
			}
		}
		
	}
	else {
		p = twoDx - dy;
		//判斷斜率正負
		if ((dx_sigend < 0 && dy_sigend < 0) || (dx_sigend > 0 && dy_sigend > 0)) {
			//判斷所給點的起點
			if (y1 > y2) {
				x = x2;
				y = y2;
				y2 = y1;
			}
			else {
				x = x1;
				y = y1;
			}
			setPixel(x, y);

			while (y < y2) {
				y++;
				if (p < 0) {
					p += twoDx;
				}
				else {
					++x;
					p += twoDxMinusDy;
				}
				setPixel(x, y);
			}
		}
		else {
			//判斷所給點的起點
			if (y1 < y2) {
				x = x2;
				y = y2;
				y2 = y1;
			}
			else {
				x = x1;
				y = y1;
			}
			setPixel(x, y);

			while (y > y2) {
				y--;
				if (p < 0) {
					p += twoDx;
				}
				else {
					++x;
					p += twoDxMinusDy;
				}
				setPixel(x, y);
			}
		}
	}
	

}

void winReshapeFcn(GLint newWidth, GLint newHeight) {
	glClear(GL_COLOR_BUFFER_BIT);
	glViewport(0, 0, newWidth, newHeight);
	glLoadIdentity();
	gluOrtho2D(0.0, GLdouble(newWidth), 0.0, GLdouble(newHeight));

	winWidth = newWidth;
	winHeight = newHeight;
}


void main(int argc, char ** argv) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(winWidth, winHeight);
	glutCreateWindow("CGLab3_CaiYiPei");

	init();

	glutDisplayFunc(displayFcn);
	glutReshapeFunc(winReshapeFcn);

	glutMainLoop();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章