昨天学习了如何使用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. IO流(字节流复制)01

    package ioDemo; import java.io.*; /** * IO流(字节流复制) * Created by lcj on 2017/11/2. */ public class bu ...

  2. url加密并计算时间

    将URL地址参数进行加密传输提高网站安全性 加密算法,直接调用就好 function keyED($txt,$encrypt_key){ $encrypt_key = md5($encrypt_key ...

  3. 第一个get请求的爬虫程序

    一:urllib库: urllib是Python自带的一个用于爬虫的库,器主要作用就是可以通过代码模拟浏览器发送请求.其被用到子模块在Python3中的urllib.request和urllib.pa ...

  4. H5的localStorage简单存储删除

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  5. mongo03

    Mongo存储的单位是文档,文档是js对象, use test2 db.createCollection("stu")//隐士创建库显示创建表 db.stu.,name:" ...

  6. UVALive3415 Guardian of Decency —— 最大独立集

    题目链接:https://vjudge.net/problem/UVALive-3415 题解: 题意:选出尽可能多的人, 使得他(她)们之间不会擦出火花.即求出最大独立集. 1.因为性别有男女之分, ...

  7. 什么是以太坊私钥储存(Keystore)文件

    进入keystore管理以太坊私钥的障碍很大,主要是因为以太坊客户端在直接的命令行或图形界面下隐藏了大部分的密码复杂性. 例如,用geth: $ geth account new Your new a ...

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

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

  9. bzoj3265: 志愿者招募加强版(线性规划+单纯形法)

    传送门 鉴于志愿者招募那题我是用网络流写的所以这里还是写一下单纯形好了-- 就是要我们求这么个线性规划(\(d_{ij}\)表示第\(i\)种志愿者在第\(j\)天能不能服务,\(x_i\)表示第\( ...

  10. [SDOI2019] 移动金币

    分析 阶梯NIM模型:共有m+1堆石子,石子总数不超过n-m,求必胜的,即奇数堆石子数目异或和非零的局面数.补集转化,答案C(n,m)-奇数堆石子数目异或和位0的局面数. 可以想到按位dp,设f[i, ...