您的位置:首页 > 运维架构

OpenGL入门示例2——黑色背景绘制绿色旋转矩形

2014-03-17 23:07 239 查看
#include<GL/glut.h>
#include<windows.h>						//For NULL AND Sleep()

static GLfloat spin=0.0;				//定义旋转量

void init(void)
{
glClearColor(0.0,0.0,0.0,0.0);		//指定清除颜色(黑色),即背景颜色
glShadeModel(GL_FLAT);				//设置着色模式,采用恒定着色(即GL_FLAT),使用图元中某个顶点的颜色来渲染整个图元,详见参考一
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);		//清除所有的像素

glPushMatrix();						//压入当前矩阵堆栈,详见参考二
glRotatef(spin,0.0,0.0,1.0);		//绕各个坐标轴的旋转(z轴)
glColor3f(0.0,1.0,0.0);				//绘制颜色(绿色),函数名glColor3f中的3代表三个参数,f代表参数类型为GLfloat型,下同
glRectf(-25.0,-25.0,25.0,25.0);		//画矩形,四参数分别表示了位于对角线上两点横、纵坐标
glPopMatrix();						//弹出栈顶的矩阵,并将其删除。这样,原来从栈顶数位于第二位的矩阵将成为栈顶矩阵。当前堆栈由函数glMatrixMode()指定。如果矩阵堆栈中只有一个矩阵,调用函数将导致错误。

glutSwapBuffers();					//glutSwapBuffers函数是OpenGL中GLUT工具包中用于实现双缓冲技术的一个重要函数。该函数的功能是交换两个缓冲区指针。 详见参考三
}

void spinDisplay(void)					//旋转方法,每次旋转2度
{
spin+=2.0;
if(spin>360.0)
{
spin-=360.0;
}
glutPostRedisplay();				// 标记当前窗口需要重新绘制。通过glutMainLoop下一次循环时,窗口显示将被回调以重新显示窗口的正常面板。多次调用glutPostRedisplay,在下一个显示回调只产生单一的重新显示回调。
Sleep(10);							//由于旋转的太快了,故调用Windows.h中的Sleep()函数降低其旋转速度,以达到期望效果
}

void reshape(int w,int h)				//重绘回调函数
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);		//GLsizei和GLint为32位整数类型,相当于C中的int
glMatrixMode(GL_PROJECTION);				//指定哪一个矩阵是当前矩阵(GL_PROJECTION,对投影矩阵应用随后的矩阵操作),详见参考四
glLoadIdentity();							//将当前的用户坐标系的原点移到了屏幕中心:类似于一个复位操作

glOrtho(-50.0,50.0,-50.0,50.0,-1.0,1.0);	//将当前的可视空间设置为正投影空间,这个函数描述了一个平行修剪空间,意味着离观察者较远的对象看上去不会变小
glMatrixMode(GL_MODELVIEW);					//GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作
glLoadIdentity();							//同上,复位作用
}

void mouse(int button,int state,int x,int y)	//鼠标响应事件定义
{
switch(button)
{
case GLUT_LEFT_BUTTON:
if(state==GLUT_DOWN)					//若按下鼠标左键,则开始旋转
{
glutIdleFunc(spinDisplay);			//设置全局的回调函数,当没有窗口事件到达时,GLUT程序功能可以执行后台处理任务或连续动画。如果启用,这个idle function会被不断调用,直到有窗口事件发生。
}
break;
case GLUT_RIGHT_BUTTON:						//若按下鼠标右键,则停止旋转
if(state==GLUT_DOWN)
{
glutIdleFunc(NULL);					//将全局回调函数设为NULL
}
break;
default:
break;
}
}

int main(int argc,char** argv)						//注意参数
{
glutInit(&argc,argv);							//初始化GLUT并处理命令行参数
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);		//双缓存,RGBA模式
glutInitWindowSize(250,250);					//指定窗口大小(像素)
glutInitWindowPosition(100,100);				//指定窗口左上角在屏幕上的位置
glutCreateWindow(argv[0]);						//使用OpenGL场景创建一个窗口,参数为窗口名称
init();											//调用初始化函数
glutDisplayFunc(display);						//注册显示回调函数,每当GLUT认为需要重绘窗口时,都会执行该函数,故应将重绘场景所需调用的函数都放到显示回调函数中。
glutReshapeFunc(reshape);						//注册重绘回调函数
glutMouseFunc(mouse);							//注册鼠标回调函数
glutMainLoop();									//进入主循环并处理事件,此时创建的所有窗口都会显示出来,被渲染到这些窗口中的内容也将显示出来,程序开始处理事件,注册的显示回调函数被触发

return 0;										//ANSI C要求函数main()返回一个int值
}

