在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline,大多译为管线,实际上指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程)管理的。图形渲染管线可以被划分为两个主要部分:第一部分把你的3D坐标转换为2D坐标,第二部分是把2D坐标转变为实际的有颜色的像素。
渲染管线包括:
灰色部分是GPU自动处理的,不需要我们额外处理,我们主要关注顶点着色器vertex shader和片段着色器fragment shader,他们是通过GLSL语言编写的编译运行在GPU上的小型程序。
1、首先想绘制一个物体,我们需要让计算机知道它的外形形状,这一步是通过顶点着色器决定的。计算机绘制图形是通过绘制无数个三角形而实现的,比如:绘制一个正方形是通过绘制2个三角形实现,绘制圆形是通过绘制很多个三角形实现:
假如我们要绘制一个正方形,如何通过顶点着色器告诉计算机我要绘制一个四边形呢?
我们知道正方形有4个顶点,分解成2个三角形 就是6个顶点,那么我们只需要告诉着色器这6个顶点的坐标,就可以确定它的形状了。
首先定义一个顶点数组,然后我们将这个数组传递给GPU,那么GPU就知道如何绘制一个四边形了。
上面着色器代码用了一个小技巧,因为我们是2D图形,所以,position vec4表示z轴和时间的z、w是无意义的,这里使用z、w传入了纹理的坐标
通过glVertexAttribPointer(0, 4, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(MemoryLayout.size * 4), UnsafeRawPointer(bitPattern: 0))函数,将顶点数组赋值给vertex,
这样我们就得到了一个没有颜色的四边形。
有了形状,还需要将纹理的颜色贴到我们绘制的四边形上,这部分属于片段着色器的工作:
如何将纹理贴到四边形上呢?
我们只需要将四边形对应的纹理坐标告诉GPU,那么它通过坐标去取对应位置的纹理颜色,然后赋值给四边形,那么, 这样就绘制出了一个带纹理的四边形。
在片段着色器中我们定义了一个sample2D的纹理变量,通过给他赋值纹理数据,定义了TexCoords纹理坐标,texture函数是从纹理中取出对应坐标的颜色,然后输出,搞定!
在ios中使用opengl es 3.0 绘制一张图片:
1、初始化opengl es 3.0接口,获取上下文
2、创建FBO 、RBO(帧缓冲和渲染缓冲)
这个就是离屏渲染的缓冲区,在缓冲区绘制好之后直接渲染到屏幕上,避免卡顿
frameBuffer只是一个提供渲染附着点的对象,本身并不存储实际的渲染缓存,真正开辟内存的是renderBuffer或者纹理附件
glgen函数创建缓冲
bind函数将缓冲对象绑定为当前对应的缓冲
glFramebufferRenderbuffer将渲染缓冲附着到帧缓冲上
3、加载、编译着色器
将写好的顶点着色器代码和片段着色器代码加载,编译,链接运行:
glCreateProgram创建着色器程序链接对象
glCreateShader创建着色器对象
glShaderSource加载着色器源码
glCompileShader编译着色器
glAttachShader将着色器附着到链接程序program上
glLinkProgram链接
glGetProgramiv编译program,GL_FALSE表示失败,输出错误信息
若运行成功则调用glUseProgram使用该着色器程序
4、设置视口viewport
用指定的颜色清洗屏幕
然后设置视口大小,视口即你在设备上能够看到的显示区域
5、更新顶点信息
glGetAttribLocation 获取着色器中给定名称的变量句柄
glEnableVertexAttribArray 默认着色器中的属性是不启用的,所以需要先开启
glVertexAttribPointer给属性赋值,该函数比较重要,有专门的文档介绍该函数的参数和用法。
6、开始渲染
这样,在屏幕上我们就得到了一个我们定义的顶点的三角形。
如何将纹理(图片)显示到这个三角形/四边形中呢?
我们可以在更新顶点信息这一步中添加下面代码:
这样就将纹理坐标和一张纹理图片转化为二进制数据并传递给了片段着色器中,ShaderHelper是我封装的一个加载纹理的工具类,具体在纹理篇中给大家分析源码。
至此,我们就完成了将一个简单的纹理图片渲染到屏幕上。