实验二 OpenGL的简单动画

ZZU的学弟学妹们不要抄作业哦~(`Д´)

一、实验目的

1.掌握OpenGL的闲置函数。

2.掌握OpenGL的时间函数。

3.掌握OpenGL的简单动画功能。

4.了解OpengGL裁剪窗口、视区、显示窗口的概念和它们之间的关系。

5.进一步掌握OpenGL的基本图元的绘制。

、实验内容

1.闲置函数的使用与简单动画。

1) 旋转的六边形,如图2-1所示

阅读6.3.3节中旋转的六边形样本框架程序,分析程序的实现步骤运行该程序观察旋转动画效果。

思考: 如果要调整旋转速度,旋转更快或更慢,应该如何修改程序?

答:增大或减小旋转增量theta。

       实验二 OpenGL的简单动画_第1张图片 

图2-1  六边形绘制

  1. 线框六边形

在display 函数中添加多边形模式设置语句观看效果。

glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //线框模式

添加线宽语句观看效果

实验二 OpenGL的简单动画_第2张图片

 

glLineWidth(2.0); //设置线宽

重回多边形填充模式:

glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); //填充模式

图同2-1

3) 在图形中添加字符"Hello",观察结果;然后将"Hello"字符改为自己名字的拼音或英文名字。如图3-2所示。

 

提示:在图形中添加如下代码:

glColor3f(1,0,0);  //设置红色绘制颜色

glRasterPos2i(30,20);    //定位当前光标,起始字符位置

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"

 

实验二 OpenGL的简单动画_第3张图片

 

 

4) 变色技术举例:

在程序头部设置全部变量:

int k=0;

在myidle函数中添加代码:

if (k==1)

{

glColor3f(1,0,0) ;

k=0;

}

else

{

glColor3f(1,1,0) ;

k=1;

}

然后在绘制函数中屏蔽原来的绘制颜色,运行查看效果

效果就是:红色和黄色交替变化,很闪。

 

5) 六边形静止,直线单独旋转,如图2-2所示。

修改前面的程序,使得六边形保持静止,以六边形中心为起点画一条不同颜色的直线,终点为六边形某一顶点,使得直线不停绕中心点旋转。代码保存下来备用。思考:如果需要直线保持与机器时钟的秒针节拍吻合,应该如何修改?

答:1秒刷新一次。

提示:可用延时 Sleep()函数,如Sleep(1000)表示延时1秒,放在 myidle函数中

   实验二 OpenGL的简单动画_第4张图片          

图2-2  六边形和直线

 

2.时间函数的使用与简单动画。

将以上程序中的闲置函数替换为时间函数,

1)主程序中的glutIdleFunc(myidle);    //注册闲置回调函数   

改为:

glutTimerFunc(1000, mytime,10); //1000毫秒后调用时间函数 mytime

2)myidle()闲置回调函数改为时间函数 mytime(t)在程序顶部,函数声明语句也要相应更改:

void myidle();  

改为:

void mytime(int t);

3)在时间函数 mytime(int t)最后再添加:

glutTimerFunc(1000, mytime,10); //1000毫秒后调用时间函数 mytime

此处图同2-2

 

3.简单时钟的设计

1)在程序头部定义系统时间变量,时分秒变量:

SYSTEMTIME timeNow;

float hh,mm,ss;

2)在程序头部定义Π常量:

#define PI 3.1415926

3)在程序头部引入数学头文件、时间头文件:

#include "math.h"

#include "time.h"

4)在初始化函数中获取系统时间:

在主程序中顶部声明初始化子函数

void init();

在main函数中 添加子函数调用语句,可放在创建窗口之后:

init();

在main函数后面,添加初始化子函数,并在函数中添加获取系统时间语句:

void init()

{

    GetLocalTime(&timeNow);    //获取系统时间

    hh=timeNow.wHour;    //获取小时时间

mm=timeNow.wMinute;   //获取分钟时间

ss=timeNow.wSecond;      //获取秒时间

}

 

5)在绘制函数中计算时分秒,确定绘制时分秒针起始点坐标,例如

//xc,yc为时针中心点坐标

//xs,ys为秒针终止点坐标

//xm,ym针终止点坐标

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)闲置函数中 或 时间函数中重复获取系统时间

GetLocalTime(&timeNow);    //获取系统时间

hh=timeNow.wHour;    //获取小时时间

mm=timeNow.wMinute;   //获取分钟时间

ss=timeNow.wSecond;      //获取秒时间

实验二 OpenGL的简单动画_第5张图片

 

 

、参考函数和相关知识

1)void glutIdleFunc((*f) (void)) //注册闲置响应函数

2)void myidle() //闲置响应回调函数

{

      //当时间空闲时系统要做的事情

}

3)void glPolygonMode(GLenum face,GLenum mode)//多边形线框模型设置

4)void glutTimerFunc(unsigned int msecs, void (*Func)(int value), int value); //注册一个回调函数,当指定时间值到达后,由GLUT调用注册的函数一次

msecs是等待的时间,单位

Func是注册的函数它的参数value是指定的一个数值,用来传递到回调函数Func中

5)glutPostRedisplay();  //重画函数,相当于重新调用Display(),改编后的变量得以传给绘制函数

6)时钟相关知识

 

系统时间转换成角度技术

1)把系统时间取出后,分钟应考虑秒钟的影响,时钟应考虑分钟的影响例如,

mm=mm+ss/60

hh=hh+mm/60

2)角度坐标提示窗体角度坐标如图2-3,2-4所示,

 

实验二 OpenGL的简单动画_第6张图片实验二 OpenGL的简单动画_第7张图片

  图2-3 直线方向表示0度方向                                图2-4 直线方向表示90度方向

 

3)时分秒针角度计算

秒针:当ss=0时,秒针角度=90度=1/2*Pi弧度60秒转一圈 即1秒钟转  360/60=6度=Pi/30弧度

分针:当mm=0时,分针角度=90度=1/2*Pi弧度60分转一圈, 即1分钟转  360/60=6度=Pi/30弧度

时针:当hh=0时,时针角度=90度=1/2*Pi弧度12小时转一圈, 即1小时转  360/12=30度=Pi/6弧度/

 

时分秒针绘制技术

关键是获取时分秒针的终止点的坐标假设时针中心点(xc,yc),秒针,分针和时针长度分别为slength,mlength,hlength

秒针终止点:xc + slength * Cos(1/2*3.14 + ss* 3.14/ 30), yc + slength *.Sin(1/2*3.14 + ss *3.14 / 30)

分针终止点:xc + mlength *Cos(1/2*3.14 +mm* 3.14/ 30), yc + mlength *sin(1/2*3.14 + mm *3.14 / 30)

时针终止点:xc + hlength *cos(3/2*3.14 +hh* 3.14/ 6), yc + hlength *sin(3/2*3.14 + hh *3.14 /6)

 

四、完整代码

#include 
#include "math.h"
#include "time.h"
#include 
#include 
#include 
#define PI 3.1415926
int n = 6, R = 10;  //多边形变数,外接圆半径

float theta = 0.0;  //旋转初始角度值
SYSTEMTIME timeNow;
float hh, mm, ss;

void init();
void Keyboard(unsigned char key, int x, int y);
void Display(void);
void Reshape(int w, int h);
void mytime(int t);

int APIENTRY _tWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	char *argv[] = { "hello ", " " };
	int argc = 2; // must/should match the number of strings in argv

	glutInit(&argc, argv);  //初始化GLUT库;
	glutInitWindowSize(700, 700);  //设置显示窗口大小
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);  //设置显示模式;(注意双缓冲)
	glutCreateWindow("A Rotating Square"); // 创建显示窗口

	init();
	glutDisplayFunc(Display);  //注册显示回调函数
	glutReshapeFunc(Reshape);  //注册窗口改变回调函数
	glutTimerFunc(1000, mytime, 10); //1000毫秒后调用时间函数 mytime
	glutMainLoop();  //进入事件处理循环

	return 0;
}

void init()
{
	GetLocalTime(&timeNow);    //获取系统时间
	hh = timeNow.wHour;    //获取小时时间
	mm = timeNow.wMinute;   //获取分钟时间
	ss = timeNow.wSecond;      //获取秒时间
}

void Display(void)
{

	glClear(GL_COLOR_BUFFER_BIT);

	glColor3f(1, 1, 1); //设置白色绘图颜色
	glBegin(GL_POLYGON);  //开始绘制六边形
	for (int i = 0; i < n; i++)
		glVertex2f(R*cos(i * 2 * PI / n), R*sin(i * 2 * PI / n));
	glEnd();

	//xc,yc为起点坐标
	//xh,yh为时针中心点坐标
	//xs,ys为秒针终止点坐标 
	//xm,ym为分针终止点坐标
	int xs, ys, xm, ym, xc=0, yc=0,xh,yh;
	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);
	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();

	/*glColor3f(0, 0, 0); //设置灰色绘图颜色
	glBegin(GL_LINES);  //开始绘制线
	glVertex2f(0, 0);
	glVertex2f(R*cos(theta + 2 * PI / n), R*sin(theta + 2 * PI / n));
	glEnd();*/

	glutSwapBuffers();   //双缓冲的刷新模式;
}

void mytime(int t)
{
	GetLocalTime(&timeNow);    //获取系统时间
	hh = timeNow.wHour;    //获取小时时间
	mm = timeNow.wMinute;   //获取分钟时间
	ss = timeNow.wSecond;      //获取秒时间
	theta += 0.01;
	if (theta >= 2 * PI) theta -= 2 * PI;
	glutTimerFunc(1000, mytime, 10); //1000毫秒后调用时间函数 mytime
	glutPostRedisplay();  //重画,相当于重新调用Display(),改编后的变量得以传给绘制函数
}

void Reshape(GLsizei w, GLsizei h)
{
	glMatrixMode(GL_PROJECTION);  //投影矩阵模式
	glLoadIdentity();  //矩阵堆栈清空
	gluOrtho2D(-1.5*R*w / h, 1.5*R*w / h, -1.5*R, 1.5*R);  //设置裁剪窗口大小
	glViewport(0, 0, w, h); //设置视区大小
	glMatrixMode(GL_MODELVIEW);  //模型矩阵模式 
}

 

你可能感兴趣的:(OpenGL)