OpenGl之旅-—初识opengl

昨天学习了如何使用codeblocks来编译运行一个opengl的项目。在建立一个新的opengl项目时他默认已经写了一个示例,今天咱们就上面的例子进行下代码的剖析,以此来敲开opengl的神秘大门。android

先把代码贴上来(在此我为每一个函数的做用都写上了详细的注释):ios

  1 /*
  2  * 该代码是由一位叫Nigel Stewart的写于2003年11月,例子的目的是测试以glut实现球体,圆椎,圆环的纺纱线框和平滑阴影的形状。
  3  * 数量的几何栈和切割可使用热键“-”或“+”调整。
  4  */
  5 
  6 #ifdef __APPLE__  //若是程序中没有定义了 __APPLE__ 这个符号则加载glut,#ifdef 是预编译命令
  7 #include <GLUT/glut.h>
  8 #else
  9 #include <GL/glut.h>
 10 #endif
 11 
 12 #include <stdlib.h>//standard library标准库头文件,stdlib 头文件里包含了C、C++语言的最经常使用的系统函数,该文件包含了的C语言标准库函数的定义
 13 
 14 static int slices = 16;
 15 static int stacks = 16;
 16 
 17 /* GLUT callback Handlers */
 18 
 19 static void resize(int width, int height)
 20 {
 21     const float ar = (float) width / (float) height;
 22 
 23     glViewport(0, 0, width, height);//占据打开窗口的整个像素矩形
 24     glMatrixMode(GL_PROJECTION);//指定当前矩阵为投影矩阵
 25     glLoadIdentity();//该函数的功能是重置当前指定的矩阵为单位矩阵
 26     glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);//建立一个透视投影的矩阵,而且用这个矩阵乘以当前矩阵
 27 
 28     glMatrixMode(GL_MODELVIEW);
 29     glLoadIdentity() ;
 30 }
 31 /*
 32 *绘制
 33 */
 34 static void display(void)
 35 {
 36     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;//返回两次调用glutGet(GLUT_ELAPSED_TIME)的时间间隔,单位为毫秒
 37     const double a = t*90.0;
 38 
 39     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色缓冲以及深度缓冲
 40     glColor3d(1,0,0);//设置红色为当前颜色
 41 
 42     glPushMatrix();//glPushMatrix(),glPopMatrix()这两个函数是搭配使用的
 43         glTranslated(-2.4,1.2,-6);//定义一个平移矩阵,该矩阵与当前矩阵相乘,使后续的图形进行平移变换。
 44         glRotated(60,1,0,0);//旋转
 45         glRotated(a,0,0,1);
 46         glutSolidSphere(1,slices,stacks);//用于渲染一个丝状球体
 47     glPopMatrix();
 48 
 49     glPushMatrix();
 50         glTranslated(0,1.2,-6);
 51         glRotated(60,1,0,0);
 52         glRotated(a,0,0,1);
 53         glutSolidCone(1,1,slices,stacks);//用于渲染一个丝状圆锥
 54     glPopMatrix();
 55 
 56     glPushMatrix();
 57         glTranslated(2.4,1.2,-6);
 58         glRotated(60,1,0,0);
 59         glRotated(a,0,0,1);
 60         glutSolidTorus(0.2,0.8,slices,stacks);//用于渲染一个丝状圆环
 61     glPopMatrix();
 62 
 63     glPushMatrix();
 64         glTranslated(-2.4,-1.2,-6);
 65         glRotated(60,1,0,0);
 66         glRotated(a,0,0,1);
 67         glutWireSphere(1,slices,stacks);//用于渲染一个实体球体
 68     glPopMatrix();
 69 
 70     glPushMatrix();
 71         glTranslated(0,-1.2,-6);
 72         glRotated(60,1,0,0);
 73         glRotated(a,0,0,1);
 74         glutWireCone(1,1,slices,stacks);//用于渲染一个实体圆锥
 75     glPopMatrix();
 76 
 77     glPushMatrix();
 78         glTranslated(2.4,-1.2,-6);
 79         glRotated(60,1,0,0);
 80         glRotated(a,0,0,1);
 81         glutWireTorus(0.2,0.8,slices,stacks);//用于渲染一个实体圆环
 82     glPopMatrix();
 83 
 84     glutSwapBuffers();//由于使用的是双缓存GLUT_DOUBLE,因此这里必需要交换缓存才会显示
 85 }
 86 /*
 87 *设置对应按键响应的不一样事件
 88 */
 89 static void key(unsigned char key, int x, int y)
 90 {
 91     switch (key)
 92     {
 93         case 27 :
 94         case 'q':
 95             exit(0);
 96             break;
 97 
 98         case '+':
 99             slices++;
100             stacks++;
101             break;
102 
103         case '-':
104             if (slices>3 && stacks>3)
105             {
106                 slices--;
107                 stacks--;
108             }
109             break;
110     }
111 
112     glutPostRedisplay();//标记当前窗口须要从新绘制。
113 }
114 
115 static void idle(void)
116 {
117     glutPostRedisplay();
118 }
119 
120 const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
121 const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
122 const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
123 const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
124 
125 const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
126 const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
127 const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
128 const GLfloat high_shininess[] = { 100.0f };
129 
130 /* Program entry point */
131 
132 int main(int argc, char *argv[])
133 {
134     glutInit(&argc, argv); //调用glut函数前,要初始化glut,即调用glutInit()
135     glutInitWindowSize(640,480);//预约义窗口大小
136     glutInitWindowPosition(10,10);//设置窗口左上方位置
137     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);//指定了是使用RGBA模式仍是双缓冲或者是深度缓冲
138 
139     glutCreateWindow("GLUT Shapes");//建立一个支持opengl渲染环境的窗口
140 
141     glutReshapeFunc(resize);//注册一个resize函数,表示当窗口发生变化时应采起什么行动,在这个里面resize根据缩放后的窗口从新设置
142     glutDisplayFunc(display);//注册一个绘图函数display,这样操做系统在必要时刻就会对窗体进行从新绘制操做。
143     glutKeyboardFunc(key);//注册一个按键消息处理函数,这个函数是告诉窗口系统,哪个函数将会被调用来处理普通按键消息的。
144     glutIdleFunc(idle);//注册一个回调函数,若是不存在其余还没有完成的事件(例如:当事件循环处于空闲的时候),就执行这个函数。
145 
146     glClearColor(1,1,1,1);//设置窗口背景色
147     glEnable(GL_CULL_FACE);//用于启动各类功能其功能由参数决定,GL_CULL_FACE启用隐藏图形材料的面。 开启剔除操做效果。
148     glCullFace(GL_BACK);//glCullFace()参数包括GL_FRONT和GL_BACK,两个参数分别表示禁用多边形正面或者背面上的光照、阴影和颜色计算及操做,消除没必要要的渲染计算。
149 
150     glEnable(GL_DEPTH_TEST);//启用深度测试
151     glDepthFunc(GL_LESS);//指定深度缓冲比较值,GL_LESS,若是输入的深度值小于参考值,则经过。
152 
153     glEnable(GL_LIGHT0);//开启0号光源
154     glEnable(GL_NORMALIZE);//在进行光照计算以前自动单位化法向量。
155     glEnable(GL_COLOR_MATERIAL);//使用颜色材质
156     glEnable(GL_LIGHTING);//开启灯光
157 
158     glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);//设置0号光源的环境强度
159     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);//光源的漫反射
160     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);//光源镜面反射
161     glLightfv(GL_LIGHT0, GL_POSITION, light_position);//指定光源位置
162 
163     glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);//材质属性中的发射光
164     glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);//材质属性中的散射光
165     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);//材质属性中的镜面反射光
166     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);//材质属性中的光强度
167 
168     glutMainLoop();//这里让整个绘图循环进行,至关于死循环
169 
170     return EXIT_SUCCESS;
171 }
View Code

