OpenGL ES初深之GLKit

303 阅读11分钟

前言

OpenGLES(OpenGLforEmbeddedSystems)是以⼿持和嵌⼊式为⽬标的⾼级3D图形应⽤程序编程接⼝(API).OpenGLES是⽬前智能⼿机中占据统治地位的图形API.⽀持的平台:iOS,Andriod,BlackBerry,bada,Linux,Windows。

OpenGLES开放式图形库(OpenGL的)⽤于可视化的⼆维和三维数据。它是⼀个多功能开放标准图形库,⽀持2D和3D数字内容创建,机械和建筑设计,虚拟原型设计,⻜⾏模拟,视频游戏等应⽤程序。您可以使⽤OpenGL配置3D图形管道并向其提交数 据。顶点被变换和点亮,组合成图元,并光栅化以创建2D图像。

OpenGL旨在将函数调⽤转换为可以发送到底层图形硬件的图形命令。由于此底层硬件专⽤于处理图形命令,因此OpenGL绘图通常⾮常快。 OpenGLforEmbeddedSystems(OpenGLES)是OpenGL的简化版本,它消除了冗余功能,提供了⼀个既易于学习⼜更易于在移动图形硬件中实现的库。

OpenGLES允许应⽤程序利⽤底层图形处理器的强⼤功能。iOS设备上的GPU可以执⾏复杂的2D和3D绘图,以及最终图像中每个像素的复杂着⾊计算

OPenGL ES 图形管线



Application -> Vertex(顶点着色器)->Geometry(图源装配)->Fragment(片源着色器)->桢缓冲区。

顶点着色器

  • 着⾊器程序—描述顶点上执⾏操作的顶点着⾊器程序源代码/可执⾏⽂件
  • 顶点着⾊器输⼊(属性)—⽤顶点数组提供每个顶点的数据 
  • 统⼀变量(uniform)—顶点/⽚元着⾊器使⽤的不变数据 
  • 采样器—代表顶点着⾊器使⽤纹理的特殊统⼀变量类型


顶点着⾊器业务: 

  • 矩阵变换位置 
  • 计算光照公式⽣成逐顶点颜⾊
  •  ⽣成/变换纹理坐标 

总结:它可以⽤于执⾏⾃定义计算,实施新的变换,照明或者传统的固定功能所不允许的基于顶点的效果

代码实例

attribute vec4 position;
attribute vec2t extCoordinate;
uniform mat4 rotateMatrix;
varying lowp vec2 varyTextCoord;
voidmain()
{
   varyTextCoord = textCoordinate;
   vec4vPos = position;
   vPos = vPos * rotateMatrix;//列向量*列矩阵
   gl_Position = vPos;
}


图元装配

顶点着⾊器之后,下⼀个阶段就是图元装配. 图元(Primitive):点,线,三⻆形等. 图元装配:将顶点数据计算成⼀个个图元.在这个阶段会执⾏裁剪、透视分割和 Viewport变换操作。 图元类型和顶点索确定将被渲染的单独图元。对于每个单独图元及其对应的顶点,图元装配阶段执⾏的操作包括:将顶点着⾊器的输出值执⾏裁剪、透视分割、视⼝变换后进⼊光栅化阶段。

 光栅化

在这个阶段绘制对应的图元(点/线/三⻆形).光栅化就是将图元转化成⼀组⼆维⽚段的过程.⽽这些转化的⽚段将由⽚元着⾊器处理.这些⼆维⽚段就是屏幕上可绘制的像素。



⽚段着⾊器/⽚元着⾊器

  • 着⾊器程序—描述⽚段上执⾏操作的⽚元着⾊器程序源代码/可执⾏⽂件
  • 输⼊变量—光栅化单元⽤插值为每个⽚段⽣成的顶点着⾊器输出 
  • 统⼀变量(uniform)—顶点/⽚元着⾊器使⽤的不变数据
  • 采样器—代表⽚元着⾊器使⽤纹理的特殊统⼀变量类型


