1. 程式人生 > >實驗三   OpenGL的簡單互動繪製

實驗三   OpenGL的簡單互動繪製

一、實驗目的

1.理解OpenGL座標系的概念,掌握OpengGL裁剪視窗、視區、顯示視窗的概念和它們之間的關係,學會計算世界座標和螢幕座標。

2.學會OpenGL的簡單鍵盤互動操作。

3.學會OpenGL的簡單字元繪製。

4.進一步掌握OpengGL點、直線、多邊形的繪製。

、實驗內容

1.調出實驗一的原始碼執行,調整修改使得顯示視窗在螢幕中央保持預設大小(300*300),繪製的矩形在顯示視窗中央。如圖3-1所示。

提示:

1)新增修改視窗位置的函式glutInitWindowPosition(int x, int y);其中(x,y)為視窗左上角在螢幕上的位置。

2)顯示視窗的左下角座標為(-1,-1),右上角座標為(1,1)。

                                     圖3-1 中央矩形

2.在實驗一的基礎上新增鍵盤互動,按W鍵繪製的矩形上移,按S鍵矩形下移,按A鍵矩形左移,按D鍵矩形右移,如圖3-2。參考步驟如下:

1)在主函式裡添加註冊鍵盤迴調函式

glutKeyboardFunc(mykeyboard);

此函式可放在 glutDisplayFunc(display);後面。

2)在display()繪製函式中修改繪製矩形程式碼,用變數代替數值引數。

例如:

glRectf(-0.5,-0.5,0.5,0.5)

改為

glRectf(x1,y1,x2,y2);

程式前面加上變數宣告和初始值,如:

float x1=-0.5,y1=-0.5,x2=0.5,y2=0.5;  

注意語句的位置。

  1. 在程式中增加mykeyboard鍵盤子函式,可放在display()函式之後。並在如下程式碼中進行修改,實現鍵盤控制矩形移動,執行程式自行測試。

void mykeyboard(unsigned char key, int x, int y)

{

switch(key)

{   

case 'W':

       case 'w':// 矩形對角座標變數修改使得矩形上移

y1+=0.1; y2+=0.1;

              break;

case 'S':

      case 's'://矩形對角座標變數修改使得矩形下移

                  y1-=0.1;y2-=0.1;

           break;

case 'A':

       case 'a'://矩形對角座標變數修改使得矩形左移

                  x1-=0.1; x2-=0.1;

           break;

case 'D':

       case 'd'://矩形對角座標變數修改使得矩形右移

                  x1+=0.1; x2+=0.1;

           break;   

       }

    //引數修改後呼叫重畫函式,螢幕圖形將發生改變

       glutPostRedisplay();  

}

                                             圖3-2 矩形的上下左右移動

3.設定視窗改變函式,使得矩形的長度和寬度等於100,程式啟動時矩形仍在視窗中央,當顯示視窗最大化時,繪製矩形也隨之增大,如圖3-3所示。         

1)在main函式裡添加註冊視窗變化函式

glutReshapeFunc(myreshape); //放在glutMainLoop()之前

2)在程式中新增視窗改變子函式,引數w,h為當前顯示視窗的寬和高

void myreshape(GLsizei w, GLsizei h)

{

glViewport(0,0,w,h);   //設定視區位置

glMatrixMode(GL_PROJECTION);//設定投影變換模式

glLoadIdentity();  //調單位矩陣,清空當前矩陣堆疊

gluOrtho2D(0,300,0,300);  

}

3) 此時,矩形的初始變數經重新計算後為:

float x1=100,x1=100,x2=200,y2=200;

注意:請同學們自己思考為什麼矩形初始的初始變數由原來的(-0.5,-0.5,0.5,0.5)變為(100,100,200,200) ?裁剪視窗設定函式gluOrtho2D(xwmin,xwmax,ywmin,ywmax); 和視區設定函式 glViewport(startx,starty,viewport_width,viewport_height)的設定有何規律?

答:myreshape函式改變了視窗的原點座標和座標單位值。

此時,按下鍵盤“WADS”鍵進行互動移動,矩形的移動距離較之前有什麼變化?要保持以前的移動頻率,程式應該如何修改?

答:移動的距離變得很小,要保持以前的移動頻率應該修改mykeyboard函式的座標改變值。

          

       a) 顯示視窗改變前                                          b)顯示視窗變大後

3-3 顯示視窗改變

4.在矩形中間新增字元"Hello",觀察結果;然後將"Hello"字元改為自己名字的拼音或英文名字。如圖3-4所示。

提示:在繪製矩形後新增如下程式碼:

glColor3f(1,0,0);

glRasterPos2i((x1+x2)/2,(y1+y2)/2);    //定位當前游標

glutBitmapCharacter(GLUT_BITMAP_9_BY_15,'H');  //寫字元"H"

glutBitmapCharacter(GLUT_BITMAP_9_BY_15,'e');  //寫字元"e"

glutBitmapCharacter(GLUT_BITMAP_9_BY_15,'l');   //寫字元"l"

glutBitmapCharacter(GLUT_BITMAP_9_BY_15,'l');   //寫字元"l"

