Bootstrap

实验3—OpenGL的键盘交互绘制

一、实验目的

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();
}

在这里插入图片描述

;