一、实验目的
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;
注意语句的位置。
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分别为绘图区在显示窗口的起点位置, 以及绘图区的宽度和高度
四、代码
#include
#include
#include
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;
}