OpenGl之旅-—初识opengl
昨天学习了如何使用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的更多相关文章
- 深入理解OpenGL拾取模式(OpenGL Picking)
深入理解OpenGL拾取模式(OpenGL Picking) 本文转自:http://blog.csdn.net/zhangci226/article/details/4749526 在用OpenGL ...
- OpenGL模板 Mac Cmake OpenGL(Glut) Template
自己经常使用的一些功能做一个模板,有灯光效果,你可以用鼠标放大,围绕所述旋转坐标系的原点 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHlhbmcxOT ...
- [转]用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口
原文链接: 1.用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口 2.Windows MFC 两个OpenGL窗口显示与线程RC问题
- OpenGl之旅-—如何使用code blocks创建一个opengl项目
开始学习opengl啦,练习用的编辑器是code blocks. 首先当然是要清楚如何使用code blocks创建一个opengl项目了. 首先必须先引用opengl的库glut,网上百度下载一个完 ...
- 初识OpenGl
函数命名规则 OpenGl函数都遵循一个命名约定:<库前缀> <根命令> <可选参数个数> <可选参数类型> 如:glColor3f() ,gl:核心库 ...
- 【OpenGL】 第一篇 OpenGL概览
---------------------------------------------------------------------------------------------------- ...
- OpenGL extension specification (from openGL.org)
Shader read/write/atomic into UAV global memory (need manual sync) http://www.opengl.org/registry/sp ...
- Linux下安装QT和OpenGL后QT无法使用OpenGL的解决方法
我的系统为Ubuntu14.04,用apt-get安装了实现了OpenGl的mesa,QT则是用官网下载的run文件来安装的. 好了,现在两个都分别有了,所以要在qt下尝试写OpenGl代码. 之前试 ...
- OpenGL学习 Our First OpenGL Program
This shows you how to create the main window with the book’s application framework and how to render ...
随机推荐
- asp.net mvc + javascript生成下载文件
近期做的是对现有项目进行重构.WEB FROM改成MVC,其实也算是推倒重来了. 里面有一个导出功能,将数据输出成txt文件,供下载.原先的做法是有一个隐藏的iframe,在这个iframe的页面中设 ...
- xcode10的那些事
前言 这里主要介绍一下Xcode10 版本主要更新的内容.随着iOS12的发布,Xcode10已经可以从Mac App Store下载.Xcode10包含了iOS12.watchOS 5.macOS1 ...
- webService和RMI
1.请求: servlet:提供了请求/响应模式,是JAVA的一种规范,只能使用于java上,用来替代早期使用的难懂的CGI,是一种无状态的请求响应,客户端访问一个服务器的url,只需要发送简单的ht ...
- arm位清零bic指令
(1)指令的语法格式 BIC{<cond>}{S} <Rd>,<Rn>,<shifter_operand> BIC(Bit Clear)位清零指令,将寄 ...
- settings.xml 文件配置
Maven 远程中央仓库:repo1.maven.org 通过 ping repo1.maven.org 查看该网络是否可以连接访问: 1. 设置代理 Plugin org.apache.maven. ...
- APACHE2 服务器配置 (二) 默认端口***
如将默认的80端口修改为9000 不管怎样,只要你选择合适的端口(电信商没有封的),进行如下的设置即可: 1, 修改 /etc/apache2/ports.conf 将 NameVirtualHost ...
- 小程序-demo:小程序示例
ylbtech-小程序-demo:小程序示例 1.返回顶部 0. 1.app.js const openIdUrl = require('./config').openIdUrl App({ ...
- ChartCtrl源码剖析之——CChartScrollBar类
CChartScrollBar类用来针对每个轴的数据进行滚动,将那些不在当前区域内的数据通过滚动展示出来. CChartScrollBar类的头文件. #pragma once class CChar ...
- mybatis 基础详解
转 https://www.cnblogs.com/Mr-Kenson/p/8124680.html mybatis 是一个开源的 用于对数据库操作的框架, 读者基本都大体了解其基本功能, 我就不多解 ...
- 【黑金教程笔记之007】【建模篇】【Lab 06 SOS信号之二】—笔记
控制模块的协调角色. 实验六用到了实验四的按键消抖模块debounce_module.v和实验五的sos_module.v. 设计思路: debounce_module.v看成一个输入,sos_mod ...