OpenGl之旅-—初识opengl

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

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

  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 }

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

什么是opengl

opengl是图形硬件的一种软件接口,这个接口包含的函数超过700多个,这些函数可以用于指定物体和操作,创建交互式的三维应用程序。opengl的设计目标就是作为流线型的、独立于硬件的接口,在许多不同硬件平台上实现。我们学习opengl目的就是去实现绘制自己想要的图形效果,而且他的一大特点就是与平台无关,与语言无关,比如我们基于android使用opengl绘制图形界面,那么绘制出的这些界面不仅可以再android操作系统上引用也完全可以移植到ios上去。

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

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

opengl是图形api他封装的接口有很多,我们无须去了解每一个函数接口的作用,只要了解主要的接口函数以及调用的逻辑,当我们特殊需要时就去看他的api文档来对应调用。

对于上面每个函数的作用我都标上了注释,所以这里不再叙述,这里着重说下双缓冲技术。

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

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

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

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

时间: 2024-12-12 12:51:08

OpenGl之旅-—初识opengl的相关文章

[OpenGL]环境搭建以及OpenGL初识

想往游戏行业发展的话,经常被提及到的就是OpenGL和DirectX,这两者听起来感觉是一门挺高深的技术,今天我也开始摸索学习OpenGL,那么OpenGL到底是什么?它和DirectX有什么区别和联系? OpenGL初识 OpenGL只是一套图形函数库 DirectX包含图形.声音.输入.网络等模块. 但就图形而论,DirectX的图形库性能不如OpenGL,OpenGL稳定,可以跨平台使用,DirectX只支持Windows平台,所以OpenGL还是有它的优势!OpenGL ES是OpenG

深入理解OpenGL拾取模式(OpenGL Picking)

深入理解OpenGL拾取模式(OpenGL Picking) 本文转自:http://blog.csdn.net/zhangci226/article/details/4749526 在用OpenGL进行图形编程的时候,通常要用鼠标进行交互操作,比如用鼠标点选择画面中的物体,我们称之为拾取(Picking),在网上看了很多OpenGL拾取的文章,但大多是只是介绍在OpenGL中如何拾取,如何利用OpenGL提供的一系列函数来完成拾取,最多再简单介绍下OpenGL的名字栈(Name stack),

OpenGL模板 Mac Cmake OpenGL(Glut) Template

自己经常使用的一些功能做一个模板,有灯光效果,你可以用鼠标放大,围绕所述旋转坐标系的原点 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHlhbmcxOTg5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > Main.cpp #include <GLUT/glut.h> #include <cstdlib> /*

OpenGL学习 Our First OpenGL Program

This shows you how to create the main window with the book’s application framework and how to render simple graphics into it. In shaders,we use #version430 core to tell the shader compiler that we intend to use version 4.3 of the shading language.The

[转]用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口

原文链接: 1.用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口 2.Windows MFC 两个OpenGL窗口显示与线程RC问题 原文地址:https://www.cnblogs.com/rainbow70626/p/8973440.html

Linux下安装QT和OpenGL后QT无法使用OpenGL的解决方法

我的系统为Ubuntu14.04,用apt-get安装了实现了OpenGl的mesa,QT则是用官网下载的run文件来安装的. 好了,现在两个都分别有了,所以要在qt下尝试写OpenGl代码. 之前试过在Vim粘贴代码然后编译,经测试成功的是包含以下一条编译选项的语句. 1 gcc a.c -o a 但是直接将代码粘贴到qt creator上点击运行,却出现多条报错信息,各条调用函数都提示找不到,即是qt还未能连接使用安装了的OpenGL库. 网上查了很多解决方案都是在qt项目的.pro文件中添

OpenGL(一) OpenGL管线 与 可编程管线流程

由于OpenGL是一个纯渲染核心,要写OpenGL程序,得先搭建一个外壳程序.不同平台下外壳程序的实现各有不同,这个系列的文章都在win32的平台上进行.具体实现,网上能找到很多,所以这不是本文的重点.本篇主要构建探讨 OpenGL管线 本身,具体说来,就是构建可编程管线. 主体流程 大体流程是: 在main函数中拉起外壳程序,初始化一些默认参数.例如双缓冲,32位颜色等. 创建GL上下文(HGLRC). 加载&设置OpenGL的相关参数 在帧循环中进行绘制 至于固定管线和可编程管线,主要区别在

vue之旅:初识vue

vue是一个mvvm框架(库),和angular类似比较容易上手.小巧 mvc:Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写 而vue是mvvm,m有了,v有了,vm相当于c vue指令  v-xxx 其实vue就是一片html代码配合上json,再new出来vue实例 适合:移动端项目,小巧 目前vue的发展势头很猛,github上的start数量已经超越angular 注意:与angular的共同点:不兼容低版本ie

OpenGL ES总结(一)OpenGL 初识

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/61615215 OpenGL是在图形图像中,非常优秀的渲染库,文中Demo下载地址:https://github.com/hejunlin2013/OpenGL31,看下今天的Agenda: OpenGL是什么? OpenGL主要功能是什么? OpenGL ES是什么? Android中如何描述OpenGL ES版本 映射坐标绘制对