OpenGL ES 2.0 Quick Start

作者:禅与计算机程序设计艺术

1.简介

Opengl(Open Graphics Library)是一个用于渲染二维图像、视频和用户界面图形的跨平台API。近年来随着移动设备的广泛普及和物联网(Internet of Things)领域的兴起,Opengl成为了开发高性能、跨平台的图形应用的首选方案。而在移动设备上绘制高质量的游戏画面一直是困难重重的。因此,Opengl ES(Embedded Systems),也就是专门为嵌入式系统设计的Opengl API被设计出来。

而作为一名具有多年编程经验的CTO,虽然对计算机图形学不是很熟悉,但是我却非常喜欢看书,特别是相关领域的技术书籍,如OpenGL Programming Guide (The official guide to learning OpenGl programming and developing high performance graphics applications with it),这本书提供了非常详实的基础知识和教程,并且作者也经过了多年的积累,通过不断学习和总结,帮助读者更好的理解Opengl。

基于此,本文将以阅读《OpenGL Programming Guide》这本书作为切入点,尝试从基础知识到实现高性能的跨平台游戏渲染程序的完整流程,分享如何用Opengl ES 2.0进行游戏渲染,并带领读者一步步掌握Opengl的使用方法和优化技巧,最终达到提升游戏渲染效率的目的。

首先,让我们先回顾一下OpenGL的历史:

1992年,Khronos公司为了推动科研和应用的创新,邀请Wilkinson、Carver、Kovac、Heitz等人合作发明了OpenGL API。它定义了一系列规范,包括图形处理管线、光照模型、纹理映射等方面的标准化接口,并提供了跨平台的底层实现。

1994年,经过几年的发展,1.1版的OpenGL成为最初的发布版本。1.1版提供了少量的功能,主要是提供了立方体对象、纹理映射、光照模型、几何变换和顶点数组对象的支持。

1997年,正式发布了2.0版的OpenGL。2.0版继承了1.1版所有的特性,并添加了向量、矩阵和着色器语言的支持。同时,它引入了虚拟机并允许开发者在运行时编译和链接着色器程序。

2008年,又发布了OpenGL 3.0版,该版本在保持OpenGL 2.0的所有特性的基础上,新增了对异构计算(Heterogeneous Computing)的支持,以及对3D文本uring和Vertex Buffer Object等新的特性的支持。

从这些年的发展中可以看到,OpenGL已经走过了快速发展的时期,并且目前的版本也是OpenGL 4.3。而与此同时,Opengl ES则由ARM公司推出,它是一种专门为嵌入式设备设计的API,其历史更长,有20多年的历史。但它的定位就比较特殊一些,只提供一小部分OpenGL的功能,并针对性能做了许多优化。

综合而言,Opengl拥有跨平台、高性能的优点,而Opengl ES则定位于嵌入式系统,对于游戏渲染来说,尤其重要。因此,了解OpenGL ES 2.0的工作原理,以及如何利用它进行游戏渲染,无疑会对我们有所帮助。

2.基本概念术语说明

2.1 Opengl的抽象结构

Opengl是一个跨平台的3D图形渲染库,它的基本单元是叫做“渲染目标”(Render Target)的东西,它封装了GPU硬件中渲染所需的所有资源。一个渲染目标包括了一块内存,里面存储了颜色值、法线、位置、纹理坐标、深度值等数据。渲染目标之间可以互相共享,也可以不同渲染器之间共享。当某个渲染器需要渲染的时候,它把自己需要渲染的数据写入渲染目标中,然后通知其他渲染器读取数据并进行渲染。

Opengl有一个基本的概念就是渲染状态。它指的是渲染过程中各种数据的集合。包括视口(Viewport)、投影矩阵(Projection Matrix)、模型视图矩阵(Model View Matrix)、颜色、材料、光源、纹理等。渲染状态可以通过一些函数设置,或者直接修改它所指向的矩阵或数组。

