OpenGL Pipeline

OpenGL Pipeline

OpenGL 实现了我们通常说的渲染管线(rendering pipeline),它是一系列数据处理过程,并且将应用程序的数据转换到最终渲染的图像。OpenGL首先接收用户提供的几何数据(顶点和和几何图元),并且将它输入到一系列着色器阶段中处理,包括:定点着色、细分着色、几何着色,然后将几何数据送入光栅化单元(rasterizer)。光栅化单元负责对所有剪切区域(clipping region)内的图元生成片元数据,然后对每个生成的片元着色器。

OpenGL Host

OpenGL传输数据

  • Modern OpenGL中,host(CPU端,也称服务端)会设置一个有序的顶点列表,并把这些数据送到流水线,这些顶点定义了原图形的属性:形状、点、法线、纹理坐标等等,同时也告诉了OpenGL如何去解读这些数据(Vertex Array Object)。
  • OpenGL需要将所有的数据都保存到缓存对象(Vertex Buffer object等等), 它相当于由OpenGL服务端维护的一块内存区域(GPU)。创建这样的数据缓存,最常用的方法就是使用glBufferData()命令。

将数据传输到OpenGL

缓存初始化之后,我们就可以在host上通过调用OpenGL的一个绘制指令来请求渲染几何图元,例如glDrawArrays()OpenGL的绘制通常是将顶点数据发送到OpenGL服务端,通常来说就是显卡。我们可以将一个顶点视为一个需要统一处理的数据包,其可以包含任何数据(位置、纹理、颜色、法向量等等)。

Vertex Rendering

顶点着色

  • 顶点着色器对每个独立的顶点进行基础处理,顶点Shader接受输入属性,并且基于用户定义的程序,将每个输入的顶点转换为一一对应输出顶点。
  • 顶点Shader可以使用用户自定义的输出,但是也有一个特殊的输出gl_Position,代表顶点的最终位置,一般填充为裁剪空间的顶点位置。
  • 一个限制是,在顶点处理过程中,因为各个顶点shader之间的不可共享状态,任何一个输入属性必须被映射到唯一一个顶点输出中。如果你填充了完全相同的属性到相同的顶点Shader中的相同原图形中,那么你将会获得相同的输出顶点数据。
  • 一个复杂的程序可能会有多个顶点着色器,但是同一时刻只有一个起作用

细分着色

  • 细分着色器会使用patch来描述一个物体的形状,并且使用相对简单的Patch几何体连接来完成细分的工作,其结果是几何图元数量增加,使得模型外观会变的更为平顺
  • 细分着色器分为控制和计算两个步骤

几何着色

  • 几何Shader是用户自定义的程序,处理每个输入原图形,并产生0-n个输出原图形。一个很典型的应用就是计算每个顶点的法向量。

Vertex Post-Processing

  • 经过基于Shader的(可编程的)顶点处理之后,顶点会执行一系列的固定管线函数处理,由Host(context)来控制。

图元装配

  • 图元装配阶段将之前顶点和相关的几何图元之间组织起来,准备下一步的剪裁和光栅化工作。

剪切

  • 原图形随后被裁切,裁切意味着,在边界上的原图形,将会被分离成几部分原图形,这样所有的全图型,都将保证在可视空间之内。
  • 同时,最后的顶点处理Shader也可以执行用户自定义操作。顶点位置在透视分割和视图转换时,被转换到裁切空间。

面剔除

  • 三角形元数据可以被剔除,这基于三角形面在窗口空间的朝向。他允许你不渲染背对观察者的三角形。这些三角形会被离观察者近的面挡住,所以你永远没有必要去渲染他们。

光栅化

  • 剪切之后马上要执行的工作,就是将更新后的图元传递到光栅化单元中,生成对应的片元。我们可以将一个片元视为一个候选像素,也就是可以放置在帧缓存中的像素。
  • 以屏幕而发出均匀扫描线,而此时由于图元是3D的,所以会进行非均匀采样,这样我们就能将图元映射到屏幕上。
  • 这个过程可以选择性的进行多重采样。(anti-aliasing)

片元着色

  • 光栅化过程中产生的片段数据,将由片段Shader进行处理。片段Shader的输出是为每个颜色Buffer写入的颜色列表,一个深度值和一个模板值。片段程序无法为片段设置模板值,但是可以控制颜色和深度值。
  • 片段Shader也是可选的。如果你不使用片段Shader,深度(和模板)值,将是他们的通常值。但是所有片段的颜色值是未定义的。不使用片段Shader进行渲染,在我们只想将一个原图形的深度信息写入到深度缓冲的时候,会显得非常有用,比如在做 遮挡查询(Occlusion Query )测试的时候。

逐片元操作

剔除测试

剔除测试是由Host context实现,如果测试被激活且片段没有通过测试,对应的像素或者采样将不会被更新(discard):

  • 像素所有权测试
  • 剪刀测试(Scissor Test):当片段的像素位于指定的屏幕的矩形区域之外的时候,测试将会失败
  • 模板测试(Stencil Test):如果被激活,如果测试提供的模板值,与用户指定的模板缓冲中的值无法匹配,那么测试将会失败
  • 深度测试(Depth Test,z-buffering):如果被激活,当片段的深度值,与用户指定的深度缓冲中的深度值,不匹配,那么测试将会失败
  • Alpha Test

混合

  • 对于每一个片段颜色值,在已经在FrameBuffer中的颜色值,和当前颜色值之间,有一个特殊的混合操作
0%