OpenGL流水线概览

来源:互联网 发布:运放芯片淘宝有真的吗 编辑:程序博客网 时间:2024/04/29 01:53

渲染流水线概览

原文:https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview

渲染流水线(Rendering Pipeline)是OpenGL渲染物件时候的一系列步骤。这个概览将会对这个流水线的步骤,做一个俯瞰描述。

Contents

  [hide] 
  • 1Pipeline
  • 2Vertex Specification
    • 2.1Vertex Rendering
  • 3Vertex Processing
    • 3.1Vertex shader
    • 3.2Tessellation
    • 3.3Geometry Shader
  • 4Vertex post-processing
    • 4.1Transform Feedback
    • 4.2Clipping
  • 5Primitive assembly
    • 5.1Face culling
  • 6Rasterization
  • 7Fragment Processing
  • 8Per-Sample Operations

流水线(Pipeline)

Rendering Pipeline Flowchart
渲染流水线图标,蓝色部分是可编程的步骤.

 OpenGL 渲染流水线按照下面的步骤工作:

  1. 准备顶点数据( vertex array data)而后渲染他
  2. 顶点处理
    1. 每个顶点在顶点Shader里被处理,然后变成一个输出顶点。
    2. (可选)原图形填充(tessellation )步骤。
    3. (可选)几何 Shader 原图形处理,输出将是一序列的原图形。
  3. 顶点后期处理,最后一步的输出,将会被调整并运送到不同的地方。
    1. Transform 反馈在这里发生。
    2. 原图形裁剪,透视分割,视图变换到窗口空间。
  4. 原图形装配。
  5. 扫描转换和原图形参数插值,这将产生很多的片段。
  6. 一个片段Shader处理每个片段,每个片段生成多个输出。
  7. 基于每个采样的处理(Per-Sample_Processing)
    1. 裁剪测试
    2. 模板测试
    3. 深度测试
    4. 混合
    5. 逻辑处理
    6. 空白遮罩(Write Mask,暂时不懂,看明白之后改成更合适的翻译)


顶点规范化

顶点规范化过程,是应用程序设置一个有序的顶点列表,并送往流水线的过程,这些顶点定义了原图形的边界。

原图形是基础绘制形状,比如三角形,线和点。明确的告诉你,在后面的步骤中,顶点数据作为原图形,应该如何被解读(译注:如哪几位是顶点,哪几位是颜色,哪几位是法线,哪几位是纹理坐标)

这部分的流水线,处理一些对象,如VAO(Vertex Array Object 顶点数组对象)和VBP(Vertex Buffer Ojbect 顶点缓冲对象),VAO定义了,顶点都有哪些数据,而VBO则存放实际的数据。

一个顶点数据,由一组属性组成,每个属性是一个下个步骤将要依赖之计算的小数据集。 而一组属性,确定了一个顶点,这并不是说,一个顶点的属性,一定是位置或者法线什么的,顶点数据可以是任意的东西(译注:比如我读硕士时尝试用顶点数据做并行计算,虽然最后选择了新兴的CUDA技术)在顶点处理阶段,会给每个顶点的每个分量分配唯一的含义。

顶点渲染

一旦顶点数据被适当的指定,他将通过绘图指令,作为原图形进行渲染。

顶点处理

在上一个阶段获得的顶点,将在这个阶段进行他们的处理。顶点处理阶段,几乎都是可编程处理操作。这将允许用户编码去自定义顶点如何被处理。每个阶段对应一个不同的Shader操作。有些步骤是可选的。

顶点shader

顶点Shader针对每个独立的顶点进行基础处理,顶点Shader,顶点Shader从顶点渲染接受输入属性,并基于用户定义的程序,将每个输入的顶点,转换为一一对应输出顶点。

顶点Shader可以使用用户自定义的输出,但是也有一个特殊的输出,代表顶点的最终位置(译注:这句应该指的是gl_Position),如果没有随后的顶点处理步骤,顶点Shader预期将会将这位置信息,填充为裁剪空间的顶点位置。以备后用。

一个限制是,在顶点处理过程中,因为各个顶点shader之间的调用,不可共享状态,任何一个输入属性必须被映射到唯一一个顶点输出中。如果你填充了完全相同的属性,到相同的顶点Shader中的相同原图形中,那么你将会获得相同的输出顶点数据。这给予驱动的实现,去优化顶点处理过程,如果他们可以检测到,他们将要去处理一个已经被处理过的顶点,他们可以使用之前存放在post-transform缓存中的数据,而不需要去再次运行顶点处理程序重复处理那条数据。(暂时没理解透彻,先放放,以后回来填坑)

顶点Shader不是可选的,是必须的。

Tessellation

填充过程是可选的,如果TES打开,则认为填充是激活的。TCS也是可选的,TSC不可以独立存在必须和TES一起使用。

几何 Shader

几何shader是用户自定义的程序,处理每个输入原图形,并产生0-n个输出原图形。几何Shader的输入原图形,是一些原图形装配过程中产生的输出原图形的子集。所以如果你发送一个三角形Strip,几何Shader会把他们视为一系列的三角形。

