Android OpenGL ES(一)开发入门

作者: 王英豪 | 来源:发表于2019-06-09 15:27 被阅读25次

早就听过大名鼎鼎的 OpenGL,却迟迟没有实践学习,有些惭愧。今天开始通过实践+博文方式学习掌握 OpenGL。此文对于 OpenGL 的学习分为以下部分:

  • OpenGL 基础概念
  • OpenGL 坐标系理解
  • OpenGL 渲染管线
  • OpenGL 着色语言

OpenGL 基础概念

OpenGL

OpenGL 即 Open Graphics Library,是一个功能强大、调用方便的底层图形库,它定义了跨编程语言、跨平台的专业图形程序接口,可用于二维或三维图像的处理与渲染。

OpenGL 是跨平台的,除了它纯粹专注的渲染外,其他内容在每个平台上都要有它的具体实现,比如上下文环境和窗口的管理就交由各个设备自己来完成。

OpenGL ES

OpenGL ES (OpenGL for Embedded Systems)是三维图形 API OpenGL 的子集,针对手机、PDA 和游戏主机等嵌入式设备而设计。

Android 对应 OpenGL ES 的版本支持如下:

  • Android 1.0 开始支持 OpenGL ES 1.0 及 1.1
  • Android 2.2 开始支持 OpenGL ES 2.0
  • Android 4.3 开始支持 OpenGL ES 3.0
  • Android 5.0 开始支持 OpenGL ES 3.1

其中 OpenGL ES 1.0 是以 OpenGL 1.3 规范为基础的,OpenGL ES 1.1 是以 OpenGL 1.5 规范为基础的,而 OpenGL ES 2.0 基于 OpenGL 2.0 实现。2.x 版本相比 1.x 版本有较大差异,1.x 版本为 fixed function pipeline,即固定管线硬件,而 2.x 版本为 programmable pipeline,可编程管线硬件。

固定管线中原本由系统做的一部分工作,在可编程管线中必须需要自己写程序实现,具体程序为 vertex shader(顶点着色器)和 fragment shader(片元着色器)。

OpenGL 上下文

OpenGL 是一个仅仅关注图像渲染的图像接口库,在渲染过程中它需要将顶点信息、纹理信息、编译好的着色器等渲染状态信息存储起来,而存储这些信息的数据结构就可以看作 OpenGL 的上下文。

调用任何 OpenGL 函数前,必须已经创建了 OpenGL Context,GL Context 存储了OpenGL 的状态变量以及其他渲染有关的信息。OpenGL 是个状态机,有很多状态变量,是个标准的过程式操作过程,改变状态会影响后续所有操作,这和面向对象的解耦原则不符,毕竟渲染本身就是个复杂的过程。OpenGL 采用 Client-Server 模型来解释 OpenGL 程序,即 Server 存储 GL Context(可能不止一个),Client 提出渲染请求,Server 给予响应,一般 Server 和 Client 都在我们的 PC 上,但 Server 和 Client 也可以是通过网络连接。

之后的渲染工作就要依赖这些渲染状态信息来完成,当一个上下文被销毁时,它所对应的 OpenGL 渲染工作也将结束。

OpenGL 纹理

纹理(Texture)是一个 2D 图片(甚至也有 1D 和 3D 的纹理),它可以用来添加物体的细节;你可以想象纹理是一张绘有砖块的纸,无缝折叠贴合到你的 3D 的房子上,这样你的房子看起来就像有砖墙外表了。因为我们可以在一张图片上插入非常多的细节,这样就可以让物体非常精细而不用指定额外的顶点。

OpenGL 坐标系理解

  • 1. 世界坐标
    世界坐标系以屏幕中心为原点 (0, 0, 0)。你面对屏幕,你的右边是 x 正轴,上面是 y 正轴,屏幕指向你的为 z 正轴。长度单位这样来定: 窗口范围按此单位恰好是 (-1,-1) 到 (1,1) 。
  • 2. 物体坐标
    物体坐标是以物体某一点为原点而建立的“世界坐标”,该坐标系仅对该物体适用,用来简化对物体各部分坐标的描述。物体放到场景中时,各部分经历的坐标变换相同,相对位置不变。
  • 3. 眼坐标
    以视点为原点,以视线的方向为 Z+ 轴正方向的坐标系中的方向。OpenGL 管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视见体)之内的场景才会进入下一阶段的计算。
  • 4. 裁剪坐标
    由眼坐标可知,OpenGL 管道首先会将目标从世界坐标变换到眼坐标,然后对视线范围外的部分进行裁剪。 裁剪过程中用到投影变换矩阵栈(ProjectionMatrix),栈顶矩阵就是当前投影变换矩阵,负责将场景各坐标变换到眼坐标,由所得到的结果是裁剪后的场景部分,称为裁剪坐标。