⽚元着⾊器业务

  • 计算颜⾊ 
  • 获取纹理值 
  • 往像素点中填充颜⾊值(纹理值/颜⾊值)

总结:它可以⽤于图⽚/视频/图形中每个像素的颜⾊填充(⽐如给视频添加滤镜,实际上就是将视频中每个图⽚的像素点颜⾊填充进⾏修改。

⽚元着⾊代码案例:

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
gl_FragColor = texture2D(colorMap,varyTextCoord);}

逐片段操作


逐⽚段操作

  • 像素归属测试:确定帧缓存区中位置(Xw,Yw)的像素⽬前是不是归属于OpenGLES所有.例如,如果⼀个显示OpenGLES帧缓存区View被另外⼀个View所遮蔽.则窗⼝系统可以确定被遮蔽的像素不属于OpenGLES上下⽂.从⽽不全显示这些像素.⽽像素归属测试是OpenGLES的⼀部分,它不由开发者开⼈为控制,⽽是由OpenGLES内部进⾏.
  • 裁剪测试:裁剪测试确定(Xw,Yw)是否位于作为OpenGLES状态的⼀部分裁剪矩形范围内.如果该⽚段位于裁剪区域之外,则被抛弃.
  • 深度测试:输⼊⽚段的深度值进步⽐较,确定⽚段是否拒绝测试
  • 混合:混合将新⽣成的⽚段颜⾊与保存在帧缓存的位置的颜⾊值组合起来.
  • 抖动:抖动可⽤于最⼩化因为使⽤有限精度在帧缓存区中保存颜⾊值⽽产⽣的伪像.
  • OpenGLES命令需要渲染上下⽂和绘制表⾯才能完成图形图像的绘制.
  • 渲染上下⽂:存储相关OpenGLES状态.
  • 绘制表⾯:是⽤于绘制图元的表⾯,它指定渲染所需要的缓存区类型,例如颜⾊缓存区,深度缓冲区和模板缓存区.
  • OpenGLESAPI并没有提供如何创建渲染上下⽂或者上下⽂如何连接到原⽣窗⼝系统.EGL是Khronos渲染API(如OpenGLES)和原⽣窗⼝系统之间的接⼝.唯⼀⽀持 OpenGLES却不⽀持EGL的平台是iOS.Apple提供⾃⼰的EGLAPI的iOS实现,称为EAGL.
  • 因为每个窗⼝系统都有不同的定义,所以EGL提供基本的不透明类型—EGLDisplay,这个类型封装了所有系统相关性,⽤于和原⽣窗⼝系统接⼝.

由于OpenGLES是基于C的API,因此它⾮常便携且受到⼴泛⽀持。作为CAPI,它与Objective-CCocoaTouch应⽤程序⽆缝集成。OpenGLES规范没有定义窗⼝层;相反,托管操作系统必须提供函数来创建⼀个接受命令的OpenGLES渲染上下⽂和⼀个帧缓冲区,其中写⼊任何绘图命令的结果。在iOS上使⽤OpenGLES需要使⽤iOS类来设置和呈现绘图表⾯,并使⽤平台中⽴的API来呈现其内容。

OpenGLES显示器执⾏动画的应⽤程序流程


来到GLKit

GLKit框架的设计⽬标是为了简化基于OpenGL/OpenGLES的应⽤开发.。它的出现加快OpenGLES或OpenGL应⽤程序开发。使⽤数学库,背景纹理加载,预先创建的着⾊器效果,以及标准视图和视图控制器来实现渲染循环。

 GLKit框架提供了功能和类,可以减少创建新的基于着⾊器的应⽤程序所需的⼯作量,或者⽀持依赖早期版本的OpenGLES或OpenGL提供的固定函数顶点或⽚段处理的现有应⽤程序。

