引子:移动端开发经过这么多年的开发,已经越来越成熟了,而且由于网页端技术的野蛮发展,移动端开发已经越来越式微啦。在这个环境下深耕iOS原生和努力掌握大前端技术栈对于iOS开发者来说越发的重要。基于图形和视频技术的流行趋势,掌握图形和视频的渲染技术栈也显得越发重要。本篇介绍如果在Xcode搭建Open GL 工程。
该篇文章简单的搭建一个在MAC的OpenGL工程,以及对代码进行解释
-
新建macOS工程 Xcode --> File --> New --> Project
选择macOS ---> Application ---> App
-
添加OpenGL.framework和GLUT.framework两个系统库
在General下的Frameworks,Libraries,and Embedded Content下,或者Build Phases下的Link Binary With Libraries下添加OpenGL.framework和GLUT.framework两个系统库
-
导入GLTools、libGTools.a等文件这里已经整理好了。直接把include、libGTools.a文件拖入工程
文件地址:https://pan.baidu.com/s/1cM8ryabz_hfiqGCJIws5ig 提取码:tqch
删除程序入口文件:AppDelegate.h、AppDelegate.m、Main.storyboard、main.m、viewController.h、viewController.m
-
新建程序入口文件main.cpp
新建c++文件main.cpp作为程序入口文件,不创建header file文件
编写main.cpp文件绘制一个图形
main.cpp文件如下:
#include
#include "GLTools.h"
/*
GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数
*/
#include
/*
在Mac 系统下,`#include`
在Windows 和 Linux上,我们使用freeglut的静态库版本并且需要添加一个宏
*/
#include "GLShaderManager.h"
/*
`#include` 移入了GLTool 着色器管理器(shader Mananger)类。没有着色器,我们就不能在OpenGL(核心框架)进行着色。着色器管理器不仅允许我们创建并管理着色器,还提供一组“存储着色器”,他们能够进行一些初步䄦基本的渲染操作。
*/
GLBatch triangleBatch;// 简单的批次容器,是GLTools的一个简单的容器类。
GLShaderManager shaderManager;// 定义一个着色管理器
/// 窗口大小改变时接受新的宽度和高度,其中(0,0)代表窗口的左下角坐标,w、h代表像素
void changeSize(int w, int h) {
glViewport(0, 0, w, h);
}
/// 做初始花设置
void setupRC(){
/// 设置背景颜色
glClearColor(1.f, 1.f, 1.f, 1.f);
/// 初始化着色管理器
shaderManager.InitializeStockShaders();
/// 设置三角形,其中数组vVert包含所有3个顶点的x,y,笛卡尔坐标对。
GLfloat vVerts[] = {
-1.f, -1.f, 0.f,
0.5f, 0.f, 0.f,
-0.6f, 0.5f, 0.f
};
/// 批次处理
triangleBatch.Begin(GL_TRIANGLES, 3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
/// 开始渲染
void renderScene(void) {
/// 清除一个或一组特定的缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
/// 设置一组浮点数表示红色
GLfloat vRed[] = {1.f, 0.f, 0.f, 1.f};
/// 传递到存储着色器,即GLT_SHADER_IDENTITY着色器,这个着色器只是使用指定颜色以默认笛卡尔坐标系在屏幕上渲染集合图形
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
/// 提交着色器
triangleBatch.Draw();
/// 将在后台缓冲区进行渲染,然后再结束时交换到前台
glutSwapBuffers();
}
int main(int argc, char * argv[]) {
/// 设置当前工作目录,针对MAC OS X,防止在Windows上错误。在Windows中是没必要的。因为windows下默认的工作目录就是与程序可执行目录相同。但是在Mac OS中工作目录被更改为应用程序捆绑中的/Resource文件夹。
gltSetWorkingDirectory(argv[0]);
/// 初始化GLUT库,GLUT库的api在macOS 10.9 已被弃,但不影响使用
glutInit(&argc, argv);
/// 初始化双缓存窗口 GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL 分别是:双缓存窗口、RGBA颜色模式、深度测试、模板缓冲区
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
/// GLUT窗口,设置窗口大小
glutInitWindowSize(800, 800);
/// 设置窗口标题
glutCreateWindow("Triangle");
/// 注册回调
glutReshapeFunc(changeSize);// 注册重塑函数
glutDisplayFunc(renderScene);// 注册显示函数
/// 驱动程序的初始化无问题,初始化GLEW库,确保OpenGL API对程序完全可用。
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "glew error: %s\n",glewGetErrorString(err));
return 1;
}
/// 调用setupRC,设置渲染环境
setupRC();
/// 进入GLUT事件处理循环,让所有的与“事件”有关的函数调用无限循环,这里让整个绘图循环进行。它将调用必要的任何已注册的回调
glutMainLoop();
return 0;
}
程序入口main函数代码解读:
- gltSetWorkingDirectory(argv[0])
设置当前工作目录,针对MAC OS X,防止在Windows上错误。在Windows中是没必要的。因为windows下默认的工作目录就是与程序可执行目录相同。但是在Mac OS中工作目录被更改为应用程序捆绑中的/Resource文件夹。 - glutInit(&argc, argv)
初始化(OpenGL Utility Toolkit),GLUT是一个很方便的辅助库,而且与平台无关。GLUT的功能包括窗口和菜单的创建和管理,事件处理以及提供了很多绘制3D图形的方法等等。虽然GLUT库的api在macOS 10.9 已被弃用但是作为窗口工具在学习OpenGL却是比较方便的 - glutInitDisplayMode(unsigned int mode)
设置显示模式的类型mode的类型值可指定单个或多个值的组合,在本程序我们选择GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL
值 | 对应宏定义 | 意义 |
---|---|---|
GLUT_RGB | 0x0000 | 指定RGB颜色模式的窗口 |
GLUT_RGBA | 0x0000 | 指定RGBA颜色模式的窗口 |
GLUT_INDEX | 0x0001 | 指定颜色索引模式的窗口 |
GLUT_SINGLE | 0x0000 | 指定单缓存窗口 |
GLUT_DOUBLE | 0x0002 | 指定双缓存窗口 |
GLUT_ACCUM | 0x0004 | 窗口使用累加缓存 |
GLUT_ALPHA | 0x0008 | 窗口的颜色分量包含 alpha 值 |
GLUT_DEPTH | 0x0010 | 窗口使用深度缓存 |
GLUT_STENCIL | 0x0020 | 窗口使用模板缓存 |
GLUT_MULTISAMPLE | 0x0080 | 指定支持多样本功能的窗口 |
GLUT_STEREO | 0x0100 | 指定立体窗口 |
GLUT_LUMINANCE | 0x0200 | 窗口使用亮度颜色模型 |
- 窗口参数设置:
glutInitWindowSize(800, 800)用来设置窗口大小
glutCreateWindow("Triangle")设置窗口的名字 - 注册回调函数:
glutReshapeFunc(void (func)(int width, int height));// glutReshapeFunc函数在调整窗口大小时被调用
glutDisplayFunc(void (func)(void));// glut调用glutDisplayFunc函数进行渲染 - glewInit()初始化GLEW
(OpenGL Extension Wrangler Library)是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLEW。初始化失败就退出程序。 - setupRC()
在该函数中进行预加载纹理,建立几何图形,渲染器等工作 - glutMainLoop()
进入GLUT事件处理循环,让所有的与“事件”有关的函数调用无限循环,这里让整个绘图循环进行。它将调用必要的任何已注册的回调
setupRC函数解读:
- glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)在颜色缓冲被清空后调用设置色值和透明度。
- GLShaderManager:
存储着色器由GLTools的C++类GLShaderManager管理。
GLShaderManager shaderManager;
shaderManager.InitializeStockShaders();初始化存储着色管理器 - vVerts:
vVerts中存储顶点坐标,因为采用的是笛卡尔坐标系,所以是三个参数表示为一个点,三个三处依次为(x,y,z) -
GLBatch:
GLBatch是GL的一个批次类,可以简单的理解为GL的批次处理脚本类。
GLBatch的Begin(GLenum primitive, GLuint nVerts, GLuint nTextureUnits = 0);函数三个参数分别为几何图元类型,顶点坐标个数和纹理参数。其中纹理参数可为空。该工程我们选择GL_TRIANGLES。调用GLBatch的Begin函数开始预处理,调用CopyVertexData3f函数复制顶点数据,最后调用End函数结束
几何图元的参数一共有十种,分别为:
GL_POINTS:点
GL_LINES:线段,二个点确定线段
GL_LINE_STRIP:第一个点依次连接的线段
GL_LINE_LOOP:和GL_LINE_STRIP相同,但首尾连接,形成环状
GL_POLYGON:多边形
GL_QUADS:由四个点组成一个四边形
GL_QUADS_STRIP:四边形带
GL_TRIANGLES:三角形,三个点确定
GL_TRIANGLE_STRIP:共用一个条带上的顶点的一组三角形
GL_TRIANGLE_FAN:以一个原点为中心呈扇形排列,公共相邻顶点的一组三角形
renderScene函数解读
- glClear (GLbitfield mask)清除viewport的缓冲区,可以清空单个或多个缓冲区标志为:
GL_COLOR_BUFFER_BIT: 当前可写的颜色缓冲
GL_DEPTH_BUFFER_BIT: 深度缓冲
GL_ACCUM_BUFFER_BIT: 累积缓冲
GL_STENCIL_BUFFER_BIT: 模板缓冲 - UseStockShader(GLT_STOCK_SHADER nShaderID, ...)存储着色器的种类有很多种,在该程序我们使用单位着色器GLT_SHADER_IDENTITY。存储着色器的种类有:
单位(Identity)着色器---GLT_SHADER_IDENTITY
平面着色器---GLT_SHADER_FLAT
上色(Shaded)着色器---GLT_SHADER_SHADED
默认光源着色器---GLT_SHADER_DEFAULT_LIGHT
点光源着色器---GLT_SHADER_DEFAULT_LIGHT
纹理替换矩阵着色器---GLT_SHADER_TEXTURE_REPLACE
纹理调整着色器---GLT_SHADER_TEXTURE_MODULATE
纹理光源着色器---GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF等 - GLBatch 的 Draw()函数。提交批次类进行绘制
- glutSwapBuffers()。函数表示双缓存的后台渲染完成后可以交换两个缓冲区指针,这样缓存区已经渲染好的位图就可以交替的出现在屏幕上了