1.使用GLKView简化OpenGL初始化。
在前面的教程里面,介绍了如何从一个UIView来建立OpenGL工程,里面做了很多初始化工作,比如:创建render buffer 和 frame buffer等。这些重复性的工作,apple提供了一个基础类GLKView给我使用。
在TTAppDelegate.m中初始化了一个TTViewController为rootViewController。
点击TTViewController.xib 我们可以看到它的属性是GLKView,而不是通常的UIView。
TTViewController继承于 GLKViewController,在标准viewcontroller函数的基础上添加了OpenGL ES rendering loop相关的函数。
2. EAGLContext初始化
EAGLContext是OpenGL ES RenderingContext的iOS实现。
每个程序有自己的EAGLContext,这保证了各个OpenGL ES程序互不干扰。
在EAGLContext需要在调用任何OpenGL ES api前创建并初始化。
下面的代码在- (void)viewDidLoad函数的最前面。
创建了一个OpenGL ES 2.0的EAGLContext,并设为view的context。
3. setupGL初始化
在解析[self setupGL]前,我们来看下这个工程运行的结果。
2个不同颜色的正方体在旋转,但是这里只有一个顶点法线数组gCubeVertexData。
仔细观察代码,会发现这里有2个着色器,
一个是GLKBaseEffect,为了方便OpenGL ES 1.0转移到2.0的通用着色器。
一个是OpenGL ES 2.0新添加的可编程着色器,使用跨平台的着色语言GLSL 。
为了方便观察,我在原始代码上加了2个宏来控制打开其中某一个还是两个一起。
屏蔽某一个宏可以屏蔽某个正方体的显示输出。
回到setupGL,第一行代码是
在某个线程调用OpenGL api前,需要设置api作用于哪个context,
这个函数设置当前线程操作的context。
注意:不要多个线程同时操控同一个context。
然后是GLSL着色器初始化,后面再详细分析。
GLKBaseEffect着色器初始化。
最后是顶点数组和法线的初始化。
关于 VertexArray Objects 请猛击。
这里我简单画了个关系图,可能更好理解。
4. loadShaders初始化GLSL着色器
与可编程着色器相关的几个函数如下:
validateProgram没有使用,compileShader和linkProgram可以作为公共库函数,不需要修改。
唯一需要根据需求修改的是loadShaders函数。
loadShaders大部分步骤都有英文注释,标准的加载流程:
1.创建程序。
2.创建并编译 顶点着色器和片段着色器。
3.把 顶点着色器和片段着色器 与 程序连接起来。
4.设置 顶点着色器和片段着色器 的输入参数。
5.链接程序。
6.获取 uniform 指针。
注意:这步只能在 5 成功后才能调用,在 linkProgrom 前, uniform 位置是不确定的。
7.断开 顶点着色器和片段着色器 ,并释放它们。
注意:程序并没释放。
第4步是会变化的部分,第6步为可选。
先来看看Shader.vsh顶点着色器的代码。
再来看片段着色器代码。
我们现在回头再看看loadShaders函数里面的第4步。
"position"和"normal"与顶点着色器代码里面的两个attribute对应,
分别与setupGL加载的顶点数组里面的顶点和法线数据对应起来。
5.update更新数据
update是一个delegate 方法用来更新数据,不做UI更新。
好吧,这部分是很头痛的矩阵变换,暂时不去分析他的算法(其实是我不懂=,=)。
对于GLKBaseEffect着色器,下面的代码用来更新矩阵。
而可编程着色器,先保存在下面2个变量中,然后再draw的时候作为输入参数传递给着色器。
6.drawInRect输出到屏幕
默认工程的不足:
1)顶点数组并没有优化,应使用顶点与索引的方式减少重复点。
参考 [url=http://www.1000phone.net/thread-6263-1-1.html]http://www.1000phone.net/thread-6263-1-1.html 有关glDrawElements的部分。
2)演示了2种着色器的同时使用,可只选其一来使用。
附:GLSL数据类型
void – 用于没有返回值的函式
bool – 条件类型,其值可以是真或假
int – 带负号整数
float – 浮点数
vec2 – 2 个浮点数组成的向量
vec3 – 3 个浮点数组成的向量
vec4 – 4 个浮点数组成的向量
bvec2 – 2 个布林组成的向量
bvec3 – 3 个布林组成的向量
bvec4 – 4 个布林组成的向量
ivec2 – 2 个整数组成的向量
ivec3 – 3 个整数组成的向量
ivec4 – 4 个整数组成的向量
mat2 – 浮点数的 2X2 矩阵
mat3 – 浮点数的 3X3 矩阵
mat4 – 浮点数的 4X4 矩阵
sampler1D – 用来存取一维纹理的句柄(handle)(或:操作,作名词解。)
sampler2D – 用来存取二维纹理的句柄
sampler3D – 用来存取三维纹理的句柄
samplerCube – 用来存取立方映射纹理的句柄
sampler1Dshadow – 用来存取一维深度纹理的句柄
sampler2Dshadow – 用来存取二维深度纹理的句柄
在前面的教程里面,介绍了如何从一个UIView来建立OpenGL工程,里面做了很多初始化工作,比如:创建render buffer 和 frame buffer等。这些重复性的工作,apple提供了一个基础类GLKView给我使用。
在TTAppDelegate.m中初始化了一个TTViewController为rootViewController。
点击TTViewController.xib 我们可以看到它的属性是GLKView,而不是通常的UIView。
TTViewController继承于 GLKViewController,在标准viewcontroller函数的基础上添加了OpenGL ES rendering loop相关的函数。
2. EAGLContext初始化
EAGLContext是OpenGL ES RenderingContext的iOS实现。
每个程序有自己的EAGLContext,这保证了各个OpenGL ES程序互不干扰。
在EAGLContext需要在调用任何OpenGL ES api前创建并初始化。
下面的代码在- (void)viewDidLoad函数的最前面。
创建了一个OpenGL ES 2.0的EAGLContext,并设为view的context。
3. setupGL初始化
在解析[self setupGL]前,我们来看下这个工程运行的结果。
2个不同颜色的正方体在旋转,但是这里只有一个顶点法线数组gCubeVertexData。
仔细观察代码,会发现这里有2个着色器,
一个是GLKBaseEffect,为了方便OpenGL ES 1.0转移到2.0的通用着色器。
一个是OpenGL ES 2.0新添加的可编程着色器,使用跨平台的着色语言GLSL 。
为了方便观察,我在原始代码上加了2个宏来控制打开其中某一个还是两个一起。
从宏块可以方便的看出哪些代码是属于哪个着色器相关的,哪些代码是共用的。
屏蔽某一个宏可以屏蔽某个正方体的显示输出。
回到setupGL,第一行代码是
在某个线程调用OpenGL api前,需要设置api作用于哪个context,
这个函数设置当前线程操作的context。
注意:不要多个线程同时操控同一个context。
然后是GLSL着色器初始化,后面再详细分析。
GLKBaseEffect着色器初始化。
最后是顶点数组和法线的初始化。
关于 VertexArray Objects 请猛击。
这里我简单画了个关系图,可能更好理解。
4. loadShaders初始化GLSL着色器
与可编程着色器相关的几个函数如下:
validateProgram没有使用,compileShader和linkProgram可以作为公共库函数,不需要修改。
唯一需要根据需求修改的是loadShaders函数。
loadShaders大部分步骤都有英文注释,标准的加载流程:
1.创建程序。
2.创建并编译 顶点着色器和片段着色器。
3.把 顶点着色器和片段着色器 与 程序连接起来。
4.设置 顶点着色器和片段着色器 的输入参数。
5.链接程序。
6.获取 uniform 指针。
注意:这步只能在 5 成功后才能调用,在 linkProgrom 前, uniform 位置是不确定的。
7.断开 顶点着色器和片段着色器 ,并释放它们。
注意:程序并没释放。
第4步是会变化的部分,第6步为可选。
先来看看Shader.vsh顶点着色器的代码。
再来看片段着色器代码。
我们现在回头再看看loadShaders函数里面的第4步。
"position"和"normal"与顶点着色器代码里面的两个attribute对应,
分别与setupGL加载的顶点数组里面的顶点和法线数据对应起来。
5.update更新数据
update是一个delegate 方法用来更新数据,不做UI更新。
好吧,这部分是很头痛的矩阵变换,暂时不去分析他的算法(其实是我不懂=,=)。
对于GLKBaseEffect着色器,下面的代码用来更新矩阵。
而可编程着色器,先保存在下面2个变量中,然后再draw的时候作为输入参数传递给着色器。
6.drawInRect输出到屏幕
默认工程的不足:
1)顶点数组并没有优化,应使用顶点与索引的方式减少重复点。
参考 [url=http://www.1000phone.net/thread-6263-1-1.html]http://www.1000phone.net/thread-6263-1-1.html 有关glDrawElements的部分。
2)演示了2种着色器的同时使用,可只选其一来使用。
附:GLSL数据类型
void – 用于没有返回值的函式
bool – 条件类型,其值可以是真或假
int – 带负号整数
float – 浮点数
vec2 – 2 个浮点数组成的向量
vec3 – 3 个浮点数组成的向量
vec4 – 4 个浮点数组成的向量
bvec2 – 2 个布林组成的向量
bvec3 – 3 个布林组成的向量
bvec4 – 4 个布林组成的向量
ivec2 – 2 个整数组成的向量
ivec3 – 3 个整数组成的向量
ivec4 – 4 个整数组成的向量
mat2 – 浮点数的 2X2 矩阵
mat3 – 浮点数的 3X3 矩阵
mat4 – 浮点数的 4X4 矩阵
sampler1D – 用来存取一维纹理的句柄(handle)(或:操作,作名词解。)
sampler2D – 用来存取二维纹理的句柄
sampler3D – 用来存取三维纹理的句柄
samplerCube – 用来存取立方映射纹理的句柄
sampler1Dshadow – 用来存取一维深度纹理的句柄
sampler2Dshadow – 用来存取二维深度纹理的句柄