OpenGL ES顶点着色器和片元着色器
一、OpenGL ES
-
OpenGL ES是使用在手机端和嵌入式里的3D图形应用程序编程接口,是跨平台的API。OpenGL ES是OpenGL的简化版本。
-
OpenGL ES也分客户端Client和服务端Server,OpenGL ES framework属于客户端,与application共同运行在CPU上;OpenGL ES顶点着色器、片元着色器等对图形的处理运行在GPU上,是服务端。客户端向服务端提供数据,服务端通过顶点着色器、片元着色器等计算数据并显示。
二、 OpenGL ES 3.0 图形管线
OpenGL ES 3.0 图形管线- 使用API创建顶点数据(纹理坐标也是顶点数据)存入顶点缓冲区/数组对象,顶点缓冲区是GPU显存上的区间,顶点数组存储在内存中,数据会传给顶点着色器;
- 顶点着色器对glPiont赋值、执行旋转缩放变换等操作,之后进行图元装配;
- 图元装配中设置顶点之间的连接方式来确定绘制方式,然后绘制图形,之后对图形进行光栅化;
- 光栅化是确定图形在屏幕上的像素点,便于后续片元着色器填充颜色;
- 纹理坐标数据是不断变化的,需要通过attribute属性通道交给顶点着色器往下传递到片元着色器;
- 片元着色器对各个像素点填充颜色,可以对图形填充纯色,也可以从纹理数据中获取对应位置的颜色填充;
- 逐片元操作是将图形中的每一个像素点填充颜色,把结果放在帧缓冲区中;
- 从帧缓冲区将结果显示到屏幕上。
tips:图元装配、光栅化、逐片元操作和帧缓冲区是不由开发者参与的,OpenGL会自动计算。
三、OpenGL ES图形管道
OpenGL ES图形管道- application应用:程序代码将图片原始数据如顶点数据和图片数据传递给顶点着色器;
- Vertex顶点着色器:顶点着色器处理旋转缩放等变换数据,需要光照的添加光照数据,将这些数据往下传递进行图元装配;
- Geometry几何处理:对图形的处理,包括图元装配和裁剪,然后交给片元着色器处理;
- Fragment片元着色器:片元着色器计算纹理坐标颜色并填充像素点,将结果存入帧缓冲区;
- Framebuffer Operations帧缓冲区:处理图片透明度、模板、开启深度测试,最后进行颜色混合,从帧缓冲区读取数据并显示到屏幕。
四、屏幕显示图像的流程
-
顶点着色器
顶点着色器
顶点着⾊器:
- 着色器程序——输入顶点数据,描述顶点上执行操作的顶点着色器程序源代码/可执行文件;
- 顶点着色器输入[属性attribute]——用顶点数组提供每个顶点的数据,attribute不能修饰片元着色器里的变量
- 统一变量[uniform]——顶点/片元着色器使用的不变数据,比如客户端代码中计算好的旋转矩阵,通过uniform传输到GLSL中让三角形的每一个顶点都应用旋转矩阵
- 采样器——处理纹理时的一个特殊的变量,获取纹理时不会传递纹理文件纹理数据或者纹理指针到GLSL,而是使用纹理ID在内存中查找对应的纹理。代表顶点着色器使用纹理的特殊统一变量类型
- 顶点着色器输出属性:
顶点着色器实际就是获取到最终的结果给gl_Position赋值,使得计算变换之后的顶点生效,也可以对gl_PointSize赋值更改点的大小。
顶点着色器 业务:
1、矩阵变换位置
2、计算光照公式生成逐顶点颜色
3、生成/变换纹理坐标
总结: 它可以用于执行自定义计算,实施新的变换,照明或者传统的固定功能所不允许的基于顶点的效果.
attribute vec4 position; //attribute属性变量修饰符,vec4是数据类型表示四维向量,顶点坐标
attribute vec2 texCoordinate; //vec2二维向量,纹理坐标是二维纹理
uniform mat4 rotateMatrix; //uniform统一通道修饰符,mat4四行四列的矩阵,旋转矩阵
varying lowp vec2 varyTexCoord; //纹理坐标传递到片元着色器,通过varying通道传递,lowp表示低精度
void main() {
varyTexCoord = texCoordinate; //赋值后传递给片元着色器
vec4 vPos = position;
vPos = vPos * rotateMatrix; //每一个顶点与旋转矩阵相乘得到新的顶点
gl_Position = vPos; //赋值最终计算好的新顶点,gl_Position是内建变量,不需要定义只需要赋值
}
GPU并行计算顶点,三角形的3个顶点并行计算,上面的代码并行执行3次
- 图元装配
顶点着⾊器之后,下一个阶段就是图元装配,确定图形的形状.
三种图元(Primitive): 点,线,三角形.
图元装配: 将顶点数据计算成⼀个个图元.在这个阶段会执⾏裁剪、透视分割和 Viewport变换操作,这个过程开发者无法干预。
图元类型和顶点确定将被渲染的单独图元。对于每个单独图元及其对应的顶点,图元装配阶段执⾏的操作包括:将顶点着⾊器的输出值执⾏裁剪、透视分割、视⼝变换后进入光栅化阶段。
- 光栅化
确定图形在屏幕上的像素点
在这个阶段绘制对应的图元(点/线/三⻆形). 光栅化就是将图元转化成一组二维片段的过程.而这些转化的片段将由片元着⾊器处理.这些二维片段就是屏幕上可绘制的像素.
-
片元着色器
片元着色器
片元着⾊器/⽚段着⾊器:
- 着⾊器程序——描述片段上执⾏操作的片元着⾊器程序源代码/可执⾏文件
- 输入变量——由顶点着色器传递进来 ,片元着色器没有属性attribute变量。光栅化单元用插值为每个片段生成的顶点着⾊器输出
- 统一变量(uniform)——顶点/⽚元着⾊器使用的不变数据,比如旋转矩阵
- 采样器——代表片元着⾊器使⽤纹理的特殊统一变量类型.获取到纹理ID从内存中查找对应的纹理
- 片元着色器输出颜色:
片元着色器是输出颜色,通过计算颜色混合等最终输出一个像素点的颜色赋值给gl_FragColor,让对应的这一个像素点得到一种颜色
⽚元着⾊器 业务:
1、计算颜⾊
2、获取纹理值,从图片中获取对应像素点的颜色值
3、往像素点中填充颜⾊值(纹理值/颜色值);
总结: 它可以用于图片/视频/图形中每个像素的颜色填充(比如给视频添加滤镜,实际上就是将视频中每个图片的像素点颜色填充进⾏修改.)
varying lowp vec2 varyTexCoord; //从顶点着色器传过来的纹理坐标,需要与顶点着色器的定义完全一致
uniform sampler2D colorMap; //由客户端通过uniform传递过来的纹理采样器,拿到对应的纹理颜色值,取得纹素
void main() {
//texture2D(纹理采样器, 纹理坐标);获取对应位置对应坐标上的颜色值,取得纹素
gl_FragColor = texture2D(colorMap, varyTexCoord); //gl_FragColor内建变量赋值,类型是vec4四维向量
}
片元着色器执行次数跟图片像素点的个数一样,并行执行每一个像素点获取颜色,让每一个像素点得到颜色值
- 逐片段操作
片元着色器取出颜色后,进行逐片段操作
拿到片段数据之后执行像素归属测试
• 像素归属测试: 确定帧缓存区中位置(Xw,Yw)的像素目前是不是归属于OpenGL ES所有. 例如,如果一个显示OpenGL ES帧缓存区View被另外一个View 所遮蔽.则窗⼝系统可以确定被遮蔽的像素不属于OpenGL ES上下文,从而不全显示这些像素.⽽像素归属测试是OpenGL ES 的⼀部分,它不由开发者人为控制,而是由OpenGL ES 内部进⾏.
• 裁剪测试: 裁剪测试确定(Xw,Yw)是否位于作为OpenGL ES状态的⼀部分裁剪矩形范围内.如果该片段位于裁剪区域之外,则被抛弃.
• 深度测试: 输入⽚段的深度值进一步比较,确定片段是否拒绝测试
• 混合: 混合将新生成的片段颜色与保存在帧缓存的位置的颜色值组合起来.与片元着色器的颜色混合不同
• 抖动: 抖动可用于最小化因为使用有限精度在帧缓存区中保存颜色值而产生的伪像.
五、EGL(Embedded Graphics Library)
EGL介绍
• OpenGL ES 命令需要渲染上下文和绘制表面才能完成图形图像的绘制.
• 渲染上下文: 存储相关OpenGL ES 状态.
• 绘制表面: 是用于绘制图元的表面,它指定渲染所需要的缓存区类型,例如颜⾊缓存区,深度缓冲区和模板缓存区.
• OpenGL ES API 并没有提供如何创建渲染上下文或者上下文如何连接到原生窗口系统. EGL 是Khronos 渲染API(如OpenGL ES) 和原生窗口系统之间的接口. 唯一支持 OpenGL ES 却不支持EGL 的平台是iOS. Apple 提供⾃己的EGL API的iOS实现,称为EAGL.
• 因为每个窗口系统都有不同的定义,所以EGL提供基本的不透明类型—EGLDisplay, 这个类型封装了所有系统相关性,⽤于和原生窗口系统接口.
由于OpenGL ES是基于C的API,因此它非常便携且受到广泛⽀持。作为C API,它与Objective-C Cocoa Touch应用程序无缝集成。OpenGL ES规范没有定义窗口层; 相反,托管操作系统必须提供函数来创建一个接受命令的OpenGL ES 渲染上下文和一个帧缓冲区,其中写入任何绘图命令的结果。在iOS上使用OpenGL ES需要使用iOS类来设置和呈现绘图表面,并使用平台中的API来呈现其内容。
六、计算机对于动画的实现
- 两种动画:
- 关键帧动画:只计算关键信息,由计算机计算得到动画,由起始位置到终点位置计算机可以计算中间的过渡帧,包含动画时间、运动速度等的计算
- 逐帧动画:每一帧图片组合起来就是一个连贯的动画
-
CADisplayLink定时器,以屏幕的刷新率作为定时器,将特定的runloop mode加到runloop中,以iOS的刷新频率结束来结束调用,精度较高,NSTimer精度较低。UI的渲染、一些动画的实现都可以使用CADisplayLink。CADisplayLink可以得到上一帧的时间戳、两个帧之间的间隔,可以设置每秒的帧数、是否暂停等,但是不能够被继承!!!
-
理解动画循环(渲染循环)
动画循环
1、GLKit是Apple基于OpenGL ES 封装的一套框架,方便iOS开发者使用OpenGL ES,简单的需求可以是哟GLKit实现
2、GLKView继承于UIView,其中的两个方法Update方法和Display方法介绍
- Update方法用于更新,图中Update方法中计算旋转度数,设置旋转度数和围绕的xyz轴得到旋转矩阵
- Display方法用于显示,图中Display方法将得到的旋转矩阵通过uniform通道传递到顶点着色器/片元着色器,然后进行绘制
-
OpenGL ES显示器执行动画的应用程序流程
OpenGL ES显示器执行动画的应用程序流程
1、创建一个静态资源
2、循环:
- 更新动态资源
- 执行渲染命令
- 读取结果
3、屏幕显示,显示和循环一直在不停的执行
4、释放资源