一、实验目的
1.理解OpenGL坐标系的概念,掌握OpenGL裁剪窗口、视区、显示窗口的概念和它们 之间的关系,学会计算世界坐标和屏幕坐标。
2.学会OpenGL的简单键盘交互操作。
3.学会OpenGL的简单字符绘制。
4.进一步掌握OpenGL点、直线、多边形的绘制。
二、实验内容
1.调岀实验一的源代码运行,调整修改使得显示窗口在屏幕中央保持默认大小(300x300 ),绘制的矩形在显示窗口中央,如下图所示:
提示:
1)添加修改窗口位置的函数glutInitWindowPosition(int x, int y),其中(x,y)为窗口左上角在屏幕上的位置。
2)显示窗口的左下角坐标为(-1,-1),右上角坐标 为(1,1)。
2.在实验一的基础上添加键盘交互,按W键绘制的 矩形上移,按S键矩形下移,按A键矩形左移,按D键 矩形右移,如实验图3-2所示。参考步骤如下:
1)在主函数里添加键盘注册回调函数:
glutKeyboardFunc(mykeyboard);
此函数可放在 glutDisplayFunc(display)后面。
2)在display ()绘制函数中修改绘制矩形代码,用变量代替数值参数。
例如:
glRectf(-0.5,-0.5,0.5,0 . 5);
改为:
程序前面加上变量声明和初始值,如:
float xl=-0.5,yl=-0.5,x2=0.5,y2=0.5;
注意语句的位置。
3)在程序中增加mykeyboard键盘子函数,并在如下代码中进行修改,实现键盘控制矩 形移动,运行程序自行测试。
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.设置窗口改变回调函数,使得矩形的长度和宽度等于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)和视区设置函数 glView-port(startx,starty,viewport_width,viewport_height)的设置有何规律?
答:是函数glOrtho造成的。该函数的用途是设置或修剪空间的范围。句法为:void glOrtho(GLdouble left,GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdoublefar);left表示最左边的坐标,right表示最右边的坐标,bottom表示最下边的坐标,top表示最上边的坐标,near表示最前边的坐标,far表示最后边的坐标。
此时,按下键盘W、A、D、S键进行交互移动,矩形的移动距离较之前有什么变化?要 保持以前的移动频率,程序应该如何修改?
答:变小,几乎不动。修改矩形对角坐标变量。
显示窗口改变前:
显示窗口改变后:
4.在矩形中间添加字符"Hello”,观察结果;然后将“Hello”字符改为自己名字的拼音 或英文名字。如下图所示。
提示:在绘制矩形后添加如下代码。
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"
注意:运行程序,效果如上图所示。但是如果此时按下键盘W、A、D、S键 进行交互移动,程序会发生什么变化?要保持矩形白色、字符红色,程序应该如何修改?
答:文字与字符一起移动。矩形和文字定义不同的颜色
如果字符颜色设置语句glColor3f( 1,0,0)放在定位光标语句glRasterPos2i((xl1+x2)/2,(y1+y2)/2)之后,运行又会发生什么变化?请读者自己总结设置字符颜色语句的顺序规律。
答:字符被遮挡,只有一个矩形。字符颜色设置需在定位光标语句之前。
5.参照教材按照自己的构思画二维平面图形,将上面的矩形替换成自己构思的二维平面 图形实现交互功能,注意顶点的顺序,并在画面上标注自己的姓名。
代码:
#include "stdafx.h"
#include "Shiyan3.h"
#include <windows.h>
#include <gl/glut.h>
float x1=100,y1=100,x2=200,y2=200;
void display(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //设置清屏颜色
glClear(GL_COLOR_BUFFER_BIT); //刷新颜色缓存区
glRectf(x1, y1, x2, y2); //矩形
glColor3f(1.0f, 1.0f, 1.0f);
glColor3f(1,0,0);
glRasterPos2i((x1+x2)/2,(y1+y2)/2); //定位当前光标
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'X'); //写字符"X"
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'X'); //写字符"X"
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, 'X'); //写字符"X"
glFlush(); //用于刷新命令队列和缓存区,使所有尚未被执行的OpenGL命令得到执行
}
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();
}
void myreshape(GLsizei w, GLsizei h) {
glViewport(0, 0, w, h); //设置视区位置
glMatrixMode(GL_PROJECTION); //设置投影变换模式
glLoadIdentity(); //调整单位矩阵,清空当前矩阵堆栈
gluOrtho2D(0, 300, 0, 300);
}
int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
char *argv[] = { "hello"," " };
int argc = 2;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(300,300);
int cx = glutGet(GLUT_SCREEN_WIDTH);
int cy = glutGet(GLUT_SCREEN_HEIGHT);
glutInitWindowPosition((cx-500)/2,(cy-500)/2);
glutCreateWindow("hello");
glutDisplayFunc(display);
glutKeyboardFunc(mykeyboard);
glutReshapeFunc (myreshape);
glutMainLoop();
return 0;
}
实验结果:
三、思考题
按下列步骤操作,并分析裁剪窗口、视区和显示窗口的关系。
1 )修改视区大小为原来的一半,如图所示。
2)修改裁剪窗口的大小为原来的一半;视区保持不变,如图所示。
参考函数:
・裁剪窗口设置函数:
gluOrtho2D (xwmin, xwmax, ywmin, ywmax) ; //xwmin xwmax、ywmin、ywmax 为 裁剪窗 口在世界坐标系的位置,分别为x最小、x最大、y最小、y最大
•视区设置函数:
glViewport (startx, starty, viewport_width, viewport_height) ;//绘图区在显示窗 口 中的 位置, 以屏幕坐标系为参考,startx、starty. viewport_widthviewport_height分别为绘图 区在显示窗口 的起点位置,以及绘图区的宽度和高度
3)修改以上程序使得按数字1键实现矩形用W、S、A、D键控制上、下、左、右移动, 按2键显示自己构思的其他2D图形(三角形、点或多边形等),用W、S、A、D键控制上、下、 左、右移动。
代码修改:
void mykeyboard(unsigned char key, int x, int y) {
switch (key) {
case 'W':
case 'w': //矩形对角坐标变量修改使得矩形上移
y1 += 1; y2 += 1;
break;
case 'S':
case 's': //矩形对角坐标变量修改使得矩形下移
y1 -= 1;y2 -= 1;
break;
case 'A':
case 'a': //矩形对角坐标变量修改使得矩形左移
x1 -= 1; x2 -= 1;
break;
case 'D':
case 'd': //矩形对角坐标变量修改使得矩形右移
x1 += 1; x2 += 1;
break;
case '1': //显示窗口改变
w1 = 300; h1 = 300;
break;
case '2': //显示窗口改变
w1 = 150; h1 = 150;
break;
}
//参数修改后调用重画函数,屏幕图形将发生改变
glutPostRedisplay();
}
在这里插入图片描述