结合注释大概浏览下代码,从上面的代码中咱们能够看出OpenGL中的函数都是由gl开头的,相似的,opengl还定义了一些之前缀GL_开头的常量,全部单词都使用大写形式,并如下划线分隔。还有基本都是调用glut里面的函数接口,而后传入本身的参数去改变状态,获得本身想要的结果的。这就是由于opengl自己就是一个强大的图形api,先来理清opengl的概念。编程

什么是openglapi

opengl是图形硬件的一种软件接口,这个接口包含的函数超过700多个,这些函数能够用于指定物体和操做,建立交互式的三维应用程序。opengl的设计目标就是做为流线型的、独立于硬件的接口,在许多不一样硬件平台上实现。咱们学习opengl目的就是去实现绘制本身想要的图形效果,并且他的一大特色就是与平台无关,与语言无关,好比咱们基于android使用opengl绘制图形界面,那么绘制出的这些界面不只能够再android操做系统上引用也彻底能够移植到ios上去。缓存

回到上面的例子,看懂上面代码很简单,头文件加载什么的就很少说了,看注释。ide

咱们直接来到main函数总体观看下main函数,没有任何逻辑代码,全是调用glut的接口函数。它的基本结构很是简单就是初始化一些状态(这些状态用于控制opengl的渲染方式),并指定须要渲染的物体。还有须要注意的是,opengl跟经常使用计算机语言不同,若是你要自定义写一个函数的话必须先引用glut里的注册函数注册一遍,才能行之有效,由于opengl响应事件的触发是分开的,因此会调用不一样函数去初始化一遍,好比上面代码中注册的函数:函数

opengl是图形api他封装的接口有不少,咱们无须去了解每个函数接口的做用,只要了解经常使用的接口函数以及调用的逻辑,当咱们特殊须要时就去看他的api文档来对应调用。oop

对于上面每一个函数的做用我都标上了注释,因此这里再也不叙述,这里着重说下双缓冲技术。学习

咱们知道在现实生活中的动画都是咱们把关键帧画完而后再进行播放,可是在计算机中不一样,计算机是画完一张用一张,当要用另外一张的时候再画,可是当咱们要进行十分复杂的画图操做的时候,可能就会有明显的闪烁或者卡顿现象了,解决这个问题就要用到双缓冲技术。 测试

所谓的双缓冲技术,其实就是使用两个缓冲区,前台缓冲和后台缓冲。前台缓冲是咱们看到的,后台缓冲则是在内存中的。每次的画图操做都是再后台缓冲中进行,而后复制到屏幕中。这样就不会由于频繁刷新而出现闪烁了。 使用双缓冲技术也会当后台缓冲尚未画好的时候,这时前台会停留在当前画面直到后台绘制完成才进行切换。

在OpenGL中实现双缓冲的一种方式就是调用glutSwapBuffers()。

从代码中还会发现涉及到不少线性代数相关的东西,因此还需学好线性代数,推荐学习书籍《线性代数及其应用》,《opengl编程指南》

相关文章
相关标签/搜索