實驗三 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;
注意語句的位置。
- 在程式中增加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建實現矩形用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;
}