opengl es是什么?
opengl 是一个跨平台(不同的GPU类型,如电脑端NVIDIA,Intel,AMD的显卡,手机端PowerVR(苹果系列), Adreno(高通,安卓系列)等等)、跨编程语言(各个编程语言java,C,OC,js等等都有opengl的接口)的图形图像处理接口,opengl本身只是一组api接口规范,具体的实现一般是由具体的显卡(GPU)设备生产商编码实现的,比如苹果手机是由apple实现的,Linux系统则是由各个显卡生产商通过驱动程序导入的。
opengl es是opengl的一个子集,是专门用来针对手机,平板电脑等嵌入式设备的图形图像处理接口,接口设计中不涉及上下文环境和窗口的管理,这由各个平台自行实现。比如ios就是EAGL;安卓就是EGL;
tips:
libSDL是一个跨平台的图形处理库,其中有包含对opengl es的标准接口的封装及各个平台上下文,窗口管理的封装。
备注:opengl es 2.0 官方接口文档 https://www.khronos.org/registry/OpenGL-Refpages/es2.0/
基础概念
- 应用端:
即我们自己的程序端,相对于opengl es,我们属于应用端 - 图元:
要渲染的几何物体,或者形状。比如要渲染一个正方形的图片,就是一个图元,要渲染两条直线,这两条直线也是图元 - 纹理:
通俗点,可以理解为一张图片,在opengl es中纹理就是图片的另外一种叫法 - 纹素:
纹理的基础单元,也就是像素 - 顶点数组
顶点指的是组成图元的各个顶点的坐标数据(在3D笛卡尔坐标中即x,y,z坐标),这些坐标数据可以一起存到一个内存数组中,这个数组就叫做顶点数组 - 顶点缓冲区
在显存中专门分配一块显存来存储这个顶点数组,这个显存就称为顶点缓冲区 - 顶点着色器
顶点着⾊器(简称为VS)是opengl es中⽤于计算图形顶点属性(包括顶点坐标归一化、顶点光照运算等等)的程序。顶点着色器是逐顶点运算的程序,也就是说每个顶点数据都会执行⼀次顶点着⾊器,当然这是并行的 - 片元着色器
片元着色器(简称为PS)用来决定要渲染图形的每个像素的颜色的程序,它也是并行计算的
opengl es渲染管线
渲染管线也就是opengl es的工作流程,这里是opengl es2.0以后的版本的渲染管线
- 1、opengl es接收API的输入
通过 API 设定顶点的信息(一般包括顶点坐标,纹理坐标,颜色,变换矩阵等等),一般由顶点着色器接收这些信息作为输入 - 2、顶点着色器处理顶点坐标
前一阶段的输入将在 VS 中进行运算,以得到最终的顶点坐标。 - 3、图元装配
将顶点着色器计算出的最终顶点坐标进行图元装配,构建出最终想要渲染的图形。所有要渲染的图形都可以由三个基本的图元(点、线、三角形)组成,比如正方形或者长方形,就可以由两个三角形组成,圆形可以由无数个三角形组成,只是三角形的数量越多,圆形看上去越圆润 - 4、光栅化
通过计算,将要渲染的图形上所有的像素点找到,并根据插值或者其他方式计算出其颜色等信息的过程 - 5、片元着色器计算像素颜色
光栅化得到了要渲染图形的所有像素的信息,这些信息作为片元着色器的输入,那么在片元着色器中将计算像素颜色 - 6、像素处理
片元着色器计算的像素颜色还不是最终要渲染的颜色,这一步骤还包括Alpha Test、Depth/Stencil Test、Blend、Dither等几个步骤,经过这几个步骤后得到的就是最终的渲染颜色
备注:以上所有的操作都是并行处理
opengl es的相关坐标系
opengl es的坐标系原点位于要渲染区域的中心点,向右和向上分别为x轴和y轴的正向轴,取值范围为(-1,1)
如下为正确渲染一张图片为例传递顶点坐标
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 中,通常将纹理中的像素根据纹理坐标系来进行编址,纹理坐标系的横轴成为S轴,纵轴成为T轴,垂直于ST轴的成为R轴,在2D纹理中,没有
R轴,横轴和纵轴又称为UV轴,所以2D纹理坐标系又称为UV坐标系,UV轴的取值范围都是(0,1)。与OpenGL 坐标系不同的是,纹理坐标系的原点位于左
上角
如下为正确渲染一张图片为例传递纹理坐标:
static float uvData[8] = {
0.0f, 1.0f,// 左下角
1.0f, 1.0f, // 右下角
0.0f, 0.0f,// 左上角
1.0f, 0.0f, // 右上角
};
纹理坐标系一般不要去改变它的值,传这个就好,(当然也可该,前提是知道内部的转换原理),如果要实现压缩和裁剪效果,改变几何坐标系方便一些。设定opengl es渲染区域
glViewPort(x,y,w,h) 函数窗口创建的渲染区域
它以左下角作为原点的坐标系
此函数的意思就是,基于当前视图左下角作为原点的坐标系,选取一个左下角坐标为x,y,长宽为w,h的区域作为渲染的区域
纹理映射
1、缩放
纹理的映射就是让物体的每个片元(每个颜色像素)都找到对应的纹理纹素点,在这个映射过程中,因为纹理和物体的不匹配,一般会出现两种情况
第一种是拥有大量纹素的纹理被映射到只还有少量片元的物体中
第二种是拥有少量纹素的纹理被映射到含有大量片元的物体中
如下:
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);2、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绑定
opengl es api和EGL api
opengl es api是用来进行图像渲染操作的,
egl api是由各个操作系统实现的系统api,它主要的作用就是创建窗口,创建opengl 上下文环境等。可以由各自厂商自行定义,使用通用的EGL接口。
如苹果就是EAGL,安卓就可以用EGL来自行管理,也可以用GLSurface系统创建opengl 环境