开篇
这个章节会展示实时图形的核心组件,即图形渲染管线(Graphics Rendering Pipeline)或“管线”。管线的主要功能是在给定一个虚拟相机、一些三维物体、一些光源等条件下,生成或绘制一张二维图像,下图描述了使用管线的过程。
物体的位置和形状是由它们的几何、环境的特征、相机在环境中的摆放决定的。物体的外表会被材质属性、光源、纹理以及着色方程影响。
接下来的部分将解释图形管线的不同阶段,我们将会聚焦于功能而不是实现。一些相关的细节会在后续的章节被覆盖。
架构(Architecture)
从工厂装配线到快餐厨房,管线这一概念在现实世界中以多种形式展现,它也在图形渲染中被应用。一条管线由多个阶段组成,每个阶段会执行大量任务的一部分。
管线的阶段是以并行的方式执行的,每个阶段会依赖上一个阶段执行完的结果。在理想的情况下,把一个非管线系统分成\(n\)个管线阶段会获得\(n\)倍的性能提升。这种性能提升是使用管线的主要原因。例如,非常多的三明治可以被一系列人快速地做好,一个人可以准备面包,一个人加肉,另一个添加配料。每个人把制作后的结果传递给管线中的下一个人后,就立即开始下一个三明治的制作。如果每个人要花二十秒来制作,那么每二十秒这几个人就能制作一个三明治。虽然管线的阶段是以并行的方式执行的,但是它们会停止直到最慢的阶段完成它自己的任务。如果,肉的添加阶段要花费更多的时间,以三十秒为例,那么制作一个三明治就要三十秒。对于这个管线来说,肉的添加阶段是瓶颈(Bottleneck),因为它决定了整个管线的速度。在等待肉的添加阶段完成的时间中,配料阶段会处于数据饥饿(Starve)状态(对于顾客也是)。
这种管线的构造也在实时计算机图形中出现。实时渲染管线可以被粗糙地划分为四个阶段,即应用程序(Application)阶段、几何处理(Geometry Processing)阶段、光栅化(Rasterization)阶段、像素处理(Pixel Processing)阶段,下方为一张相关的示例图。
这种结构是被用于实时计算机图形应用中的渲染管线引擎的核心,也是后续章节讨论的必要基础。一般来说,每个阶段本身也是管线,会由一些子阶段构成。我们区分在这里展示的功能阶段与它们的实现结构。一个功能阶段有特定的任务要执行,但是不声明任务在管线中是如何被执行的。一个给定的实现有可能结合两个功能阶段到一个单元或使用使用可编程核心来执行,同时也有可能划分别的更加耗时的功能阶段到一些硬件单元中。
渲染速度有可能使用每秒帧数(FPS)来表达,也就是每秒被渲染的图像数量。也可以使用赫兹(Hz)来表达,它只是更新的频率,即\(1/秒\)。还可以使用毫秒(ms)来表达,也就是渲染一张图像花费的时间。生成一张图像的时间通常不同,会取决于每帧计算的复杂度。每秒帧数被用来表达一帧的速率或某个时间区间内的平均速率。赫兹则被用于硬件,就比如显式速率,它是一个固定的速率。
由应用程序阶段这个名字可知,这个阶段是由应用程序驱动的,通常由运行在通用CPU上的软件实现。这些CPU通常包含多个核心,有能力以并行的方式处理多个线程(Thread)。这就使得CPU可以高效地执行许多不同类型的应用程序阶段要完成的任务。有些任务传统上是在CPU上执行的,包括碰撞检测、全局加速算法、动画、物理模拟以及其它取决于应用类型的任务。下一个主要阶段是几何处理阶段,它处理变换、投影以及其它所有需要解决的几何问题。这个阶段会计算要绘制的物体、物体如何被绘制、物体要在哪被绘制。几何阶段通常在包含多个可编程核心和固定功能硬件的图形处理单元(GPU)上执行。光栅化阶段通常取三个输入的顶点构成一个三角形,然后找到所有被认为在三角形内的像素,接着让这些像素进入下一个阶段。最后的像素处理阶段会为每个像素执行一个程序,来决定它的颜色。以及可能进行深度测试,来确定像素是否可见。它还有可能执行逐像素的操作,例如将计算出的颜色与之前的颜色进行混色。光栅化以及像素处理阶段都是完全在GPU上执行的。第三章将会有更多的GPU如何处理这些阶段的细节。
应用程序阶段(The Application Stage)
对于应用程序阶段是如何完成的,开发者有完全的控制权,因为它通常在CPU上执行。因此,开发者能决定整个实现方法,后续为了提升性能可以进行修改。在这里进行的改变可以影响后续阶段的性能。例如,一个应用程序阶段的算法或设置可以减少被绘制的三角形的数量。
当然了,一些应用程序的工作可以在GPU上执行,通过使用一个单独的叫计算着色器(Compute Shader)的模式。这个模式会把GPU当作一个高度并行的通用处理器,而忽略它被用于渲染图形这一特殊功能。
在应用程序阶段末尾,要被渲染的几何体会被送入几何处理阶段。这些几何体被称作渲染图元(Rendering Primitive),包括点、线、三角形以及那些最终会出现在屏幕上的几何体。这就是应用程序阶段最重要的任务。
基于软件实现的一个结果是这个阶段没有被划分为子阶段。然而,为了提升性能,这个阶段通常以并行的方式在多个处理器核心上被执行。在CPU的设计中,这被称为超标量体系结构(Superscalar Construction),因为它能在同一阶段和时间执行一些不同的任务。
通常,在这个阶段实现的一个处理是碰撞检测(Collision Dectection)。当两个物体之间的碰撞被检测到,一个响应有可能产生然后被发送到产生碰撞的物体和力反馈设备。这个阶段也会处理来自其它地方的输入,比如键盘、鼠标、头戴式显示器。取决于输入,一些不同类型的行为可能会被采取。加速算法,例如某个剔除算法,也会在这里被实现。总之就是一些别的阶段解决不了的任务。
几何处理(Geometry Processing)
在GPU上的几何处理阶段会负责几乎所有的逐三角形和逐顶点操作。这个阶段可以被细分成以下四个功能阶段,即顶点着色、投影、裁剪、屏幕映射,如下图所示。
顶点着色(Vertex Shading)
顶点着色有两个主要任务,一个是计算顶点的位置,另一个是计算期望的顶点输出数据,比如法线和纹理坐标。传统地说,物体的着色都是在顶点上进行的,为顶点计算出的颜色会在三角形上进行插值。正是因为这样,可编程的顶点处理单元被称为顶点着色器。随着GPU的发展,着色可以逐像素进行,顶点着色阶段就变得更加通用化,取决于编程者的意图,顶点着色阶段可能不会评估任何着色方程。在当下,顶点着色器是个更加通用的单元,专门被用来设置和每个顶点关联的数据。
我们首先描述顶点位置是如何被计算的,一系列坐标总是需要的。在去屏幕的路上,一个模型会被变换到数个不同的空间(Space)或坐标系(Coordinate System)。一开始,模型存在于它自己的模型空间(Model Space)中,这意味着还没被变换。每个模型可以与一个模型变换(Model Transform)关联,从而让模型能有位置和朝向。一个模型可能与多个模型变换关联,这样能让相同模型的拷贝(实例(Instance))在同一场景中有不同的位置、朝向、大小,而不需要复制基本的几何体。
会被变换的是模型的顶点和法线。一个物体的坐标叫模型坐标(Model Coordinate),模型的坐标被模型变换后,模型会位于世界坐标(World Coordinate)或世界空间(World Space)。世界空间是独特的,当模型被各自的模型变换所变换后,所有的模型都会处于世界空间。
正如之前提到的那样,只有被相机看到的模型才会被渲染。相机在世界空间中有位置和朝向,为了方便投影和裁剪,相机和所有的模型都会进行视图变换(View Transform)。视图变换是为了把相机放在原点,并且让相机看着\(-z\)轴,此外还要让\(+y\)轴为相机的上方,让\(+x\)轴为相机右方。我们让相机看着\(-z\)轴,而有些书倾向让相机看着\(+z\)。这两者之间只是约定不同,因为从其中一个转换到另一个很简单。在视图变换后,实际的位置和方向会取决于底层的API。视图变换后的空间被称为相机空间(Camera Space),或更加通常的视图空间(View Space)或眼空间(Eye Space)。视图变换对相机和模型的影响如下图所示。
模型变换和视图变换可能都是用\(4 \times 4\)的矩阵实现的,这是第四章的话题。然而,意识到顶点的位置和法线可以以任何方式来计算很重要。
接下来,我们讨论来自顶点着色的第二种输出类型。为了生成一个真实的场景,仅仅渲染形状和物体的位置是不够的,它们的外表应该也被建模。而这包括每个物体的材质以及作用于物体的任何光源。材质和光源可以使用多种方式来建模,从简单的颜色到物理描述的详细展示。
决定光源作用于材质的效果的操作被称为着色(Shading)。它涉及为物体的不同位置计算一个着色方程(Shading Equation)。通常情况下,这些计算会逐顶点进行,而在另一些情况则会逐像素进行。各种材质数据可以存储于顶点,比如位置、法线、颜色以及任何需要用来评估着色方程的数据。顶点着色的结果接着会被送入光栅化和像素处理阶段,这些结果会被插值然后用来计算表面的着色。
GPU顶点着色器形式的顶点着色在书中会有更深入的讨论,特别是在第三章和第五章。
作为顶点着色的一部分,渲染系统会进行投影(Projection),接着进行裁剪。这会把视图体变换到单位立方体,即\(x,y,z \in [-1,1]\)。有些不同的范围也被使用,例如\(0 \leq z \leq 1\)。单位立方体被称为规范视图体(Canonical View Volume)。投影是最先被完成的,在GPU上则会由顶点着色器完成。有两种常用的投影方法,一种为正交(Orthographic)投影,另一种为透视(Perspective)投影,如下图所示。
事实上,正交投影只是平行投影的一种形式。其它的常用形式有斜投影和轴测投影等等。
正交视图的视图体通常是一个矩形盒,正交投影会把这种视图体变换到单位立方体,它的一个主要特点是平行线被变换后会保持平行。这个变换是平移和缩放的结合。
透视投影则更加复杂,在这一类型的投影中,远离相机的物体被投影后会更小。平行线被投影后可能在地平线汇聚。因此,透视变换模拟了我们如何感知物体的大小。从几何上说,视图体被称为一个截头锥体(Frustum),它是一个有着矩形底面被截取的金字塔,它也会被变换到单位立方体。正交和投影变换都能用\(4 \times 4\)的矩阵来构造,在被任意一种投影矩阵变换后,模型会位于裁剪坐标(Clip Coordinate)。这些实际上是齐次坐标,会在第四章被讨论,它会在除以\(w\)之前出现。GPU的顶点着色器必须总是输出这种坐标来让下一个功能阶段(裁剪)正确地工作。
尽管这些矩阵会把一个体变换到另一个体,但是它们都被称作投影。因为在显示后,z坐标不会存储于图像而是在z缓冲中。这样,模型就从三维被投影到了二维。
可选的顶点处理(Optional Vertex Processing)
每条管线都有上述描述的顶点处理。一旦处理完成了,就没有多少可选的在GPU上执行的阶段,以执行顺序排列有:镶嵌细分、几何着色、流输出。它们的使用取决于硬件的能力和编程者的想法。此外它们都是相互独立的,一般都不被常用。在第三章有这些可选的阶段的更多讨论。
第一个可选阶段是镶嵌细分(Tessellation)。想象一下有个跳跃的球物体,如果你使用三角形来表示它,那么就会遇到质量或性能上的问题。从5米观察可能看起来很好,但是近距离观察会发现每个三角形。为了解决这一问题,你会用更多的三角形来提升质量,但是从远处观察时会浪费可观的处理时间和内存。使用镶嵌细分,一个曲面可以用合适数量的三角形来表示。
关于三角形我们只讨论了一点,但目前的管线只处理了顶点。这些顶点可以被用来表示点、线、三角形或其它物体。顶点也可以被用来表示曲面,就比如球。这种表面可以使用一系列曲面片来声明,这些曲面片是由一系列顶点构成的。镶嵌细分阶段由一系列阶段构成,包括:外壳着色器、细分器、域着色器。它们能把一系列曲面片顶点转化成更多顶点的集合,从而生成更多的三角形。场景的相机可以被用来决定有多少三角形要生成,当相机离曲面片近时就生成更多三角形,反之则更少。
下一个可选阶段是几何着色器(Geometry Shader)。这个着色器早于镶嵌细分着色器,因此在GPU中更常见。它与镶嵌细分着色器类似,会取不同类型的图元生成更多的顶点。不过它是个简单得多的阶段,这种生成有范围限制,且输出图元的类型被更严格地限制。几何着色器有一些用途,其中一个最受欢迎的就是粒子生成。想象模拟烟花爆炸,每个火球都可以用一个顶点来表示。几何着色器能取每个顶点,然后将其变成一个面向相机的正方形,这样就提供了一个更好的图元让我们着色。
最后一个可选阶段是流输出(Stream Output)。这个阶段能让我们把GPU当作一个几何引擎。处理后的顶点可以为了后续的处理被输出到数组,而不是被输出到管线的剩余部分,直到被渲染在屏幕上。这个阶段通常被用于粒子模拟,比如之前说的烟花例子。
这三个阶段会以如下顺序执行:镶嵌细分、几何着色、流输出,且每个阶段都是可选的。
裁剪(Clipping)
只有那些完全或部分在视图体内的图元需要被送入光栅化阶段,接着在屏幕上被绘制。完全在视图体内的图元可以直接进入下一阶段,而完全在视图体外的图元不需要被渲染。对于部分在视图体内的图元,我们需要进行裁剪。比如有根直线,它的一个顶点在外另一个顶点在内,我们应该使用视图体来裁剪这根直线,把在外的顶点替换成直线与视图体的交点。使用投影矩阵意味着被变换的图元要使用单位立方体来裁剪。在裁剪前进行视图和投影变换能让裁剪操作有一致性,要被裁剪的图元总是会被单位立方体裁剪。裁剪的过程如下图所示。
除了六个裁剪平面外,用户还可以定义额外的平面来裁剪物体,这种类型的可视化叫做剖切(Sectioning),如下图所示。
裁剪步骤会使用通过投影生成的齐次坐标值。在透视空间中,顶点的携带的值通常不会在三角形上线性插值。当使用透视投影时,会需要第四个坐标来让数据被正确地插值和裁剪。最后,会进行透视除法(Perspective Division),三角形的位置会处于三维归一化设备坐标(Normalized Device Coordinate,NDC)。之前提到过,这个视图体的范围为\(x,y,z \in [-1,1]\)。几何阶段的最后一步会把这个空间转化到窗口坐标。
屏幕映射(Screen Mapping)
只有在视图体内(被裁剪)的图元会被送入屏幕映射阶段,在这个阶段每个图元的\(x\)和\(y\)坐标会被变换到屏幕坐标(Screen Coordinates)。屏幕坐标与\(z\)坐标一起被称为窗口坐标(Window Coordinate)。假设场景要被渲染到有着最小角落\((x_1,y_1)\)和最大角落\((x_2,y_2)\)的窗口,那么屏幕映射是一次平移接着一次缩放的操作。新的\(x\)和\(y\)坐标是屏幕坐标。\(z\)坐标(\([-1,+1]\)对于OpenGL,\([0,1]\)对于DirectX)也会被映射到\([z_1,z_2]\),\(z_1=0\)和\(z_2=1\)会作为默认值,这两个值可以用API来改变。窗口坐标与再映射的\(z\)值会被送入光栅器阶段。屏幕映射的过程如下图所示。
接下来,我们描述整数和浮点数是如何与像素联系的。给定使用笛卡尔坐标的一组水平像素,最左侧像素的左边缘的浮点坐标为\(0.0\)。OpenGL总是使用这个方案,并且DirectX 10和它的继任者也使用这个方案。这个像素的中心在\(0.5\)。因此,有着范围\([0,9]\)的像素覆盖了\([0.0,10.0)\)的范围。可以使用如下简单的公式进行转换。
其中的\(d\)为像素的离散索引,而\(c\)为像素中的连续值。
虽然所有API的像素位置的值都会从左往右增加,但是从下往上则不一致,比如OpenGL和DirectX。OpenGL从始至终倾向于笛卡尔系统,让左下角为有最低值的元素。取决于上下文,DirectX有时定义左上角为有最低值的元素。这两者有各自的逻辑,在它们有区别的地方没有正确的答案。例如,在OpenGL中\((0,0)\)为图像左下角,在DirectX中则为左上角。当从一个API转移到另外一个API时要注意这个重要的区别。
光栅化(Rasterization)
有了变换和投影后的顶点以及与顶点关联的着色数据后,下一阶段的目标就是找到所有在图元内的像素(Picture Element,Pixel)。我们称这个过程为光栅化,且分为两个子功能阶段,即三角形设定和三角形遍历,下方为一张示例图。
要注意的是光栅化也可以处理点和线,但由于三角形是最常见的,因此子阶段的名字中有“三角形”。光栅化也可以被称为扫描转换(Scan Conversion),是从有着z值和各种着色信息的屏幕空间内的二维顶点到屏幕上的像素的转换。光栅化还可以被认为是几何处理和像素处理之间的同步点,因为在这里三角形由三个顶点组成,并且最终要被送入像素处理。
三角形是否与像素重叠取决于你如何设定GPU管线。比如,你可能使用点采样来确定像素是否在三角形内。最简单的情况就是判断每个像素的中心是否在三角形内,如果在那么对应的像素就被认为在三角形内。你也许会使用超采样或多重采样抗走样技术来为每个像素使用多个样本。还有一个方法是使用保守光栅化,只要像素与三角形重叠,那么就认为这个像素在三角形内。
三角形设定(Triangle Setup)
在这个阶段微分、边方程以及其它用于三角形的数据都会被计算。这些数据可能被用于三角形遍历,或从几何阶段生成的各种着色数据的插值。固定功能硬件会被用于这个任务。
三角形遍历(Triangle Traversal)
在这里,每个像素会被检查是否在三角形内,如果在那么会有一个片段(Fragment)生成,对应着这个像素。找到在三角形内的样本或像素通常被称为三角形遍历(Triangle Traversal)。每个三角形片段的属性会从组成这个三角形的三个顶点的属性插值得到。这些属性包括片段的深度以及任何来自几何阶段的着色数据。所有在图元内的像素或样本接着会被送入像素处理阶段。
像素处理(Pixel Processing)
到这里,所有被认为在三角形或其它图元的像素都被到找了。像素处理阶段被划分为像素着色(Pixel Shading)和合并(Merging),这两个阶段如下图所示。
像素处理是逐像素或逐样本计算的阶段,各种计算会应用于那些在图元内的像素或样本。
像素着色(Pixel Shading)
任何逐像素着色计算会在这里进行,并使用插值后的着色数据。最终的结果是被传入到下一个阶段的一或多个颜色。不像三角形设定和三角形遍历阶段那样由专用硬件硅芯片执行,像素着色阶段是通过可编程GPU核心执行的。编程者需要为像素着色器(对于OpenGL来说是片段着色器)提供一个程序,它可以包含任何期望的计算。有非常多的技术可以在这里实施,最重要之一的是纹理映射(Texturing)。第六章中有更多的纹理映射的细节。你可以把纹理映射一个物体当作为了不同目的,把一个或多个图像“粘”在物体上,下方是这个过程的一个示例。
图像可以是一维、二维或三维的,其中二维图像是最常见的。简而言之,对于每个片段会有一个颜色计算出来,这些片段接着会被传递到下一个子阶段。
合并(Merging)
每个像素的信息存储于颜色缓冲(Color Buffer)中,它是颜色的矩形数组(对于每个颜色有红、绿、蓝三个分量)。合并阶段的责任就是结合片段与缓冲中片段对应的像素的颜色。这个阶段也被称为ROP,取决于你问的人,它可以是光栅操作(管线)或渲染输出单元。不像着色阶段,执行这个阶段的GPU子单元通常不是完全可编程的。然而,它是高度可配置的,允许各种各样的效果。
这个阶段也会负责确定可见度。这意味着当整个场景被渲染时,颜色缓冲应该包含场景中对于相机可见的图元的颜色。对于大多数甚至是所有图形硬件来说,这是通过z缓冲(也被称为深度缓冲(Depth Buffer))算法完成的。一个z缓冲与颜色缓冲有着相同的大小和形状,对于每个像素,它会存储图元在这个像素最近的z值。这意味着当图元被渲染到某个像素上时,图元在这个像素位置的z值会被计算,并与z缓冲中相同像素位置存储的z值比较。如果新的z值比z缓冲存储的z值小,那么被渲染的图元在这个像素位置与相机的距离比之前记录的最近距离还要近。因此,这个像素的z值和颜色会被来自被绘制图元的z值和颜色更新。如果新的z值比z缓冲存储的z值小,那么什么都不做。z缓冲算法很简单,有着\(O(n)\)的时间复杂度,而且适用于任何被绘制的图元,只要图元在像素位置的z值是可以被计算的。还要注意这个算法允许大多数图元以任意顺序被绘制,这是另一个它受欢迎的原因。然而,z缓冲只为屏幕上的每个点存储单独的深度,因此它不能被用于部分透明的图元。这种图元必须在所有不透明图元被绘制后,以从后往前的顺序,或使用一个顺序无关的算法进行绘制。透明度是基础的z缓冲一个主要的弱点。
我们已经提到颜色缓冲会存储颜色,z缓冲会存储z值。然而,有其它通道和缓冲可以被用来过滤和捕捉片段信息。阿尔法通道(Alpha Channel)会与颜色缓冲相关联,它会存储与每个像素关联的不透明度值。在更老的API中,阿尔法通道被用来通过阿尔法测试特性来选择性地抛弃像素。如今,抛弃操作可以被插入像素着色器程序中,任何类型的计算都能被用来触发一次抛弃。这种类型的测试确保了完全透明的片段不会影响z缓冲。
模板缓冲(Stencil Buffer)是个离屏缓冲,它被用来记录被渲染图元的位置。每像素通常包含8比特。图元可以使用各种函数被渲染到模板缓冲上,缓冲的内容接着可以被用来控制渲染到颜色缓冲和z缓冲上的内容。假设有个实心圆被绘制到了模板缓冲上。通过模板缓冲,我们可以让只有实心圆存在的区域才有图元被绘制。模板缓冲是个强大的工具,能实现一些特殊效果。管线末尾的所有功能可以被称为光栅操作(Raster Operations,ROP)或混合操作(Blend Operation)。在像素着色阶段计算出的颜色可以与颜色缓冲当前存储的值混合。这能允许透明度或颜色样本的累积。之前提到过,混合通常是可配置的而不是完全可编程的。然而,有些API支持光栅顺序视图,也被称为像素着色器排序,它允许可编程的混合能力。
帧缓冲(Framebuffer)通常由系统上的所有缓冲组成。
当图元到达了光栅器阶段时,那些对于相机可见的图元会被显示到屏幕上。屏幕会显示颜色缓冲的内容。为了避免观察到图元正在被光栅化且被送到屏幕上,双重缓冲(Double Buffering)会被使用。这意味着场景的渲染会在一个叫后缓冲(Back Buffer)的地方离屏进行。一旦场景被渲染完了,后缓冲就会与被显示的前缓冲(Front Buffer)进行交换。交换通常发生在垂直回扫(Vertical Retrace)期间,在这段时间进行交换是安全的。
通过管线(Through the Pipeline)
点、线、三角形是组成模型和物体的渲染图元。想象应用程序是一个交互式计算机辅助设计(Computer Aided Design)应用程序,用户正在检查华夫饼机的设计。在这里,我们跟随模型穿过整个图形渲染管线的四个阶段。场景会通过透视渲染到屏幕上的窗口。在这个简单的例子中,华夫饼机模型包括线和三角形。华夫饼机有一个盖子能被打开。有些三角形会使用有着制造商Logo的二维图像进行纹理映射。对于这个例子,表面着色会完全在几何阶段进行,除了有纹理的应用外,它会在光栅化阶段进行。
应用程序(Application)
CAD应用程序允许用户选择和移动模型的部件。比如,用户可能选择盖子,接着移动鼠标并打开它。应用程序阶段必须把鼠标移动转换成对应的旋转矩阵,并确保在渲染时矩阵被正确应用于盖子。另一个例子是相机随着预定义的路径移动,从不同视角展示华夫饼机的动画。相机的属性例如位置和观察方向必须随着时间被应用程序更新。对于被渲染的每一帧,应用程序阶段都会设置相机位置、光照以及进入管线中下一个主要阶段的图元。
几何处理(Geometry Processing)
对于透视视图,我们假设应用程序已经提供了一个投影矩阵。此外,对于每个物体,假设应用程序已经计算出了一个矩阵描述物体的位置和朝向以及它的视图变换。在我们的例子中,华夫饼机的底座会有一个矩阵,盖子会有另一个矩阵。在几何阶段,物体的顶点和法线会使用这个矩阵变换到视图空间。接着在顶点的着色或其它的计算可能会进行。然后另一个单独的投影矩阵会被用来进行投影,把物体变换到单位立方体空间。所有可见的物体都会在这个空间中,那些在立方体外的图元都会被抛弃,而那些与单位立方体相交的图元都会被立方体裁剪。顶点接着被映射到屏幕上的窗口。在所有的逐三角形和逐顶点操作被执行后,结果数据会被传递到光栅化阶段。
光栅化(Rasterization)
在上一个阶段所有从裁剪存活的图元接着都会被光栅化,这意味着所有在图元内的像素会被找到并送往像素处理。
像素处理(Pixel Processing)
这里的目标是为了给每个可见图元的每个像素计算颜色。那些与任意纹理(图像)关联的三角形在这里会使用纹理映射进行渲染。可见度会通过z缓冲算法确定,伴随着可选的抛弃和模板测试。每个物体会依此被处理,最终的图像接着被显示在屏幕上。