Opengl es是什么?
opengl 是一个跨平台、跨编程语言的图形处理接口,opengl es是它的一个子集,专门用来针对手机,平板电脑等嵌入式设备的图像处理库。对于手机来说,它的所有对图像的计算和渲染都是在gpu上完成,所以具有较好的性能
opengl es的接口设计中不涉及上下文环境和窗口的管理,这由各个平台自行实现。比如ios就是EAGL;安卓就是EGL;
.tips:
libSDL,它是一个跨平台的图形处理库,其中有包含对对OpenGL es的标准接口的封装及各个平台上下文,窗口管理的封装。
备注:Opengl es 2.0 官方接口文档 https://www.khronos.org/registry/OpenGL-Refpages/es2.0/
opengl es系列文章
opengl es之-基础概念(一)
opengl es之-GLSL语言(二)
opengl es之-GLSL语言(三)
opengl es之-常用函数介绍(四)
opengl es之-渲染两张图片(五)
opengl es之-在图片上添加对角线(六)
opengl es之-离屏渲染简介(七)
opengl es之-CVOpenGLESTextureCache介绍(八)
opengl es之-播放YUV文件(九)
基础概念
应用端:即我们自己的程序端,相对于opengl es,我们属于应用端
图元:要渲染的几何物体,或者形状。比如要渲染一个正方形的图片,就是一个图元,要渲染两条直线,这两条直线也是图元
纹理:通俗点,可以把它想象成一堆像素构成的区域
纹素:纹理的基础单元,也就是像素
Opengl es渲染管线
这里是opengl es2.0以后的版本的渲染管线
1、确定几何形状,比如是要点,线,还是三角形(长方形,正方形和其它二维几何图形都是由三角形来渲染的)。
它最终由glDrawArrays()函数的调用来确定,其第一个参数确定了形状可取值如下:
GL_POINTS:绘制点
GL_LINES:线
GL_TRIANGLE_STRIP:三角形
2、处理顶点坐标
此阶段需要顶点着色器的参与,首先由应用端传递给顶点着色器几何图形的坐标,纹理的坐标(如果有的话);然后根据opengl es内部的坐标系和投影矩阵进行转化
成最终的坐标;在这一步中,应用端需要知道的是基于(左下角为原点(-1,-1),右上角(1,1),这个范围就是前面glViewPort()开辟大小)的坐标系来确定几何图形的坐标
;基于(左上角为原点(0,0),右下角(1,1))的坐标系来确定纹理的坐标,但是纹理坐标要上下翻转180度后在与几何坐标顺序一直传递
tips:
常用的就是渲染图片,所以图片都是矩形,所以传递的几何坐标如下:
static float verData1[8] = {
-1.0f, -1.0f, // 左下角
1.0f,-1.0f, // 右下角
-1.0f,1.0f, // 左上角
1.0f,1.0f, // 右上角
};
一般按照如上的顺序传递坐标,取值也可以是其它值,比如
static float verData1[8] = {
-0.5f, -0.5f, // 左下角
0.5f,-0.5f, // 右下角
-0.5f,0.5f, // 左上角
0.5f,0.5f, // 右上角
};
表示取中间的1/2区域;实际上就是压缩效果
static float verData1[8] = {
-2.0f, -2.0f, // 左下角
2.0f,-2.0f, // 右下角
-2.0f,2.0f, // 左上角
2.0f,2.0f, // 右上角
};
表示将原来的坐标系放大了一倍后在基于原始的进行截取
传递的纹理坐标系(OpenGL es纹理坐标系左上角为原点(0,0),右下角为(1,1)与几何坐标系上下刚好翻转180度)如下:
static float uvData[8] = {
0.0f, 1.0f,// 左下角
1.0f, 1.0f, // 右下角
0.0f, 0.0f,// 左上角
1.0f, 0.0f, // 右上角
};
纹理坐标系一般不要去改变它的值,传这个就好,(当然也可该,前提是知道内部的转换原理),如果要实现压缩和裁剪效果,改变几何坐标系方便一些。
3、图元组装
经过阶段二的顶点处理操作之后,不论模型的顶点还是纹理坐标都已经确定,这个阶段,顶点将会应用程序的指令规则比如glDrawArrays()函数确定的(如
GL_POINTS,GL_LINES,GL_TRIANGES等),将根据这些顶点坐标描绘出具体的图元(比如最终要渲染成一个矩形图元)
4、栅格化操作
由阶段3传递过来的图元,将在此阶段被分解成更小的单元并对应于帧缓冲区的各个像素,这些单元成为片元,一个片元包含颜色,坐标等属性。片元的坐标属性
根据顶点坐标利用插值运算确定,这个过程称为栅格化操作。该阶段只是确定了每个片元的坐标属性,颜色由下阶段通过片元着色器确定。
5、片元处理
上阶段确定了各个片元的坐标,此阶段将通过片段着色器GLSL语言确定各个片元的颜色。比如可以通过纹理坐标获取纹理中对应片元坐标的颜色,如果应用端传进来的纹理大小和要绘制的几何图形大小不一样,那么opengles会根据应用自己设置的缩放规则(比如用glTexParameteri()函数指定的规则)进行插值运算来获取到对应
的颜色)如果没有纹理,可以根据自己的代码规则确定片元颜色;这个过程就是给GLSL的内建变量gl_FragColor赋值
6、帧缓存操作
该阶段主要指向帧缓冲的写入操作,负责将最终的像素值写入帧缓冲区中。
光栅化
前面就是opengl es标准的渲染管线,但是要想将图像最终呈现到屏幕上,还需要进行光栅化操作(也就是将帧缓冲区中的像素数据渲染到屏幕上),而
这这一步的实现是由各个设备供应商提供的,称为Opengl EGL API,拿苹果ios的例子来说,需要调用EAGLContext 的presentRenderbuffer函数,图
像才会最终渲染到屏幕上;
opengl es api和EGL api
opengl es api是用来进行图像渲染操作的,
egl api是由各个操作系统实现的系统api,它主要的作用就是创建窗口,创建opengl 上下文环境等。可以由各自厂商自行定义,使用通用的EGL接口。
如苹果就是EAGL,安卓就可以用EGL来自行管理,也可以用GLSurface系统创建opengl 环境
opengl es坐标系
1、它以左下角作为原点的坐标系
此函数的意思就是,基于当前视图左下角作为原点的坐标系,选取一个左下角坐标为x,y,长宽为w,h的区域作为渲染的区域
glViewPort(x,y,w,h) 函数窗口创建的渲染区域
纹理坐标系
在opengl 中,通常将纹理中的像素根据纹理坐标系来进行编址,纹理坐标系的横轴成为S轴,纵轴成为T轴,垂直于ST轴的成为R轴,在2D纹理中,没有
R轴,横轴和纵轴又称为UV轴,所以2D纹理坐标系又称为UV坐标系,UV轴的取值范围都是(0,1)。与OpenGL 坐标系不同的是,纹理坐标系的原点位于左
上角
纹素
纹理中的最小单元就成为纹素,纹理是由一个个纹素组成
纹理映射
纹理的映射就是让物体的每个片元(每个颜色像素)都找到对应的纹理纹素点,在这个映射过程中,因为纹理和物体的不匹配,势必会出现两种情况。
第一种是拥有大量纹素的纹理被映射到只还有少量片元的物体中
第二种是拥有少量纹素的纹理被映射到含有大量片元的物体中
如下:
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
GL_TEXTURE_MIN_FILTER:
是多个纹素对应一个片元的解决方案。可以设置两个值,GL_NEAREST 和 GL_LINEAR ,这两个值分别对应了两种不同的解决方案。GL_LINEAR 会混合匹配的颜色来得到片元的颜色,产生的颜色可能是纹理中不存在的颜色。例如一个纹理是由交替的黑色和白色的纹素组成,那个线性取样会使最终的片元颜色为灰色。GL_NEAREST 会拾取与片元 U,V 坐标最相近的颜色。
GL_TEXTURE_MAG_FILTER:
是没有足够的纹素来映射片元的解决方案。可以设置的值同 GL_TEXTURE_MIN_FILTER 一样。GL_LINEAR 会告诉OpenGL ES 混合附近纹素的颜色来计算片元的颜色。GL_LINEAR会有一个放大纹理的效果,当没有足够的纹素来映射片元时,会让纹理模糊的出现在要渲染的图形上。
GL_NEAREST 仅仅会拾取片元的 U ,V 位置接近的纹素的颜色,并放大纹理,会使其像素化的出现在要渲染的图形上。
GL_LINEAR:
线性插值,取最近的点的线性平均值 (性能消耗较大)
mipmaps
它也是一种纹理过滤算法,按我的理解它是以空间换时间的一种技巧,具体原理就是事先根据纹理生成长和宽逐渐除以2的小纹理,比如原始纹理大小128x128,
采用此方法后,会生成64x64 32x32 16x16 8x8 4x4 2x2 1x1的一系列纹理,如果需要20x18的纹理,则取最近的32x32 16x16进行平均
该方法很好的解决了如下问题:
1、当纹理很大,但是屏幕区域很小,渲染出现的闪烁问题,因为根据最邻近插值和线性插值都无法很快计算出合理的像素
它可以取的值如下:
GL_NEAREST_MIPMAP_NEAREST 选择最近的mipmap层,然后再用最邻近过滤插值
GL_LINEAR_MIPMAP_NEAREST 选择最近mipmap层,然后再用线性插值
GL_NEAREST_MIPMAP_LINEAR 选择最近的2层mipmap用最邻近过滤插值
GL_LINEAR_MIPMAP_LINEAR 选择最邻近的2层mipmap用线性插值
使用如下函数生成mipmaps
glGenerateMipmap(GLenum target);
warp
另外一种在映射时可能出现的情况是纹理的四个顶点坐标不是1.0时,将采用如下方式:
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_WARP_S,GL_REPEAT) S轴方向
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_WARP_T,GL_REPEAT) T轴方向
GL_REPEAT:纹理没有覆盖的部分重复之前的纹理,当纹理大小大于物体大小时,纹理采样会出错。
GL_MIRRODED_REPEAT:将原来的纹理先颠倒再重复,当纹理大小大于物体大小时,纹理采样会出错。
GL_CLAMP_TO_EDGE:延续结束时的纹理
顶点着色器中顶点坐标的顺序规则
open gl 中顶点坐标
static float verData1[8] = {
-1.0f,-1.0f, // 左下角
1.0f,-1.0f, // 右下角
-1.0f,1.0f, // 左上角
1.0f,1.0f, // 右上角
};
对应的纹理坐标
static float uvData[8] = {
0.0f, 1.0f, // 左下角
1.0f, 1.0f, // 右下角
0.0f, 0.0f, // 左上角
1.0f, 0.0f, // 右上角
};
对应的为glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 可以渲染出一张图片
VBO
GPU中专门开辟的一块内存用于存储图元的顶点数据,这样每次调用glDrawArrays()函数时,GLSL就是直接从GPU中获取
顶点数据,而不是每次都有cpu拷贝到GPU(cpu拷贝到gpu肯定效率不如直接从GPU中取),这样对于顶点数据比较多时,
可以加快效率;
FBO
帧缓冲,也就是通过glGenFramebuffers()函数生成的对象,它主要用于存储opengl es最终的渲染结果。
离屏渲染
当需要对纹理进行多次渲染采样时(也就是对一个纹理进行多个着色器程序去处理),而这些渲染采样中间过程是不需要
展示给用户看的,所以就可以额外创建一个FBO对象来专门做这个事情,这个FPO对象就成为为离屏渲染帧缓冲,这个
过程叫做离屏渲染
渲染缓冲区
通过glGenRenderbuffers()生成的缓冲区,他用于将渲染的结果呈现到屏幕上,需要与FBO绑定