另一个重要的概念是缓冲区。渲染目标和渲染状态都是由缓冲区管理的。缓冲区是一个用来保存数据的内存区域,它可以是显存、磁盘文件、程序变量等。缓冲区的作用是在渲染过程中传递数据。Opengl中的缓冲区分为两种类型,分别是“固定缓冲区”(Fixed-size buffer)和“可变缓冲区”(Variable-sized buffer)。固定缓冲区一般大小不变,而可变缓冲区大小可以根据需要动态调整。

还有一种重要的概念叫做“顶点数组对象”。它是一种可供渲染器使用的存储顶点信息的数据结构。每一个顶点数组对象都有自己的顶点格式、顶点数量、顶点数据指针等属性。当渲染器要渲染某个物体时,它只需要调用这个顶点数组对象即可。

最后,还有一个重要的概念叫做“着色器”,它其实就是一个小型的CPU程序,它运行在GPU硬件上,负责执行图形渲染的各项任务。着色器分为两个主要的类别,即“顶点着色器”和“像素着色器”。顶点着色器负责计算每个顶点的位置、颜色、法线、纹理坐标等属性;而像素着色器则负责计算每个像素的颜色、纹理贴图的采样坐标等属性。

2.2 OpenGL ES 2.0的工作原理

Opengl ES 2.0实际上就是OpenGL的一个子集,只是删去了那些在移动设备上不需要的功能。因此,它在一定程度上比普通的Opengl具有更小的占用空间和更快的启动速度。与Opengl的主流版本不同,Opengl ES 2.0将渲染管线分为三个阶段:

  1. 固定功能阶段:这一阶段执行最简单的几何操作,比如顶点变换、平移缩放和裁剪。
  2. 可编程着色器阶段:这一阶段执行一些高级的计算,比如用于物理模拟、图像处理和动画效果的着色器程序。
  3. 片元着色器阶段:这一阶段生成最终的像素颜色值,主要依赖于前面两个阶段产生的输出。

固定功能管线的运算能力一般较弱,所以通常不会单独使用,而是配合可编程着色器一起使用。由于缺乏硬件加速,而且GPU的浮点运算能力受限,所以固定功能管线的运算速度可能慢得惨不忍睹。可编程着色器的运算能力强大,能够执行各种复杂的算法,并且运行速度快很多。片元着色器生成的颜色值最终显示在屏幕上,因此,片元着色器是整个渲染管线中的最后一环。

3.核心算法原理和具体操作步骤以及数学公式讲解

3.1 数据交换机制

Opengl的核心机制之一就是数据传输。渲染器和驱动器之间通过双端点通信,同步数据交换。典型的数据交换方式有两种:

直接交换(Direct exchange)

这种方式下,数据从渲染器到驱动器或者反过来,都必须完全通过网络连接。在这种方式下,发送端必须将数据序列化,接收端也必须接受序列化数据才能恢复原始数据。

间接交换(Indirect exchange)

这种方式下,数据仅仅被拷贝到显存中,然后再从显存中拷贝到驱动器或者反过来。这样就可以避免网络的存在,从而提高渲染效率。但是这需要驱动器对渲染数据的访问权限。在这种方式下,显卡中的缓冲区和窗口系统之间的联系可以更灵活,但同时也增加了额外的复杂度。

3.2 投影矩阵

投影矩阵是一个4X4矩阵,它描述了相机到齐次坐标系的转换关系。它包括三个分量:

  • 模型矩阵(Model matrix): 矩阵描述了物体空间到世界空间的变换。
  • 视图矩阵(View matrix): 矩阵描述了摄像机空间到观察空间的变换。
  • 投影矩阵(Projection matrix): 矩阵描述了经过透视除法后的剔裁窗口的变换。

这些矩阵将物体的局部坐标系转换为适合用于屏幕上的坐标。他们所用的数学公式如下:

$M = M_{model} \cdot M_{view} \cdot M_{projection}$

其中,$M$ 是最终的矩阵,$M_{model}, M_{view}, M_{projection}$ 分别表示模型矩阵、视图矩阵和投影矩阵。

模型矩阵

模型矩阵描述了物体的三维位置,它是一个4X4的矩阵。矩阵的第四列表示平移矩阵,它将物体的原点移动至世界坐标系的原点。如果物体是三维模型,那么这个矩阵是单位矩阵。如果物体是其它形式的物体,比如点、线、射线等,那么模型矩阵需要进行相应的转换。

$$\begin{bmatrix}\mathtt{m}{00}&\mathtt{m}{01}&\mathtt{m}{02}&\mathtt{m}{03}\ \mathtt{m}{10}&\mathtt{m}{11}&\mathtt{m}{12}&\mathtt{m}{13}\ \mathtt{m}{20}&\mathtt{m}{21}&\mathtt{m}{22}&\mathtt{m}{23}\ 0& 0 & 0 & 1 \end{bmatrix}$$

视图矩阵

视图矩阵描述了相机到摄像机的位置,它是一个4X4的矩阵。摄像机在世界坐标系中指定位置,而视图矩阵将物体从摄像机所在的位置转移到世界坐标系的位置。

$$\begin{bmatrix}\mathtt{v}{00}&\mathtt{v}{01}&\mathtt{v}{02}&-\mathtt{v}{03}\ \mathtt{v}{10}&\mathtt{v}{11}&\mathtt{v}{12}&-\mathtt{v}{13}\ \mathtt{v}{20}&\mathtt{v}{21}&\mathtt{v}{22}&-\mathtt{v}{23}\ 0& 0 & 0 & 1 \end{bmatrix}$$

这里,$-v_{30}-v_{31}-v_{32}=0$ 表示正交投影。其他投影模式,比如透视投影(perspective projection)、正交投影(orthogonal projection)等,可以在这里进行切换。

投影矩阵

投影矩阵描述了剔裁窗口的位置和大小,它是一个4X4的矩阵。它通过透视除法将物体投影到窗口的剔裁窗口上,并解决了窗口与物体的张弛现象。窗口的左下角为原点,右上角为($w$, $h$) ,$z$轴朝向远处。

$P=\frac{(z+p'n)/(p'_f-p'_n),(y+p'_n)/(p'_f-p'_n),-(z+p'_n)\cdot p'{r_x}/(p'f-p'_n)-p'_n,\frac{-2z\cdot y}{p'_f-p'_n}+(p'_f+p'_n)} {(w+p''_n)/(p''_f-p''_n)(y+p'_n)}\Bigg|{\mathsf{clip}}_{(p',p'',p')}\Rightarrow p'_n < z \leq p'_f,~ p''_n<x<p''_f,$

这里,$p'$, $p''$, 和 $p'$ 表示窗口在 $xy$ 平面上的纵横比,$p_f$ 为近端面,$p_n$ 为远端面。

${\mathsf{left},\mathsf{right},\mathsf{bottom},\mathsf{top},\mathsf{near},~\mathsf{far}}$ 表示投影矩阵所对应的剔裁窗口。

$$\begin{pmatrix} w/2 \ h/2 \ f/(f-n) \ n/(n-f) \end{pmatrix}\qquad
M_{\mathrm{proj}}^{-1}\mathbf{v}\qquad \begin{pmatrix} \frac{2z}{w}(x'-p'')-1 \ -\frac{2y}{h}(y'+p')+1 \ -\frac{zf+fp'_fn}{\overline{p'}}+\frac{f^2}{n+zf+fp'_fn} \ \frac{yf+fp'_fn}{\overline{p''}}+\frac{f^2}{n+yf+fp'_fn} \end{pmatrix}$$

猜你喜欢

转载自blog.csdn.net/universsky2015/article/details/133446686