GLKView提供绘制场所(View) GLKViewController(扩展于标准的UIKit设计模式.⽤于绘制视图内容的管理与呈现.)

苹果弃⽤OpenGLES,但iOS开发者可以继续使⽤.

使⽤GLKit视图呈现OpenGLES内容


配置GLKit视图代码清单

-(void)viewDidLoad{
  [superviewDidLoad];
  //创建OpenGLES上下⽂并将其分配给从故事板加载的视图
  GLKView*view =(GLKView*)self.view;
  view.context = [[EAGLContextalloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];//配置视图创建的渲染缓冲区
  view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
  view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
  view.drawableStencilFormat = GLKViewDrawableStencilFormat8;
  //启⽤多重采样
  view.drawableMultisample = GLKViewDrawableMultisample4X;
}

-(void)drawRect:(CGRect)rect 
{
//清除帧缓冲区
glClearColor(0.0f,0.0f,0.1f,1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

//使⽤先前配置的纹理,着⾊器和顶点数组绘制
glBindTexture(GL_TEXTURE_2D,_planetTexture);
glUseProgram(_diffuseShading);
glUniformMatrix4fv(_uniformModelViewProjectionMatrix,1,0,_modelViewProjectionMatrix.m);
glBindVertexArrayOES(_planetMesh);
glDrawElements(GL_TRIANGLE_STRIP,256,GL_UNSIGNED_SHORT;
}

GLKit功能

  • 加载纹理
  • 提供⾼性能的数学运算
  • 提供常⻅的着⾊器
  • 提供视图以及视图控制器

GLKit纹理加载

GLKTextureInfo创建OpenGL纹理信息.

name:OpenGL上下⽂中纹理名称

target:纹理绑定的⽬标

width、height:加载的纹理宽⾼

textureOrigin:加载纹理中的原点位置

alphaState:加载纹理中alpha分量状态

containsMipmaps:布尔值,加载的纹理是否包含mip贴图

GLTextureLoader 简化各种资源文件中加载纹理

初始化:

- initWithSharegroup: 初始化⼀个新的纹理加载到对象中
- initWithShareContext:初始化⼀个新的纹理加载对象

从⽂件中加载处理:

+ textureWithContentsOfFile:options:errer: 从⽂件加载2D纹理图像并从数据中创建新的纹理
- textureWithContentsOfFile:options:queue:completionHandler: 加载2D纹理图像,并根据数r据创建新纹理

CGImages创建纹理:

- textureWithCGImage:options:error: 从Quartz图像加载2D纹理图像并从数据创建新纹理
- textureWithCGImage:options:queue:completionHandler: 从Quartz图像异步加载2D纹理

从URL加载多维创建纹理:

/*从单个URL加载⽴⽅体贴图纹理图像,并根据数据创建新纹理*/
+ cabeMapWithContentsOfURL:options:errer: /*从单个URL异步加载⽴⽅体贴图纹理图像,并根据数据创建新纹理*/
- cabeMapWithContentsOfURL:options:queue:completionHandler: 

从⽂件加载多维数据创建纹理

/*从单个⽂件加载⽴⽅体贴图纹理对象,并从数据中创建新纹理*/
+ cubeMapWithContentsOfFile:options:errer: 

/*从单个⽂件异步加载⽴⽅体贴图纹理对象,并从数据中创建新纹理*/
- cubeMapWithContentsOfFile:options:queue:completionHandler: /*从⼀系列⽂件中加载⽴⽅体贴图纹理图像,并从数据总创建新纹理*/
+ cubeMapWithContentsOfFiles:options:errer:/*从⼀系列⽂件异步加载⽴⽅体贴图纹理图像,并从数据中创建新纹理*/
- cubeMapWithContentsOfFiles:options:options:queue:completionHandler: 

GLKitOpenGLES视图渲染

GLKView使⽤OpenGLES绘制内容的视图默认实现:

初始化视图

-initWithFrame:context: 

视图的代理

delegate 

配置帧缓存区对象

drawableColorFormat 颜⾊渲染缓存区格式drawableDepthFormat 深度渲染缓存区格式drawableStencilFormat 模板渲染缓存区的格式drawableMultisample 多重采样缓存区的格式

帧缓存区属性

drawableHeight 底层缓存区对象的⾼度(以像素为单位)drawableWidth 底层缓存区对象的宽度(以像素为单位)

绘制视图的内容

context绘制视图内容时使⽤的OpenGLES上下⽂
-bindDrawable将底层FrameBuffer对象绑定到OpenGLES
enableSetNeedsDisplay布尔值,指定视图是否响应使得视图内容⽆效的消息
-display⽴即重绘视图内容
snapshot绘制视图内容并将其作为新图像对象返回

删除视图FrameBuffer对象

-deleteDrawable删除与视图关联的可绘制对象

绘制视图的内容

-glkView:drawInRect: 绘制视图内容(必须实现代理)

更新

-(void)update 更新视图内容
-(void)glkViewControllerUpdate:

配置帧速率

preferredFramesPerSecond 视图控制器调⽤视图以及更新视图内容的速率
framesPerSencond视图控制器调⽤视图以及更新其内容的实际速率

控制帧更新

paused 布尔值,渲染循环是否已暂停
pausedOnWillResignActive 布尔值,当前程序重新激活活动状态时视图控制器是否⾃动暂停渲染循环
resumeOnDidBecomeActive 布尔值,当前程序变为活动状态时视图控制是否⾃动恢复呈现循环

获取有关View更新信息

frameDisplayed视图控制器⾃创建以来发送的帧更新数
timeSinceFirstResume ⾃视图控制器第⼀次恢复发送更新事件以来经过的时间量
timeSinceLastResume ⾃上次视图控制器恢复发送更新事件以来更新的时间量
timeSinceLastUpdate⾃上次视图控制器调⽤委托⽅法以及经过的时间量 glkViewControllerUpdate:
timeSinceLastDraw⾃上次视图控制器调⽤视图display⽅法以来经过的时间量.

GLKViewControllerDelegate渲染循环回调⽅法

处理更新事件

-glkViewControllerUpdate: 在显示每个帧之前调⽤

暂停/恢复通知

-glkViewController:willPause: 在渲染循环暂停或恢复之前调⽤

GLKBaseEffect

GLKBaseEffect⼀种简单光照/着⾊系统,⽤于基于着⾊器OpenGL渲染

命名Effect

label给Effect(效果)命名

配置模型视图转换

transform绑定效果时应⽤于顶点数据的模型视图,投影和纹理变换

配置光照效果

lightingType⽤于计算每个⽚段的光照策略,GLKLightingTypeGLKLightingType

//表示在三⻆形中每个顶点执⾏光照计算,然后在三⻆形进⾏插值
GLKLightingTypePerVertex 

//表示光照计算的输⼊在三⻆形内插⼊,并且在每个⽚段执⾏光照计算
GLKLightingTypePerPixe

配置光照

lightModelTwoSided 布尔值,表示为基元的两侧计算光照
material计算渲染图元光照使⽤的材质属性
lightModelAmbientColor环境颜⾊,应⽤效果渲染的所有图元.
light0场景中第⼀个光照属性
light1场景中第⼆个光照属性
light2场景中第三个光照属性

配置纹理

texture2d0 第⼀个纹理属性
texture2d1第⼆个纹理属性
textureOrder纹理应⽤于渲染图元的顺序

配置雾化

fog应⽤于场景的雾属性

配置颜⾊信息

colorMaterialEnable  布尔值,表示计算光照与材质交互时是否使⽤颜⾊顶点属性
useConstantColor布尔值,指示是否使⽤常量颜⾊
constantColor不提供每个顶点颜⾊数据时使⽤常量颜⾊

准备绘制效果

-prepareToDraw准备渲染效果