尽管如此,有很多输入原图形的类别,专为几何Shader定制。这些邻接原图形,给予GS更大的视野,他们提供了访问邻接当前原图形的原图形的顶点的权限。

GS的输出可能是0或多个简单原图形,更像是原图形装配集的输出。GS能够删除原图形,或者通过从一个输出衍生出更多的输出原图形来填充他们。GS也可以修补顶点数据,或者为顶点Shader做些事情,或者在填充时做些插值,几何Shader甚至可以将原图形转换为其他类别,输入一个点,可以变成一条线,一个三角形,甚至很多点。

几何Shader也是可选的。

顶点后期处理

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

Transform 反馈

几何Shader或元数据装配的输出,将会被为了这个目的(Transform Feedback),写入到一系列的缓冲对象中去。这个过程也被称形变反馈模式。它允许用户通过几何Shader变换顶点,并且保存他们以备用户后用。数据输出到Transform feedback缓冲,是由每个原图形,在这个步骤反射的数据。


裁切

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

顶点位置在透视分割和视图转换时,被转换到裁切空间。

原图形装配

原图形装配,从前面的步骤中收集顶点数据,并组装成一序列原图形。用户渲染的原图形类别决定这个步骤如何工作。这个步骤的输出是一序列有序的原图形(线,点,三角形)如果输入是一个三角形Strip包含12个顶点,那么输出将是10个三角形。(译注:用三角形链,将三角形传入GPU,会节省传输数据量,但是,GPU似乎并不认这个,所以需要Primitive Assembly)

如果Tessellation或者几何Shader是激活的,那么一个受限制的形式的元数据装备,会在顶点处理步骤之前执行。这将保证这些Shader被填充的是独立的原图形,而不是一序列的顶点。

渲染流水线也可以在这个步骤中被中止,这可以使得Tranform Feedback得以运作(译注:有些时候你不是为了渲染,而是为了计算。)而不需要实质的渲染些什么。

面剔除

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

光栅化

如果原图形能活到这一步(而没被用户终止或者崩溃掉:-),他们将会被按照他们(来送人头儿:-)的顺序光栅化。光栅化的结果是一序列的片段数据。

一个片段是在输出的帧缓冲中的一组状态,它用来计算一个像素的最终数据(或者是一个样本,如果多重采样被激活的话)。一个片段的状态,通常包括,屏幕空间的位置,采样覆盖(如果多重采样被激活),以及一系列从上一个顶点或者几何Shader发过来的任意数据。 这个过程可以选择性的进行多重采样。

片段处理过程

光栅化过程中产生的片段数据,将由片段Shader进行处理。片段Shader的输出是为每个颜色Buffer写入的颜色列表,一个深度值和一个模板值。片段程序无法为片段设置模板值,但是可以控制颜色和深度值。

片段Shader也是可选的。如果你不使用片段Shader,深度(和模板)值,将是他们的通常值。但是所有片段的颜色值是未定义的。不使用片段Shader进行渲染,在我们只想将一个原图形的深度信息写入到深度缓冲的时候,会显得非常有用,比如在做 遮挡查询(Occlusion Query )测试的时候。

每采样操作

片段处理器输出的片段数据,接下来将会通过以下步骤的处理。

第一个步骤是一系列的剔除测试。如果测试是激活的,并且片段没有通过测试。对应的像素或采样将不会被更新(同常不会)(也就是说,片段被抛弃了:-)。很多这类测试,只有用户手动激活才会生效。这些测试为:

  • 像素所有权测试:如果像素的所有权,不是由OpenGL拥有,则测试失败(比如其他窗体,覆盖了GL窗口,那么没必要渲染他了。)但是如果你使用一个帧缓冲对象,则测试必然通过。失败意味着那个像素将持有未定义的值。
  • 剪刀测试(Scissor Test)如果被激活,当片段的像素位于指定的屏幕的矩形区域之外的时候,测试将会失败
  • 模板测试(Stencil Test)如果被激活,如果测试提供的模板值,与用户指定的模板缓冲中的值无法匹配,那么测试将会失败。 注意:即时测试失败,帧缓冲中的模板值仍旧有可能会被改变(就算深度测试失败,也是一样)。
  • 深度测试(Depth Test) 如果被激活,当片段的深度值,与用户指定的深度缓冲中的深度值,不匹配,那么测试将会失败。 
注意: 尽管规定这些事情发生在片段Shader之后,在某些特定情况下,也可以强制他们发生在片段Shader之前。如果他们发生在FS之前,那么被裁减掉的像素也会防止片段Shader执行,这可以节省效率。

在这之后,颜色混合( color blending )发生了,对于每一个片段颜色值,在已经在FrameBuffer中的颜色值,和当前颜色值之间,有一个特殊的混合操作 。逻辑操作( Logical Operations )也会发生在混合的地方,他可以在片段颜色和颜色缓冲中的颜色之间实施一个按位操作。

最后,片段数据被写入到缓冲之中。遮罩操作( Masking operations)允许用户组织指定的片段颜色的写入。颜色,深度,模板遮罩可以开启或关闭,独立颜色的通道,也可以被单独遮罩。

原创粉丝点击