OpenGL 渲染管线

OpenGL 渲染管线流程为:顶点数据 -> 顶点着色器 -> 图元装配 -> 几何着色器 -> 光栅化 -> 片段着色器 -> 逐片段处理 -> 帧缓冲

OpenGL 渲染管线的流程其实就是 OpenGL 引擎渲染图像的流程,也就是说 OpenGL 引擎一步一步的将图片渲染到屏幕上的过程,渲染管线可以分为以下几个阶段:

  • 1. 指定几何对象
    首先要了解几何图元的概念,几何图元就是点、直线、三角线等几何对象,在提供了顶点坐标后,还要确定具体要画的是点、线段还是三角形,这就要确定具体执行的绘制指令。比如 OpenGL 提供给开发者的绘制方法 glDrawArrays,这个方法的第一个参数就是指定绘制方式,可选值有:
    GL_POINTS:以点的形式进行绘制,通常用在绘制粒子效果的场景。
    GL_LINES:以线的形式进行绘制,通常用于绘制直线的场景。
    GL_TRIANGLE_STRIP:以三角形的形式进行绘制,所有二维图像的渲染都会使用这种方式。
    具体选用哪一种绘制方式决定了 OpenGL 渲染管线的第一阶段应如何去绘制几何图元,这就是第一阶段指定几何对象。

  • 2. 顶点处理
    不论上面的几何图元是如何指定的,所有的几何数据都将会通过这个阶段。这个阶段的操作内容有:根据模型视图(即根据几何图元创建的物体)和投影矩阵进行变换来改变顶点的位置,根据纹理坐标与纹理矩阵来改变纹理坐标的位置,如果设计三维的渲染,还要处理光照计算和法线变换。
    关键的操作就是顶点坐标变换及光照处理,每个顶点是分别单独处理的。这个阶段所接受的数据是每个顶点的属性特征,输出的则是变换后的顶点数据。

  • 3. 图元组装
    在顶点处理之后,顶点的全部属性都已经被确定。在这个阶段顶点将会根据应用程序设定的图元规则如 GL_POINTS 、GL_TRIANGLES(三角形) 等被组装成图元。

  • 4. 珊格化操作
    在图元组装后会传递过来图元数据,到目前为止,这些图元信息还只是顶点而已:顶点处都还没有“像素点”、直线段端点之间是空的、多边形的边和内部也是空的,光栅化的任务就是构造这些。
    这个阶段会将图元数据分解成更小的单元并对应于帧缓冲区的各个像素,这些单元称为片元,一个片元可能包含窗口颜色、纹理坐标等属性。片元的属性则是图元上的顶点数据等经过插值而确定的,这就是珊格化操作,也就是确定好每一个片元是什么。

  • 5. 片元处理
    珊格化操作构造了像素点,这个阶段就是处理这些像素点,根据自己的业务处理(比如提亮、饱和度调节、对比度调节、高斯模糊等)来变换这个片元的颜色。

  • 6. 逐片段处理
    进行剪切、Alpha 测试、 模版测试、深度测试、混合等处理,这些操作将会最后影响其在帧缓冲区的颜色值。

  • 7. 帧缓冲操作
    此阶段主要执行帧缓冲的写入操作,也是渲染管线的最后一步,负责将最终的像素点写到帧缓冲区。

上面提到 OpenGL ES 2.0 版本相比之前版本,提供了可编程的着色器来代替 1.x 版本渲染管线的某些阶段,具体为:

  • Vertex Shader(顶点着色器)用于替换顶点处理阶段
  • Fragment Shader(片元着色器)用于替换片元处理阶段

OpenGL 着色语言

OpenGL 着色语言 GLSL 全称为 OpenGL Shading Language,是为了实现着色器的功能而向开发人员提供的一种开发语言,语法与 C 语言类似,下面分为以下几点来学习 GLSL:

  • 1. 基本数据类型

void:空类型,即不返回任何值
bool:布尔类型,true/false
int:带符号的整数,signed integer
float:带符号的浮点数,signed scalar
vec2、vec3、vec4:n-维浮点数向量
bvec2、bvec3、bvec4:n-维布尔向量
ivec2、ivec3、ivec4:n-维整数向量
mat2、mat3、mat4:2x2、3x3、4x4 浮点数矩阵
sampler2D:2D 纹理
samplerCube:盒纹理

