1)什么是渲染上下文(Context)?
OpenGL 自身是一个巨大的状态机(State Machine):一系列的变量描述 OpenGL 此刻应当如何运行。OpenGL 的状态通常被称为 OpenGL 上下文(Context)。我们通过改变上下文中的状态来改变接下来绘画的属性和操作的缓冲对象,然后 OpenGL 利用当前的上下文(Context)的状态去渲染。因此状态的改变要非常小心,因为是状态是全局,会影响接下来的所有渲染操作。
2)什么是离屏渲染?
GPU 渲染机制:CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后屏幕控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示。
当前屏幕渲染,指的是 GPU 的渲染操作是在当前用于显示的屏幕缓冲区中进行。
离屏渲染,指的是 GPU 在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。
特殊的离屏渲染:如果将不在 GPU 的当前屏幕缓冲区中进行的渲染都称为离屏渲染,那么就还有另一种特殊的离屏渲染方式:CPU 渲染。
3**)什么是着色器** (Shader)?
着色器是OpenGL中用于控制图形渲染过程的程序。着色器分为顶点着色器(Vertex Shader)和片段着色器(Fragment Shader)。顶点着色器用于处理顶点相关计算,如位置变换、法线变换等;片段着色器用于处理每个像素的光照、纹理采样等操作。
4)什么是纹理 (Texture)?
纹理是二维图像的映射,可以应用到模型的表面上。纹理可以提供更加细腻的表面效果,如木纹、金属质感等。OpenGL中通过纹理坐标和纹理采样器将纹理映射到模型表面上。
5)为什么离屏渲染会造成性能损耗?
当使用离屏渲染的时候会很容易造成性能消耗,因为离屏渲染会单独在内存中创建一个屏幕外缓冲区并进行渲染,而屏幕外缓冲区跟当前屏幕缓冲区上下文切换是很耗性能的。
由于垂直同步的机制,如果在一个 VSync 时间内,CPU 或者 GPU 没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变。这就是界面卡顿的原因。
6)什么是 OpenGL 渲染管线(Pipeline)?
OpenGL 渲染管线就是 OpenGL 的工作流程,指的是一堆原始图形数据途经一个输送管道,期间经过各种变化处理最终出现在屏幕的过程。
图形渲染管线可以大致被划分为两个主要部分:第一部分把你的 3D 坐标转换为 2D 坐标;第二部分是把 2D 坐标转变为实际的有颜色的像素。
7)OpenGL渲染管线过程?
①、准备向OpenGL传输数据
OpenGL需要将所有的数据都保存到缓存对象(buffer object)中,它相当于OpenGL服务端维护的一块内存区域。
②、将数据传输到OpenGL
在缓存初始化完成之后,通过调用绘制命令将顶点数据传送到OpenGL服务端。我们可以将一个顶点视为一个需要统一处理的数据包。这个包中的数据可以是我们需要的任何数据。
③、顶点着色(vertex shading stage)
该阶段将接收你顶点缓存中给出的顶点数据。对于绘制命令传输的每个点,OpenGL都会用一个顶点着色器来处理顶点相关的数据(至少会计算出每个顶点经过建模和观察投影变换后在裁剪空间的坐标)。传递着色器会将数据复制并传递到下一个着色阶段。对于复杂的场景也会有相应的着色方式。
④、细分着色(tessellation shading stage)
这是一个可选阶段,与应用程序中显式地指定几何图元的方法不同,它会在OpenGL管线内部生成新的几何体。这个阶段启用之后,会收到来自顶点着色器阶段的输出数据,并且对收到的数据进一步处理。
⑤、 几何着色(geometry shading stage)
该阶段也是一个可选阶段,假如启用了该阶段,它会收到来自顶点着色或者细分着色(如果它也被启用)的数据,然后在OpenGL管线内部对几乎所有的几何图形进行修改。几何着色器不同于前两个着色器,它不仅仅只能修改输入数据,甚至可以创建新的图元交给后续的流水线处理。该阶段作用于每个独立的几何图元。
⑥、图元装配
该阶段会将这些顶点与相关的集合图元之间组织起来,准备下一步的剪切和光栅化工作。
⑦、剪切
该阶段用来保证相关的像素不会在窗口之外进行绘制。也就是说将不能被窗口显示的部分去除。
⑧、光栅化
图元信息最终被传递给光栅化单元,生成对应的片元。
⑨、片元着色(fragment shading stage)
这是最后一个可以通过编程控制屏幕显示颜色的阶段。在这个阶段中会使用着色器来计算片元的最终颜色和它的深度值。(顶点着色决定了一个图元应该处于屏幕的什么位置,片元着色决定了某个片元的颜色应该是什么)。
⑩、片元操作
在该阶段会使用深度测试和模版测试的方式来决定一个片元是否是可见的。如果一个片元成功的通过了所有激活的测试,那么他就可以直接被绘制到帧缓存中了,它所对应的像素的颜色值会被更新,如果开启了融合模式,那么对应的片元颜色会与该像素的颜色相叠加,形成一个新的颜色并写入帧缓存中。
8)为什么说 OpenGL 渲染管线中的着色器(Shader)是可编程管线?
OpenGL 渲染管线中着色器允许开发者自己配置,这样我们就可以使用 GLSL(OpenGL Shading Language)来编写自己的着色器替换默认的着色器,从而更细致地控制图形渲染管线中的特定部分。
9)有哪些着色器可以由程序员进行编程?
可编程的着色器有:顶点着色器(Vertex Shader)、几何着色器(Geometry Shader)、片段着色器(Fragment Shader)。常用的是顶点着色器和片段着色器。
10)什么是 VBO、EBO 和 VAO?
可以认为它们是在 OpenGL 中处理数据的三大类缓冲内存对象。
①、VBO(Vertex Buffer Objects)顶点缓冲区对象,指的是OpenGL中用于存储顶点数据的缓冲区。通过创建和绑定VBO,可以将顶点数据传输到显存中,从而提高渲染效率。VBO可以存储顶点的位置、颜色、纹理坐标等信息。
②、EBO(Element Buffer Object)图元索引缓冲区对象,指的是为了更高效的利用数据,存储索引来达到减少重复数据的索引数据。
③、VAO(Vertex Array Object)顶点数组对象,主要作用是用于管理 VBO 或 EBO,减少
glBindBuffer
、glEnableVertexAttribArray
、glVertexAttribPointer
这些调用操作,高效地实现在顶点数组配置之间切换。
11)如何优化shader计算量优化
将计算从像素着色器移动到顶点着色器在脚本中计算并传递给着色器,使用纹理读取的方式减轻运算量
代码优化尽量使用系统自带的内建函数,因为很多是硬件支持的简单的重复不多的计算,不应该将这种计算封装成函数,直接用代码计算即可选择合适的数据精度,尽量使用低精度
尽量不要使用if分支语句,可以使用step函数替代
12) shader中的if会造成性能影响以及如何优化
if的效率问题是会导致多个分支重复执行。在大多数没有标明关键字的情况下,编译器默认生成的是 flatten 形式的指令,flatten 把分支所有侧的逻辑都执行一遍,根据判断条件舍弃掉错误结果,选择其中一个结果。
优化:从关系运算符和逻辑运算符两个角度,进行分支合并,转换为非分支形式。或者使用内置指令代替内置指令替代。
13) 渲染上屏/交换缓冲区(SwapBuffer)
屏幕显示的图像是通过窗口渲染缓冲区映射,每个窗口只有一个缓冲区,如果屏幕刷新,窗口就会显示不完整的图像。为解决此问题,常规的OpenGL程序⾄少都会有两个缓冲区:①、显示在屏幕上的称为屏幕缓冲区;
②、没有显示的称为离屏缓冲区 。它们不断切换的行为,就是交换缓冲区。
14) 垂直同步信号(V-sync)
显示器的刷新⼀般是逐⾏进⾏的,因此为了防⽌交换缓冲区的时候屏幕上下区域的图像分属于两个不同的帧,因此交换⼀般会等待显示器刷新完成的信号,在显示器两次刷新的间隔中进⾏交换,这个信号就被称为垂直同步信号。
总结:
OpenGL ES是访问类似iPhone和iPad的现代嵌入式系统的3D图形加速硬件的标准。把程序提供的几何数据转换为屏幕上的图像的过程叫做渲染。GPU控制的缓存是高效渲染的关键。容纳几何数据的缓存定义了要渲染的点、线段和三角形。OpenGL ES3D的默认坐标系、顶点和矢量为几何数据的描述提供了数学基础。渲染的结果通常保存在帧缓存中。有两个特别的帧缓存,前帧缓存和后帧缓存,它们控制着屏幕像素的最终颜色。OpenGL ES的上下文保存了OpenGL ES的状态信息,包括用于提供渲染数据的缓存地址和用于接收渲染结果的缓存地址。