/*

1.参考一:
void glShadeModel ( GLenum mode);
OpenGL1.0提供的接口。作用:设置着色模式。
参数mode可以是GL_SMOOTH(默认值)或GL_FLAT。采用恒定着色时(即GL_FLAT),使用图元中某个顶点的颜色来渲染整个图元。
在使用光滑着色时(即GL_SMOOTH),独立的处理图元中各个顶点的颜色。对于线段图元,线段上各点的颜色将根据两个顶点的颜色通过插值得到。对于多边形图元,多边形内部区域的颜色将根据所有顶点的颜色插值得到。

2.参考二:
glPushMatrix 函数将当前矩阵堆栈推送,通过一个,复制当前矩阵。 这就是后 glPushMatrix 的调用堆栈的顶部矩阵是它下面的相同的。

原理讲解

终于明白为什么使用glPushMatrix()和glPopMatrix()的原因了。将本次需要执行的缩放、平移等操作放在glPushMatrix和glPopMatrix之间。glPushMatrix()和glPopMatrix()的配对使用可以消除上一次的变换对本次变换的影响。使本次变换是以世界坐标系的原点为参考点进行。下面对上述结论做进一步的解释:
1)OpenGL中的modelview矩阵变换是一个马尔科夫过程:上一次的变换结果对本次变换有影响,上次modelview变换后物体在世界坐标系下的位置是本次modelview变换的起点。默认时本次变换和上次变换不独立。
2)OpenGL物体建模实际上是分两步走的。第一步,在世界坐标系的原点位置绘制出该物体;第二步,通过modelview变换矩阵对世界坐标系原点处的物体进行仿射变换,将该物体移动到世界坐标系的目标位置处。
3)将modelview变换放在glPushMatrix和glPopMatrix之间可以使本次变换和上次变换独立。
4)凡是使用glPushMatrix()和glPopMatrix()的程序一般可以判定是采用世界坐标系建模。既世界坐标系固定,modelview矩阵移动物体。
一般说来,矩阵堆栈常用于构造具有继承性的模型,即由一些简单目标构成的复杂模型。例如,一辆自行车就是由两个轮子、一个三角架及其它一些零部件构成的。它的继承性表现在当自行车往前走时,首先是前轮旋转,然后整个车身向前平移,接着是后轮旋转,然后整个车身向前平移,如此进行下去,这样自行车就往前走了。将上述模型的构造过程放在glPushMatrix和glPopMatrix之间,则本次汽车在世界坐标系中的位置不是基于上一次汽车的位置而给出的(以前一次的位置为参考),而是直接给出的以世界下的坐标(以世界坐标系的原点为参考)。整个过程是符合人的思维过程的,由于每次建模都是以单位阵为变换起点,故便于采用统一的实现方式进行处理。
矩阵堆栈对复杂模型运动过程中的多个变换操作之间的联系与独立十分有利。因为所有矩阵操作函数如glLoadMatrix()、glMultMatrix()、glLoadIdentity()等只处理当前矩阵或堆栈顶部矩阵,这样堆栈中下面的其它矩阵就不受影响。堆栈操作函数有以下两个:
void glPushMatrix(void);
void glPopMatrix(void);
第一个函数表示将所有矩阵依次压入堆栈中,顶部矩阵是第二个矩阵的备份;压入的矩阵数不能太多,否则出错。第二个函数表示弹出堆栈顶部的矩阵,令原第二个矩阵成为顶部矩阵,接受当前操作,故原顶部矩阵被破坏;当堆栈中仅存一个矩阵时,不能进行弹出操作,否则出错。由此看出,矩阵堆栈操作与压入矩阵的顺序刚好相反,编程时要特别注意矩阵操作的顺序。为了更好地理解这两个函数,我们可以形象地认为glPushMatrix()就是“记住自己在哪”,glPopMatrix()就是“返回自己原来所在地”。

3.参考三:
glutSwapBuffers函数是OpenGL中GLUT工具包中用于实现双缓冲技术的一个重要函数。该函数的功能是交换两个缓冲区指针。
通常, 我们所看到的窗体、文字、图像,从根本上来说都是“画”出来的。比如,制作一个简单的五子棋, 我们可能先要绘制棋盘,然后绘制棋子,我们可能还要绘制一些提示信息。虽然这些绘制操作有一定的先后顺序,通常情况下,操作系统的这些绘制速度非常的快,使人眼误认为这些绘制操作是同时完成的。
但当我们进行复杂的绘图操作时,画面便可能有明显的闪烁。解决这个问题的关键在于使绘制的东西同时出现在屏幕上。所谓双缓冲技术, 是指使用两个缓冲区: 前台缓冲和后台缓冲。前台缓冲即我们看到的屏幕,后台缓冲则在内存当中,对我们来说是不可见的。每次的所有绘图操作都在后台缓冲中进行, 当绘制完成时, 把绘制的最终结果复制到屏幕上, 这样, 我们看到所有GDI元素同时出现在屏幕上,从而解决了频繁刷新导致的画面闪烁问题。
在OpenGL中实现双缓冲技术的一种简单方法:
1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);。这里将我们惯用的GLUT_SINGLE替换为GLUT_DOUBLE,意为要使用双缓冲而非单缓冲。
2. 调用glutDisplayFunc(display)注册回调函数时, 在回调函数中所有绘制操作完成后调用glutSwapBuffers()交换两个缓冲区指针。
3. 调用glutIdleFunc注册一个空闲时绘制操作函数, 注册的这个函数再调用display函数。

4.参考四:
glMatrixMode() - 指定哪一个矩阵是当前矩阵
mode 指定哪一个矩阵堆栈是下一个矩阵操作的目标,可选值: GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE.
glMatrixMode设置当前矩阵模式:
GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作.
GL_PROJECTION,对投影矩阵应用随后的矩阵操作.
GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作.
与glLoadIdentity()一同使用
glLoadIdentity():该函数的功能是重置当前指定的矩阵为单位矩阵。
在glLoadIdentity()之后我们为场景设置了透视图。glMatrixMode(GL_MODELVIEW)设置当前矩阵为模型视图矩阵,模型视图矩阵储存了有关物体的信息。
*/

运行结果:





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息