其中 float 可指定精度:

high:32bit,一般用于顶点坐标(vertex Coordinate)
medium:16bit,一般用于纹理坐标(texture Coordinate)
low:8bit,一般用于颜色表示(color)

  • 2. 变量修饰符

none:(默认的可省略)本地变量,可读可写,函数的输入参数既是这种类型
const:声明变量或函数的参数为只读类型
attribute:用于保存顶点或法线数据,它可以在数据缓冲区中读取数据,仅能用于顶点着色器
uniform:在运行时 shader 无法改变 uniform 变量,一般用来放置程序传递给 shader 的变换矩阵,材质,光照参数等等,可用于顶点着色器和片元着色器
varying:用于修饰从顶点着色器向片元着色器传递的变量

要注意全局变量限制符只能为 const、attribute、uniform 和 varying 中的某一个,不可复合。

  • 3. 内置变量
    GLSL 程序使用一些特殊的内置变量与硬件进行沟通,他们大致分成两种,一种是 input 类型,他负责向硬件(渲染管线)发送数据;另一种是 output 类型,负责向程序回传数据,以便编程时需要。
    顶点着色器中 output 类型的内置变量如下:

highp vec4 gl_Position:放置顶点坐标信息
mediump float gl_PointSize:需要绘制点的大小,(只在gl.POINTS模式下有效)

片元着色器中 input 类型的内置变量如下:

mediump vec4 gl_FragCoord;:片元在 framebuffer 画面的相对位置
bool gl_FrontFacing:标志当前图元是不是正面图元的一部分
mediump vec2 gl_PointCoord:经过插值计算后的纹理坐标,点的范围是0.0到1.0

片元着色器中 output 类型的内置变量如下:

mediump vec4 gl_FragColor:设置当前片点的颜色
mediump vec4 gl_FragData[n]:设置当前片点的颜色,使用glDrawBuffers数据数组

  • 4. 内置常量
    GLSL 提供了一些内置的常量,用来说明当前系统的一些特性。有时我们需要针对这些特性,对 shader 程序进行优化,让程序兼容度更好。

顶点着色器中的内置常量如下:

const mediump int gl_MaxVertexAttribs >= 8:顶点着色器中可用的最大 attributes 数
const mediump int gl_MaxVertexUniformVectors >= 128:顶点着色器中可用的最大 uniform vectors 数
const mediump int gl_MaxVaryingVectors >= 8:顶点着色器中可用的最大 varying vectors 数
const mediump int gl_MaxVertexTextureImageUnits >= 0:顶点着色器中可用的最大纹理单元数
const mediump int gl_MaxCombinedTextureImageUnits >= 8:表示最多支持多少个纹理单元

片元着色器中的内置常量如下:

const mediump int gl_MaxTextureImageUnits >= 8:片元着色器中能访问的最大纹理单元数
const mediump int gl_MaxFragmentUniformVectors >= 16:片元着色器中可用的最大 uniform vectors 数
const mediump int gl_MaxDrawBuffers = 1:表示可用的 drawBuffers 数,在 OpenGL ES 2.0 中这个值为 1, 在将来的版本可能会有所变化

上面这些值的大小取决于 OpenGL ES 在某设备上的具体实现。

  • 5. 内置函数

通用函数:abs、floor、min、max 等,参数可传入 float/vec2/vec3/vec4 类型
角度函数:sin、cos 等,参数可传入 float/vec2/vec3/vec4 类型
指数函数:pow、log 等,参数可传入 float/vec2/vec3/vec4 类型
几何函数:distance、dot 等,参数可传入 float/vec2/vec3/vec4 类型
矩阵函数:matrixCompMult,参数传入 mat 类型
向量函数:lessThan、equal 等,参数可传入 vec2/vec3/vec4 类型
纹理函数:texture2D、texture2DProj 等

更详细的内置函数介绍可去官方文档查看,在此只简单列一下大致种类。

参考文章:

《音视频开发进阶指南 - 基于Android与IOS平台的实践》
OpenGL 百度百科
OpenGL Context(渲染上下文)
OpenGL ES 百度百科
在Android中使用OpenGL ES进行开发第(一)节:概念先行
初学OpenGL(4):纹理
OpenGL各坐标系及模型矩阵、投影矩阵等的深入理解
OpenGL管线(用经典管线代说着色器内部)
OpenGL shader GLSL 中文手册

相关文章

网友评论

    本文标题:Android OpenGL ES(一)开发入门

    本文链接:https://www.haomeiwen.com/subject/rhcwxctx.html