glutBitmapCharacter(GLUT_BITMAP_9_BY_15,'o');   //寫字元"o"

注意:執行程式,效果如圖3-4所示。但是如果此時,按下鍵盤“WADS”鍵進行互動移動,程式會發生什麼變化?要保持矩形白色,字元紅色,程式應該如何修改?

答:字元會跟著動,不用改啊。。。

如果字元顏色設定語句glColor3f(1,0,0);放在定位游標語句glRasterPos2i((x1+x2)/2,(y1+y2)/2); 之後,執行又會發生什麼變化?自己總結設定字元顏色語句的順序規律。

答:字元顏色會變成矩形的顏色。

3-4 新增字元

5.自己參照講義或教材按照自己的構思畫二維平面圖形,將上面的矩形替換成自己構思的二維平面圖形實現互動功能,注意頂點的順序。並在畫面上標註自己的姓名。

 

功能描述:按W、S、A、D會上下左右移動,按Q縮小,按E放大。

三、思考題

按下列步驟操作,並分析裁剪視窗、視區和顯示視窗的關係。

1)修改視區大小為原來的一半。如圖3-5a所示

2)修改裁剪視窗的大小原來的一半;視區保持不變。如圖3-5b所示

                   a)修改視區                                        b)修改視窗                 

                                                      圖3-5

參考函式:

1.裁剪視窗設定函式:

gluOrtho2D(xwmin,xwmax,ywmin,ywmax);//xwmin,xwmax,ywmin,ywmax為裁剪視窗在世界座標系的位置,分別為x最小,x最大,y最小,y最大

2.視區設定函式:

glViewport(startx,starty,viewport_width,viewport_height);//繪圖區在顯示視窗中的位置,以螢幕座標系為參考,startx,starty,viewport_width,viewport_height分別為繪圖區在顯示視窗的起點位置, 以及繪圖區的寬度和高度

  1. 修改以上程式是的按數字1建實現矩形用W、S、A、D鍵控制上、下、左、右移動,按2鍵顯示自己構思的其他2D圖形(三角形、點或多邊形等),用W、S、A、D鍵控制上、下、左、右移動。

四、程式碼

#include<glut.h>
#include<stdio.h>
#include<windows.h>

float x1=100, y1=0, x2=0, y2=100,x3=0, y3=0;
int flag = 0;
void display(void)
{
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//設定清屏顏色
	glClear(GL_COLOR_BUFFER_BIT);//重新整理顏色快取區

	if(flag==1) glRectf(x1, y1, x2, y2); 

	if(flag==2)
	{
		glColor3f(0.5, 0.5, 0.5);
		glBegin(GL_TRIANGLES);
		glVertex2f(x1, y1);
		glVertex2f(x2, y2);
		glVertex2f(x3, y3);
		glEnd();
	}


	glFlush();//重新整理命令佇列和快取區,是所有尚未執行的OpenGL命令得到執行
}


void mykeyboard(unsigned char key, int x, int y)
{
	switch (key)
	{
	case '1':
		flag = 1;
		break;
	case '2':
		flag = 2;
		break;
	case 'W':
	case 'w':// 矩形對角座標變數修改使得矩形上移
		y1 += 10; y2 += 10; y3+=10;
		break;
	case 'S':
	case 's'://矩形對角座標變數修改使得矩形下移
		y1 -= 10;y2 -= 10; y3 -= 10;
		break;
	case 'A':
	case 'a'://矩形對角座標變數修改使得矩形左移
		x1 -= 10; x2 -= 10; x3-=10;
		break;
	case 'D':
	case 'd'://矩形對角座標變數修改使得矩形右移
		x1 += 10; x2 += 10; x3 += 10;
		break;
	case 'Q':
	case 'q'://縮小
		x1 -=10;
		y2 -=10;
		break;
	case 'E'://放大
	case 'e':
		x1 += 10;
		y2 += 10;
		break;
	}
	
	//引數修改後呼叫重畫函式,螢幕圖形將發生改變
	glutPostRedisplay();
}

void myreshape(GLsizei w, GLsizei h)
{
	glViewport(0, 0, w, h);   //設定視區位置
	glMatrixMode(GL_PROJECTION);//設定投影變換模式
	glLoadIdentity();  //調單位矩陣,清空當前矩陣堆疊
	gluOrtho2D(0, 300, 0, 300);
}

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR 						lpCmdLine, int nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);
	char *argv[] = { "hello "," " };
	int argc = 2;
	glutInit(&argc, argv);    //初始化GLUT庫;
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);   //設定顯示模式;(緩衝,顏色型別)
	glutInitWindowSize(300, 300);//繪製視窗大小
	glutInitWindowPosition(1024 / 2 - 250, 768 / 2 - 250);//視窗左上角在螢幕的位置
	glutCreateWindow("hello");  //建立視窗,標題為“hello”;
	glutDisplayFunc(display);  //顯示回撥函式用於繪製當前視窗;
	glutKeyboardFunc(mykeyboard);
	glutReshapeFunc(myreshape);
	glutMainLoop();   //表示開始執行程式,用於程式的結尾;
	return 0;
}