OpenGLES视频渲染框架应用
渲染
用3D数据生成一个2D图像的过程。
数据饥饿
CPU擅长运算,读写内存较慢,当CPU的性能因为等待内存读写而处于次优状态时,这种次优状态就叫做数据饥饿。
为缓存提供数据
1、生成(Generate),为缓存生成独一无二的标识符。
2、绑定(Bind),确定接下来运算使用的缓存。
3、缓存数据(Buffer Data),为绑定的内存分配并出示足够的内存,把CPU控制的内存数据复制到分配的内存。
4、启用或者禁止(Enable、Disable),确定在接下来的渲染是否采用缓存。
5、设置指针(Set Pointer),确定缓存中数据的类型和数据的偏移值。
6、绘图(Draw),绘制部分或者整个场景。
7、删除(Delete),删除生产的缓存并且释放资源。
缓存的生成、初始化和删除,需要耗费时间来同步图形处理器和CPU。
GPU在删除一个缓存之前必须等待缓存相关的运算结束,如果频繁生成和删除缓存,GPU没有足够时间进行渲染。
数据类型
OpenGL ES 坐标是以浮点数来存储,GPU对浮点运算做了专门的优化,即使使用其他数据类型的顶点也会被转换成浮点型。
图形处理器本质上就是大规模并行矢量处理器。
帧缓存
接收渲染结果的缓冲区叫做帧缓存。
有两个特别的帧缓存,前帧缓存和后帧缓存,控制着屏幕像素的最终颜色。
OpenGL ES的上下文保存了OpenGL ES的状态信息,包括用于渲染数据的缓存地址和接收渲染结果的缓存地址。
软件架构
每一个iOS原生控件都有一个对应的CoreAnimation层。
CoreAnimation合成器使用OpenGL ES来尽可能高效地控制GPU、混合层和切换帧缓存。
OpenGL ES会有连接到层,与层分享数据的帧缓存,至少包括一个像素颜色渲染缓存。
OpenGL ES函数
EAGLContext:封装一个特定于某个平台的OpenGL ES上下文 实例。
EAGL 可能是 Embedded Apple GL
RGBA颜色:红绿蓝和透明度。(Red、Green、Blue、Alpha)
glBufferData方法中,GL_STATIC_DRAW告诉上下文,缓存中的内容适合复制到GPU控制的内存,因为很少对其进行修改;GL_DYNAMIC_DRAW则表示数据会频繁修改,以不同的方式来处理。
帧缓存可能有除了像素颜色渲染缓存之外的其他附加缓存(比如说深度测试),他们可以通过在glClear()函数中制定不同的参数来清除。
glVertextAttribPointer()第四个参数表示小数点固定数据是否可以被改变。
viewDidUnload在视图被卸载时候调用,可以在此删除OpenGL ES缓存。(和dealloc不同)
CAEAGLLyaer是CoreAnimation提供的标准层类之一,与OpenGL ES的帧缓存共享它的像素颜色仓库。
context presentRenderbuffer:GL_RENDERBUFFER 让上下文调整外观并使用CoreAnimation合成器把帧缓存的像素颜色渲染缓存与其他相关层混合起来。
glViewport() 函数用来控制渲染至帧缓存的子集。(设置视口变换的视口大小)
视图重新调整大小的时候,layoutSubviews会被调用。
CADisplayLink的消息为重新渲染一个场景提供了理想的触发器,渲染速度大于显示刷新速度是浪费。
GLKBaseEffect会生成直接在GPU上运行的GLSL。
纹理
一个用来保存图像颜色的OpenGL ES缓存。
渲染过程中的取样可能会导致纹理被拉伸、压缩、翻转等。
视口坐标
帧缓存中的像素位置叫做视口坐标。视口转换的结果是所有绘制的几何图形都被拉伸以适应屏幕大小。
光栅化
转换几何形状数据为帧缓存中的颜色像素,叫做点阵化(rasterizing),也叫光栅化。
每个颜色像素叫做片元(fragment)。
纹理坐标系
纹理坐标系
glTexParameteri参数
GL_TEXTURE_MIN_FILTER表示较多纹素对应较少片元
GL_TEXTURE_MAG_FILFER表示较多片元对应较少纹素
GL_LINEAR 表示线性插值
GL_NEARSET 表示就近选择
当UV坐标超过ST坐标时候
GL_TEXTURE_WRAP_S表示U坐标超过了S坐标
GL_TEXTURE_WRAP_T表示V坐标超过了T坐标
GL_REPEAT 重复纹理以填满UV区域
GL_CLAMP_TO_EDGE 取样纹理边缘的纹素
MIP贴图
高细节的纹理,沿着S、T轴存储更多的纹素,减少GPU取样的数量提高渲染性能,但会增加内存。
glTexImage2D
第一个参数是GL_TEXTURE_2D
第二个参数用于指定MIP贴图的初始细节级别,如果没有使用MIP必须要是0
第三个参数是指定纹理缓存每个纹素需要保存的信息数量,对于iOS设备,有GL_RGB和RL_RGBA
第四、五个参数指定图像的宽度和高度,必须是2的幂
第六个 确定纹理纹素的边界大小,OpenGL ES中总是被设置为0
第七个 指定初始化缓存所用的图像数据中的每个像素要保存的信息,在OpenGL ES中与inernalFormat
第八个 纹素的位编码类型
第九个 像素颜色数据的指针
多重纹理
多重纹理可以避免多通道渲染导致的内存访问限制性能情况
self.baseEffect.texture2d1.envMode = GLKTextureEnvModeDecal;可以开启多重纹理
光线
GPU首先为每个三角形的顶点进行光线计算,再把结果进行插值,得出每个片元的最终颜色。
OpenGL ES的灯光模拟包括:环境光、漫反射光、镜面反射光。
只有每个光源的环境光部分才会照射到三角形的后面。
光线与几何图形相互作用的关键:计算出每个几何物体照射和发散出来多少光线。通过计算每个三角形与光的方向的垂直角度。
矢量积:右手法则。
VectorA × VectorB 的矢量积 和 B × A 是方向相反的。
光线计算依赖于表面法向量。法向量也是单位向量。
在GLKBaseEffect的灯光开启后,灯光决定了渲染的颜色;常量的颜色和顶点的颜色将被忽略。(constantColor属性仅适用于渲染单调不发光的物体)
对于立体表面而言,法线是有方向的:一般来说,由立体的内部指向外部的是法线正方向,反过来的是法线负方向。
缩放对灯光有潜在的影响:一个法向量被缩放后,就可能不再是一个单位向量。
GLKit的GLKBaseEffect类生产的GLSL会按需正规化法向量。
深度测试
每次渲染一个片元,片元的深度(片元与视点之间的距离)被计算出来并与深度缓存中为片元位置保存的值进行对比:选择深度值更小(更接近视点)的片元来,替换在像素颜色渲染缓存中对应位置的颜色和深度缓存的对应深度值。
深度缓存为GPU提供了一个存放计算出来深度值的缓存,并且用来控制像素颜色渲染缓存中片元的置换。
GLKit支持16位和24位来保存深度值的深度渲染缓存。
深度冲突(Z-fighting),两个片元的深度非常接近,深度缓存没有如果的进度来区分,最终的片元颜色经常在可能性之间来回闪烁,制造一个可见的干扰。
不使用GLKit辅助,管理一个OpenGL ES深度缓存需要的步骤:
1、Generate(生成)—— 生成独一无二的标识符
2、Bind(绑定)—— 确定使用的缓存
3、Configure Storage (配置存储) —— 指定大小
4、 Attach(附加) —— 附加到一个帧缓存
与一个Core Animation共享内存的像素颜色渲染缓存在层调整大小时会自动调整大小。其他缓存,例如深度缓存,不会自动调整大小。
可以在layoutSubviews方法里面删除现存的深度缓存,并创建一个新的与像素颜色渲染缓存的新尺寸相匹配的深度缓存。
变换
两个坐标系之间转换顶点坐标。
基本变换
四个基本变换
平移(translation)
旋转(rotation)
缩放(scale)
透视(perspective)
投影变换
视锥体的近平面不能用z位置小于0,即使是很小的z的值也会有问题。
从近平面到远平面的距离范围会映射为深度缓存中的深度范围,当GPU计算保存在深度缓存中的值时,大幅度或者过小的近平面距离会产生数学舍入误差。
OpenGL ES使用一个叫做视域的几何图形来决定一个场景生成的片元是否会显示在最终的渲染结果中。
OpenGL ES默认为指入屏幕的负的Z坐标轴,GLKMatrixMakeFrustum() 产生一个指入屏幕的带有正的Z坐标轴的视域(view volume)。