一、 实验目的
- 掌握OpenGL的闲置函数
- 掌握OpenGL的时间函数
- 掌握OpenGL的简单动画功能
- 了解OpenGL裁剪窗口、视区、显示窗口的概念和它们之间的关系
- 进一步掌握OpenGL基本图元的绘制
二、 实验环境
操作系统:Windows 10 1909版本 64位
语言开发环境:Microsoft Visual Studio 2017
程序框架:Win32 桌面应用程序。
三、 实验要求与内容
实验步骤:
-
闲置函数的使用与简单动画
- 旋转的六边形如图。
观察到六边形按照程序视窗中心点逆时针旋转,要更改旋转速度,可通过更改myidle()闲置函数的属性值theta大小实现。
2) 添加多边形模式设置与线宽设置观看效果
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glLineWidth(2.0);
观察到旋转的多边形变成空心线框模式。
回到多边形填充模式修改代码:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- 在图形中增加字符“Hello”,代码如下
glColor3f(1, 0, 0);
glRasterPos2i(3, 2);
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, 'H');
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, 'e');
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, 'l');
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, 'l');
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, 'o');
观察到“Hello”字符串在设定的坐标点定位显示
- 变色技术。
设置全局变量int k = 0;
在myidle函数添加代码
if (k == 1) {
glColor3f(1, 0, 0);
k = 0;
}
else {
glColor3f(1, 1, 0);
k = 1;
}
观察到旋转的六边形图案颜色红黄闪烁。
- 修改代码,使六边形保持静止,以六边形中心为起点直线,终点为六边形某一顶点,使直线绕中心点旋转
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor3f(1, 1, 0);
glBegin(GL_POLYGON);
for (int i = 0; i < n; i++) { //绘制正六边形
glVertex2f(R*cos(theta + i * 2 * PI / n), R*sin(theta + i * 2 * PI / n));
}
glEnd();
glBegin(GL_LINES);
glColor3f(1, 1, 1);
glVertex2f(0, 0);
glVertex2f(R*cos(theta_line + 2 * PI / n), R*sin(theta_line + 2 * PI / n));
glEnd();
glutSwapBuffers();
效果如图:观察到六边形静止,直线单独旋转
思考:要使直线保持与及其时钟秒针拍温和,可在myidle函数中设置Sleep(1000)延时一秒,并设置theta=+= 6*PI/180; 使得每秒转过6°,一分钟转一周。
- 时间函数的使用和简单动画。
- 在主程序中:glutTimerFunc(1000, mytime, 10); 注册闲置回调函数,每隔1000ms调用一次mytime函数
- 编写mytime(t)函数:
}
void mytime(int t) {
theta += 6*PI/180;
if (theta_line >= 2 * PI) theta_line -= 2 * PI;
glutPostRedisplay(); //重绘函数
glutTimerFunc(1000, mytime, 10); //回调函数,1000ms后回调自身
}
观察到时间函数的作用效果,即每隔1000ms变换一次图形,使直线旋转theta度。
3.简单时钟设计
1) 在程序头部定义系统时间变量、时分秒变量
SYSTEMTIME timeNow; //系统时间变量
float hh, mm, ss;
2)定义PI变量
#define PI 3.1415926
3)引入数学文件、时间头文件
#include<cmath>
#include<ctime>
4)在初始化函数中获取系统时间,分别获取时分秒数据。
void init()
{
GetLocalTime(&timeNow); //获取系统时间
hh = timeNow.wHour;
mm = timeNow.wMinute;
ss = timeNow.wSecond;
}
5)绘制函数display()中计算时、分、秒,确定绘制时分秒针的起始点坐标。
//xc,yc为时针中心点坐标
//xs,ys为秒针终止点坐标
//xm,ym为分针终止点坐标
float xs, ys, xm, ym, xh, yh;
float xc = 0, yc = 0;
//Calculate
xs = xc + R * cos(PI / 2.0 - ss / 60 * 2 * PI);
ys = yc + R * sin(PI / 2.0 - ss / 60 * 2 * PI);
xm = xc + R * cos(PI / 2.0 - (mm + ss / 60.0) / 60.0*2.0*PI);
ym = yc + R * sin(PI / 2.0 - (mm + ss / 60.0) / 60.0*2.0*PI);
xh = xc + (R - 5)*cos(PI / 2.0 - (hh + (mm + ss / 60.0) / 60.0) / 12.0*2.0*PI);
yh = yc + (R - 5)*sin(PI / 2.0 - (hh + (mm + ss / 60.0) / 60.0) / 12.0*2.0*PI);
6)以直线方式绘制时、分、秒针。
glColor3f(1, 0, 0);
glBegin(GL_LINES);
glVertex2f(xc, yc);
glVertex2f(xs, ys);
glEnd();
glColor3f(1, 1, 0);
glBegin(GL_LINES);
glVertex2f(xc, yc);
glVertex2f(xm, ym);
glEnd();
glColor3f(0, 1, 1);
glBegin(GL_LINES);
glVertex2f(xc, yc);
glVertex2f(xh, yh);
glEnd();
7)绘制静止正六边形
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glLineWidth(2.0);
glColor3f(1, 1, 1);
glBegin(GL_POLYGON);
for (int i = 0; i < n; i++) { //绘制正六边形
glVertex2f(R*cos(theta + i * 2 * PI / n), R*sin(theta + i * 2 * PI / n));
}
glEnd();
8)在时间函数mytime(t)中设置重复获取系统当前时间。
void idletime(int t) {
GetLocalTime(&timeNow); //获取系统时间
hh = timeNow.wHour;
mm = timeNow.wMinute;
ss = timeNow.wSecond;
glutTimerFunc(1000, idletime, 10);
glutPostRedisplay(); //重绘函数
}
观察到简单时钟的显示,时分针秒针以时钟的形式呈现在视区中,并以当前的时间正确显示。
效果图
完整代码: