實驗2 基本圖元光柵化

1.實驗目的:

  • 理解基本圖形元素光柵化的基本原理;
  • 掌握基本圖形元素光柵化方法,如中點方法,Bresenham方法;
  • 利用OpenGL實現基本圖形元素的光柵化算法。

2.實驗內容:

(1) 閱讀學習所給的直線光柵化的DDA算法示範代碼,將其徹底弄懂,根據實驗思考題找出其中的錯誤;同時能在計算機上編譯運行,輸出正確結果,指出錯誤並截圖保存爲圖1至word實驗文檔(30分鐘);

(2) 在示範程序的基礎上,根據程序所留接口,增加中點線算法,並給出若干條測試直線實例,,截圖保存爲圖2至word實驗文檔(30分鐘);

(3) 爲示範程序增加中點圓繪製算法,同時增加鍵盤按鍵控制(數字按鍵3),並給出若干個測試圓的實例,截圖保存爲圖3至word實驗文檔(30分鐘);

(4) 整理圖1-3,並增加程序代碼合併到一個word文檔,將其命名爲“序號-姓名-Prj2.doc”,電子版提交至雨課堂,A4打印稿下一次課前或實驗課前提交。

3.實驗原理:

示範代碼原理參見教材直線光柵化一節中的DDA算法。下面介紹下OpenGL畫線的一些基礎知識和glutReshapeFunc()函數。

(1)數學上的直線沒有寬度,但OpenGL的直線則是有寬度的。同時,OpenGL的直線必須是有限長度,而不是像數學概念那樣是無限的。可以認爲,OpenGL的“直線”概念與數學上的“線段”接近,它可以由兩個端點來確定。這裏的線由一系列頂點順次連結而成,有閉合和不閉合兩種。

前面的實驗已經知道如何繪“點”,那麼OpenGL是如何知道拿這些頂點來做什麼呢?是一個一個的畫出來,還是連成線?或者構成一個多邊形?或是做其它事情呢?爲了解決這一問題,OpenGL要求:指定頂點的命令必須包含在glBegin函數之後,glEnd函數之前(否則指定的頂點將被忽略),並由glBegin來指明如何使用這些點。

例如:

glBegin(GL_POINTS);

    glVertex2f(0.0f, 0.0f);

    glVertex2f(0.5f, 0.0f);

glEnd();

則這兩個點將分別被畫出來。如果將GL_POINTS替換成GL_LINES,則兩個點將被認爲是直線的兩個端點,OpenGL將會畫出一條直線。還可以指定更多的頂點,然後畫出更復雜的圖形。另一方面,glBegin支持的方式除了GL_POINTS和GL_LINES,還有GL_LINE_STRIP,GL_LINE_LOOP,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN等,每種方式的大致效果如圖A.2所示:

在這裏插入圖片描述

圖A.2 OpenGL幾何圖元類型

(2)首次打開窗口、移動窗口和改變窗口大小時,窗口系統都將發送一個事件,以通知程序員。如果使用的是GLUT,通知將自動完成,並調用向glutReshapeFunc()註冊的函數。該函數必須完成下列工作:

  • 重新建立用作新渲染畫布的矩形區域;

  • 定義繪製物體時使用的座標系。

如:

void Reshape(int w, int h)

{

glViewport(0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);

}

在GLUT內部,將給該函數傳遞兩個參數:窗口被移動或修改大小後的寬度和高度,單位爲像素。glViewport()調整像素矩形,用於繪製整個窗口。接下來三個函數調整繪圖座標系,使左下角位置爲(0, 0),右上角爲(w, h)。

(3) 鍵盤輸入

當你按下一個鍵後,GLUT提供了兩個函數爲這個鍵盤消息註冊回調。第一個是glutKeyboardFunc,用來處理普通按鍵,如字母,數字,和其他可以用ASCII代碼表示的鍵;另一個是glutSpecialFunc,用來處理特殊按鍵,如FiF_i,方向鍵,Home,End鍵等。

glutKeyboardFunc函數原型如下:
void glutKeyboardFunc(void(*func)(unsigned char key,int x,int y));
參數:
func: 處理普通按鍵消息的函數的名稱。如果傳遞NULL,則表示GLUT忽略普通按鍵消息。
這個作爲glutKeyboardFunc函數參數的函數需要有三個形參:第一個表示按下的鍵的ASCII碼,其餘兩個提供了當鍵按下時當前的鼠標位置。鼠標位置是相對於當前客戶窗口的左上角而言的。

glutSpecialFunc函數請參考https://blog.csdn.net/xie_zi/article/details/1911891

4.實驗代碼:

#include <GL/glut.h>

int flag = 0;
void LineDDA(int x0,int y0,int x1,int y1/*,int color*/)
{
	int  x, dy, dx, y;
	float m;
	dx=x1-x0;
	dy=y1-y0;
	m=dy/dx;
	y=y0;

	glColor3f (1.0f, 1.0f, 0.0f);   
	glPointSize(1);
	for(x=x0;x<=x1; x++)
	{
		glBegin (GL_POINTS);
		glVertex2i (x, (int)(y+0.5));
		glEnd ();
		y+=m;
	}		
}

void LineMidPoint(int x0, int y0, int x1, int y1)
{
	//請在這裏填寫你的代碼
}

void myDisplay(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f (1.0f, 0.0f, 0.0f); 
	glRectf(25.0, 25.0, 75.0, 75.0);

	glPointSize(5);
	glBegin (GL_POINTS);
	glColor3f (0.0f, 1.0f, 0.0f);   glVertex2f (0.0f, 0.0f);
	glEnd ();

	glBegin (GL_LINES);
	glColor3f (1.0f, 0.0f, 0.0f);   glVertex2f (100.0f, 0.0f);
	glColor3f (0.0f, 1.0f, 0.0f);   glVertex2f (180.0f, 240.0f);	
	glEnd ();

	if(flag == 1)
		LineDDA(0, 0, 200, 300);

	//if (flag == 2)
		//LineMidPoint(...);

	glFlush();
}

void Init()
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_FLAT);
}

void Reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei) w,  (GLsizei) h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, (GLdouble) w, 0.0, (GLdouble) h);
}

void keyboard(unsigned char key, int x, int y)
{
	switch (key)
	{
	case '1'://DDA Line
		flag = 1;
		break;
	case '2': // MidPoint Line
		//請在這裏填寫你的代碼
		
		break;
	default:
		break;
	}
	glutPostRedisplay();//重畫
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("Hello World!");
	Init();
	glutDisplayFunc(myDisplay);
	glutReshapeFunc(Reshape);
	glutKeyboardFunc(keyboard);
	glutMainLoop();
	return 0;
}

注: glShadeModel選擇平坦或光滑漸變模式。GL_SMOOTH爲缺省值,爲光滑漸變模式,GL_FLAT爲平坦漸變模式。

5.實驗思考

示範代碼有個小錯誤,能否指出並改正?請將結果寫入實驗報告。

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