- 注:这篇文集是针对《OpenGL ES应用开发实践指南 iOS卷》的学习笔记。
- 后续会根据学习进度不断更新OpenGL ES案例解读,当然会有自己的理解。
- 笔者也是0基础开始学习OpenGL ES,有大牛发现文中有误的希望能在评论中指出,也欢迎OpenGL ES新手一起探讨学习。
图形渲染原理及问题
- 图像显示过程:把程序提供的几何数据转换为屏幕上的图像的过程叫做渲染。CUP处理图形数据->传递给GPU->GPU渲染图形数据为2D的平面图像显示到屏幕。
- 使用现代硬件渲染3D图形的速度几乎完全取决于不同的内存区域被访问的方式。
- 从内存的一个区域将数据拷贝到另一个区域是相对较慢的,更糟糕的是,除非非常小心,在内存复制发生的时候GPU和CPU都不能把内存另作他用。因此内存区域之间的数据交换需要尽量避免。
- 所有的内存访问都是相对较慢的。CPU大约每秒一亿次运算,但只能每秒读写内存200万次,GPU理想状态下每秒执行数亿次运算,但是却只能每秒访问内存2亿次。GPU和CPU总是处于“数据饥饿”状态。
- 概括最新OpenGL ES和以前的OpenGL版本之间的差异的一种方式是:最新的为了支持新改进的方法抛弃了旧式的低效内存复制操作的支持。
缓存:提供数据的最好方式
OpenGL ES为两个内存区域间的数据交换定义了缓存(buffers)概念。即图形处理器能够控制和管理连续的RAM。缓存的概念解决了上面3中的问题。几乎所有的程序提供给GPU的数据都应该放入缓存中。
- 为缓存提供数据有如下7个步骤:
- ①生成(Generate)
C函数:glGenBuffers()
—— 请求OpenGL ES为图形处理器控制的缓存生成一个独一无二的标识符。 - ②绑定(Bind)
C函数:glBindBuffer()
—— 告诉OpenGl ES为接下来的运算使用一个缓存。 - ③缓存数据(Buffer Data)
C函数:glBufferSubData()
—— 让OpenGL ES为当前绑定的缓存分配并初始化足够的连续内存(通过从CPU控制的内存复制数据到分配的内存)。 - ④启用(Enable)或者禁止(Disable)
C函数:glEnableVertexAttribArray()或者glDisableVertexAttribArray()
—— 告诉OpenGL ES在接下来的渲染中是否使用缓存中的数据。 - ⑤设置指针(Set Pointer)
C函数:glVertexAttribPointer()
—— 告诉OpenGL ES在缓存中的数据的类型和所有需要访问的内存偏移值。 - ⑥绘图(Draw)
C函数:glDrawArrays()或者glDrawElements()
—— 告诉OpenGL ES使用当前绑定并启用的缓存中的数据渲染整个场景或者某个场景的一部分。 - ⑦删除(Delete)
C函数:glDeleteBuffer()
—— 告诉OpenGL ES删除以前生成的缓存并释放相关的资源。
帧缓存
概念:GPU需要知道应该在内存中的哪个位置存储渲染出来的2D图像像素数据。就像GPU提供数据的缓存一样,接收渲染结果的缓冲区叫做帧缓存(frame buffer)。
- 帧缓存不需要初始化,因为渲染指令会在适当的时候替换缓存的内容。帧缓存会在被绑定的时候隐式开启,同时自动根据特定平台的硬件配置和功能来设置数据的类型和偏移。
- 帧缓存可以同时存在很多个,并且可以通过OpenGL ES让GPU把渲染结果存储到任意数量的帧缓存中。
- 屏幕显示像素受到保存在前帧缓存(front frame buffer)的特定帧缓存中的像素颜色元素控制。
- 程序和操作系统很少会直接渲染到前帧缓存中,因为那样会让用户看到正在渲染中还诶与渲染完成的图像。相反,会把渲染结果保存到包括后帧缓存(back frame buffer)在内的其他帧缓存中。
- 当渲染后的后帧缓存包含一个完成的图像时,前、后帧缓存几乎会瞬间切换。后帧缓存变成新的前帧缓存。
OpenGL ES的上下文
- 用于配置OpenGL ES的保存在特定平台的软件数据结构中的信息会被封装到一个OpenGL ES上下文(context)中。
-
OpenGL ES是一个状态机器,这意味着在一个程序中设置了一个配置值后,这个值会一直保持,知道程序修改了这个值。
-
上下文中的信息可能会被保存在CPU所控制的内存中,也可能被保存在GPU所控制的内存中。OpenGL ES会按需在两个内存区域间复制信息。
-
OpenGL ES为使程序不需要知道太多与特定系统相关的信息,OpenGL ES为跟上下文交互提供了ANSI C语言函数。
-
OpenGL ES上下文会跟踪用于渲染的帧缓存、用于几何数据、颜色等的缓存。还会决定是否使用如纹理、灯光等功能以及会为渲染定义当前的坐标系统等。
一个3D场景的几何数据
几何数据是相对于3D坐标系定义的。
坐标系
-
OpenGL ES总是开始于一个矩形的笛卡尔坐标系,这意味着任何两个轴之间的角度都是90°。空间中的每一个位置被称为一个顶点,每个顶点通过其在X、Y、Z轴上的位置被定义。
X、Y、Z定义了OpenGL的坐标系
-
OpenGL ES坐标是以浮点数来存储的。现代GPU对浮点数运算做了专门的优化,即使使用其他数据类型的顶点也会被转换成浮点值。
矢量
- 从某种意义上讲,矢量是另一种诠释顶点数据的方式。矢量是既有方向又有距离的一个量。所有的顶点可以用它相对于OpenGL ES坐标系原点({0, 0, 0})的距离和方向来定义。从原点到顶点的实心箭头描述了矢量。虚线显示顶点如何与坐标轴对齐。
在3D坐标中的一个矢量 - 矢量是理解现代GPU的关键,因为图形处理器就是大规模并行矢量处理器。GPU能够同时控制多个矢量,并执行用于定义渲染结果的矢量运算。
- OpenGL ES的默认坐标系、顶点和矢量为要渲染的几何数据的定义提供了足够的数学元素。
点、线、三角形
- 一个顶点会定义坐标系中的一个点的位置,两个顶点定义一个线段,三个顶点会定义一个三角形。
- OpenGL ES只渲染顶点、线段和三角形。
小结
- GPU控制的缓存是高效渲染的关键。
- 容纳几何数据的缓存定义了要渲染的点、线段和三角形。
- OpenGL ES的3D默认坐标系、顶点和矢量为几何数据的描述提供了数学基础。
- 渲染的结果通常保存在帧缓存中。其中有两个特别的帧缓存:前帧缓存和后帧缓存,他们控制着屏幕像素的最终颜色。
- OpenGL ES的上下文保存了OpenGL ES的状态信息,包括用于提供渲染的数据的缓存地址和用于接受缓存结果的缓存地址。
网友评论