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

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

 /*
* 该代码是由一位叫Nigel Stewart的写于2003年11月,例子的目的是测试以glut实现球体,圆椎,圆环的纺纱线框和平滑阴影的形状。
* 数量的几何栈和切割可以使用热键“-”或“+”调整。
*/ #ifdef __APPLE__ //如果程序中没有定义了 __APPLE__ 这个符号则加载glut,#ifdef 是预编译命令
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif #include <stdlib.h>//standard library标准库头文件,stdlib 头文件里包含了C、C++语言的最常用的系统函数,该文件包含了的C语言标准库函数的定义 static int slices = ;
static int stacks = ; /* GLUT callback Handlers */ static void resize(int width, int height)
{
const float ar = (float) width / (float) height; glViewport(, , width, height);//占据打开窗口的整个像素矩形
glMatrixMode(GL_PROJECTION);//指定当前矩阵为投影矩阵
glLoadIdentity();//该函数的功能是重置当前指定的矩阵为单位矩阵
glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);//创建一个透视投影的矩阵,并且用这个矩阵乘以当前矩阵 glMatrixMode(GL_MODELVIEW);
glLoadIdentity() ;
}
/*
*绘制
*/
static void display(void)
{
const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;//返回两次调用glutGet(GLUT_ELAPSED_TIME)的时间间隔,单位为毫秒
const double a = t*90.0; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色缓冲以及深度缓冲
glColor3d(,,);//设置红色为当前颜色 glPushMatrix();//glPushMatrix(),glPopMatrix()这两个函数是搭配使用的
glTranslated(-2.4,1.2,-);//定义一个平移矩阵,该矩阵与当前矩阵相乘,使后续的图形进行平移变换。
glRotated(,,,);//旋转
glRotated(a,,,);
glutSolidSphere(,slices,stacks);//用于渲染一个丝状球体
glPopMatrix(); glPushMatrix();
glTranslated(,1.2,-);
glRotated(,,,);
glRotated(a,,,);
glutSolidCone(,,slices,stacks);//用于渲染一个丝状圆锥
glPopMatrix(); glPushMatrix();
glTranslated(2.4,1.2,-);
glRotated(,,,);
glRotated(a,,,);
glutSolidTorus(0.2,0.8,slices,stacks);//用于渲染一个丝状圆环
glPopMatrix(); glPushMatrix();
glTranslated(-2.4,-1.2,-);
glRotated(,,,);
glRotated(a,,,);
glutWireSphere(,slices,stacks);//用于渲染一个实体球体
glPopMatrix(); glPushMatrix();
glTranslated(,-1.2,-);
glRotated(,,,);
glRotated(a,,,);
glutWireCone(,,slices,stacks);//用于渲染一个实体圆锥
glPopMatrix(); glPushMatrix();
glTranslated(2.4,-1.2,-);
glRotated(,,,);
glRotated(a,,,);
glutWireTorus(0.2,0.8,slices,stacks);//用于渲染一个实体圆环
glPopMatrix(); glutSwapBuffers();//因为使用的是双缓存GLUT_DOUBLE,所以这里必须要交换缓存才会显示
}
/*
*设置对应按键响应的不同事件
*/
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case :
case 'q':
exit();
break; case '+':
slices++;
stacks++;
break; case '-':
if (slices> && stacks>)
{
slices--;
stacks--;
}
break;
} glutPostRedisplay();//标记当前窗口需要重新绘制。
} static void idle(void)
{
glutPostRedisplay();
} const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f }; const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f };
const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat high_shininess[] = { 100.0f }; /* Program entry point */ int main(int argc, char *argv[])
{
glutInit(&argc, argv); //调用glut函数前,要初始化glut,即调用glutInit()
glutInitWindowSize(,);//预定义窗口大小
glutInitWindowPosition(,);//设置窗口左上方位置
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);//指定了是使用RGBA模式还是双缓冲或者是深度缓冲 glutCreateWindow("GLUT Shapes");//创建一个支持opengl渲染环境的窗口 glutReshapeFunc(resize);//注册一个resize函数,表示当窗口发生变化时应采取什么行动,在这个里面resize根据缩放后的窗口重新设置
glutDisplayFunc(display);//注册一个绘图函数display,这样操作系统在必要时刻就会对窗体进行重新绘制操作。
glutKeyboardFunc(key);//注册一个按键消息处理函数,这个函数是告诉窗口系统,哪一个函数将会被调用来处理普通按键消息的。
glutIdleFunc(idle);//注册一个回调函数,如果不存在其他尚未完成的事件(例如:当事件循环处于空闲的时候),就执行这个函数。 glClearColor(,,,);//设置窗口背景色
glEnable(GL_CULL_FACE);//用于启动各种功能其功能由参数决定,GL_CULL_FACE启用隐藏图形材料的面。 开启剔除操作效果。
glCullFace(GL_BACK);//glCullFace()参数包括GL_FRONT和GL_BACK,两个参数分别表示禁用多边形正面或者背面上的光照、阴影和颜色计算及操作,消除不必要的渲染计算。 glEnable(GL_DEPTH_TEST);//启用深度测试
glDepthFunc(GL_LESS);//指定深度缓冲比较值,GL_LESS,如果输入的深度值小于参考值,则通过。 glEnable(GL_LIGHT0);//开启0号光源
glEnable(GL_NORMALIZE);//在进行光照计算之前自动单位化法向量。
glEnable(GL_COLOR_MATERIAL);//使用颜色材质
glEnable(GL_LIGHTING);//开启灯光 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);//设置0号光源的环境强度
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);//光源的漫反射
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);//光源镜面反射
glLightfv(GL_LIGHT0, GL_POSITION, light_position);//指定光源位置 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);//材质属性中的发射光
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);//材质属性中的散射光
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);//材质属性中的镜面反射光
glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);//材质属性中的光强度 glutMainLoop();//这里让整个绘图循环进行,相当于死循环 return EXIT_SUCCESS;
}

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

