【OpenGL学习记录】图形渲染管线(1)

什么是渲染管线?

渲染管线是OpenGL在渲染对象时需要执行的一系列步骤,是显示芯片内部处理图形信号相互独立的的并行处理单元。
【OpenGL学习记录】图形渲染管线(1)

管线(Pipeline)

一.顶点数据

首先我们需要渲染对象的顶点数据,例如点的位置,法线向量,颜色等等。定义这样的顶点数据以后,我们会把它作为输入发送给图形渲染管线的第一个处理阶段:顶点着色器。它会在GPU上创建内存用于储存我们的顶点数据,然后我们还要配置OpenGL如何解释这些内存。
这部分会处理许多顶点对象,如顶点数组对象(VAO)和顶点缓冲对象(VBO)。顶点数组对象定义每个顶点有哪些数据,而顶点缓冲对象本身存储实际的顶点数据。

二.顶点着色器(Vertex Shader)

顶点着色器会做一系列的坐标变化,目的是为了把顶点的局部坐标转化到屏幕坐标,这过程成为称为视口变换。最后转换的坐标将会送到光栅器,由光栅器将其转化为片段。
【OpenGL学习记录】图形渲染管线(1)
首先,顶点坐标开始于局部空间(Local Space),称为局部坐标(Local Coordinate),然后经过世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)结束。

1.局部空间

局部空间(Local Space)是指对象所在的坐标空间,例如,对象最开始所在的地方。想象你在一个模型建造软件(比如说Blender)中创建了一个立方体。你创建的立方体的原点有可能位于(0,0,0),即使有可能在最后的应用中位于完全不同的另外一个位置。甚至有可能你创建的所有模型都以(0,0,0)为初始位置,然而他们会在世界的不同位置。则你的模型的所有顶点都是在局部空间:他们相对于你的对象来说都是局部的。

2.世界空间

如果我们想将我们所有的对象导入到程序当中,它们有可能会全挤在世界的原点上(0,0,0),然而这并不是我们想要的结果。我们想为每一个对象定义一个位置,从而使对象位于更大的世界当中。世界空间(World Space)中的坐标就如它们听起来那样:是指顶点相对于(游戏)世界的坐标。物体变换到的最终空间就是世界坐标系,并且你会想让这些物体分散开来摆放(从而显得更真实)。对象的坐标将会从局部坐标转换到世界坐标;该转换是由模型矩阵(Model Matrix)实现的。

3.观察空间

观察空间(View Space)经常被人们称之OpenGL的摄像机(Camera)(所以有时也称为摄像机空间(Camera Space)或视觉空间(Eye Space))。观察空间就是将对象的世界空间的坐标转换为观察者视野前面的坐标。因此观察空间就是从摄像机的角度观察到的空间。而这通常是由一系列的平移和旋转的组合来平移和旋转场景从而使得特定的对象被转换到摄像机前面。这些组合在一起的转换通常存储在一个观察矩阵(View Matrix)里,用来将世界坐标转换到观察空间。

4.裁剪空间

在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个给定的范围内,且任何在这个范围之外的点都应该被裁剪掉(Clipped)。被裁剪掉的坐标就被忽略了,所以剩下的坐标就将变为屏幕上可见的片段。
这里就需要用到投影矩阵,有两种不同的方式。一个正射投影矩阵(Orthographic Projection Matrix)一个透视投影矩阵(Perspective Projection Matrix)。

  1. 正射投影
    这种投影一般用在2D平面上
    【OpenGL学习记录】图形渲染管线(1)

  2. 透视投影
    这种会有更真实的3D效果
    【OpenGL学习记录】图形渲染管线(1)

三.图元装配(Primitive Assembly)

图元装配会从前级阶段收集一系列输出的顶点数据,并将其组合为一系列图元的过程。这将产生一系列的三角形、线段和点。这些图元需要经过裁剪到可视平截体(三维空间中一个可见的区域)和任何有效地应用程序指定的裁剪平面。

四.几何着色器(Geometry Shader)

图元装配阶段的输出会传递给几何着色器(Geometry Shader)。几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。
几何着色器是可选着色器,可以不用。
【OpenGL学习记录】图形渲染管线(1)

五.光栅化(Rasterization)

经过图元装配的原始图元必须进行光栅化。光栅化的目的是为了确定屏幕上哪些像素点用来构成图元,光栅化一个图元的结果是一系列片段。
【OpenGL学习记录】图形渲染管线(1)

六.片段着色器(Fragment Shader)

来自光栅化阶段的每个片段的数据由片段着色器处理。片段着色器的主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。

七.测试和混合

  1. 裁剪测试
    如果片段的像素位于屏幕的指定矩形之外,则丢弃片段,无需后续计算。
  2. 采样
    超级采样抗锯齿技术(Super Sample Anti-aliasing, SSAA)
    它暂时使用一个更高的解析度(以超级采样方式)来渲染场景,当视频输出在帧缓冲中被更新时,解析度便降回原来的普通解析度。这个额外的解析度被用来防止锯齿边。虽然它确实为我们提供了一种解决走样问题的方案,但却由于必须绘制比平时更多的片段而降低了性能。所以这个技术只流行了一段时间。
    多采样抗锯齿(Multisample Anti-aliasing,MSAA)
    它是OpenGL内建的采样算法。多采样所做的是不再使用单一采样点来决定三角形的覆盖范围,而是采用多个采样点。我们不再使用每个像素中心的采样点,取而代之的是4个子样本,用它们来决定像素的覆盖率,然后对每个像素的子样本的颜色进行平均化。
    【OpenGL学习记录】图形渲染管线(1)
  3. 模板测试
    启用模板测试时,如果测试提供的模板值未与用户指定的模板值相比,则模板缓冲区中的基础样本的模板值会比较失败。模板测试可以让开发人员*控制丢弃片段,也是最复杂的一种测试。
  4. 深度测试
    深度缓存中存储着每个像素点的深度值,深度值越大,则离摄像机越远。为了防止被遮挡的面渲染到前面。
    在大多数系统中深度缓冲区为24位。
    现在大多数 GPU 都支持一种称为提前深度测试(Early depth testing)的硬件功能。提前深度测试允许深度测试在片段着色器之前运行。明确一个片段永远不会可见我们可以更早地放弃该片段。
  5. 混合
    混合是指两种颜色的叠加方式。
    C=源颜色向量∗源因子+目标颜色向量∗目标因子