什么是opengl

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

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

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

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

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

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

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

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

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

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

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

    深入理解OpenGL拾取模式(OpenGL Picking) 本文转自:http://blog.csdn.net/zhangci226/article/details/4749526 在用OpenGL ...

  2. OpenGL模板 Mac Cmake OpenGL(Glut) Template

    自己经常使用的一些功能做一个模板,有灯光效果,你可以用鼠标放大,围绕所述旋转坐标系的原点 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHlhbmcxOT ...

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

    原文链接: 1.用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口 2.Windows MFC 两个OpenGL窗口显示与线程RC问题

  4. OpenGl之旅-—如何使用code blocks创建一个opengl项目

    开始学习opengl啦,练习用的编辑器是code blocks. 首先当然是要清楚如何使用code blocks创建一个opengl项目了. 首先必须先引用opengl的库glut,网上百度下载一个完 ...

  5. 初识OpenGl

    函数命名规则 OpenGl函数都遵循一个命名约定:<库前缀> <根命令> <可选参数个数> <可选参数类型> 如:glColor3f() ,gl:核心库 ...

  6. 【OpenGL】 第一篇 OpenGL概览

    ---------------------------------------------------------------------------------------------------- ...

  7. OpenGL extension specification (from openGL.org)

    Shader read/write/atomic into UAV global memory (need manual sync) http://www.opengl.org/registry/sp ...

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

    我的系统为Ubuntu14.04,用apt-get安装了实现了OpenGl的mesa,QT则是用官网下载的run文件来安装的. 好了,现在两个都分别有了,所以要在qt下尝试写OpenGl代码. 之前试 ...

  9. OpenGL学习 Our First OpenGL Program

    This shows you how to create the main window with the book’s application framework and how to render ...

随机推荐

  1. BC1.2的一些心得

    什么叫DCD DataContact Detect(DCD) 1.首先是DCD 2.然后是Primary detection 3.然后是Secondary detection 检測充电的条件是VBUS ...

  2. /etc/profile与/etc/bashrc、交互式与非交互式、login与non-login shell的差别

    线上的memcached又挂了.仍然没有得到core文件. 排查原因,同事发现启动memcached的脚本存在可疑问题. 问题一:没有设置memcached工作文件夹,有可能core dump时没有工 ...

  3. 在做java 的web开发,为什么要使用框架

    现在做项目都会使用框架,现在很常见的框架就是SSH(Struts+SpringMVC+spring+hibernate),SSM(Struts/springMVC+Spring+Hibernate), ...

  4. 网络驱动移植之net_device结构体及其相关的操作函数

    内核源码:Linux-2.6.38.8.tar.bz2 在Linux系统中,网络设备都被抽象为struct net_device结构体.它是网络设备硬件与上层协议之间联系的接口,了解它对编写网络驱动程 ...

  5. 一.OC基础之:1,OC语言的前世今生 ,2,OC语言入门,3,OC语言与C的差异,4,面向对象,5,类和对象的抽象关系,6,类的代码创建,7,类的成员组成及访问

    1,OC语言的前世今生 , 一, 在20世纪80年代早期,布莱德.麦克(Brad Cox)设计了OC语言,它在C语言的基础上增加了一层,这意味着对C进行了扩展,从而创造出一门新的程序设计语言,支持对象 ...

  6. 牛客练习赛13D:幸运数字Ⅳ(康托展开) F:关键字排序

    链接:https://www.nowcoder.com/acm/contest/70/D 题目: 定义一个数字为幸运数字当且仅当它的所有数位都是4或者7. 比如说,47.744.4都是幸运数字而5.1 ...

  7. 从free到page cache

    Free 我们经常用free查看服务器的内存使用情况,而free中的输出却有些让人困惑,如下:   图1-1 先看看各个数字的意义以及如何计算得到: free命令输出的第二行(Mem):这行分别显示了 ...

  8. E20180206-E

    fundamental   adj. 基础的,基本的,根本的,重要的,原始的,主要的,十分重大的; [物] 基频的,基谐波的; [乐] 基音的; n. 原理,原则,基本,根本,基础; [乐] 基音; ...

  9. bzoj 2839: 集合计数【容斥原理+组合数学】

    首先,考虑容斥,我们所要的答案是并集至少有\( k \)个数的方案数减去并集至少有\( k+1 \)个数的方案数加上并集至少有\( k \)个数的方案数-- 在n个数中选i个的方案数是\( C_{n} ...

  10. hdu 3007【最小圆覆盖-随机增量法模板】

    #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> usin ...