Skip to content

渲染管线

色彩基础

颜色运算

颜色的表示使用3d向量\((r,g,b)\),且适用包括加减法、标量乘法在内的运算规则。此外,颜色向量有特殊的分量式运算:

\[(c_{r},c_{g},c_{b} ) \otimes ( k_{r},k_{g},k_{b})=(c_{r}k_{r},c_{g}k_{g},c_{b}k_{b})\]
分量式的应用

分量式主要应用于光照方程。例如,假设有颜色\((r,g,b)\)的入射光线,照射到一个反射50%红光、75%绿光、25%蓝光并吸收剩余光的表面,那么反射光线的颜色为:

\[(r,g,b ) \otimes (0.5,0.75,0.25)=(0.5r,0.75g,0.25b)\]

如果在归一化的颜色运算过程中,颜色分量的其中一个值大于\(1.0\)或小于\(0.0\),则将其clamp(钳制)为\(1.0\)\(0.0\)

除rgb外,颜色向量通常还会涉及alpha分量,用于表示opacity。alpha分量和r,g,b构成一个4d向量,如果给每个分量分配\(32\)位浮点数数据进行存储,则共计\(128\)位,符合XMVECTOR的对齐标准,也能适用于DirectXMath。

DirectXMath提供了分量式的运算方法:

XMVECTOR XM_CALLCONV XMColorModulate(FXMVECTOR C1,FXMVECTOR C2);

渲染管线概述

若给出某个3d场景的几何描述,并在其中架设一台已知位置和朝向的虚拟摄像机,那么渲染管线就是以此摄像机为观察视角生成2d图像的一系列完整步骤。

渲染管线按时序分为输入装配、顶点着色器、外壳着色器、曲面细分、域着色器、几何着色器、流输出、光栅化、像素着色器和输出合并。

5111

输入装配器阶段Input Assemsbler

图元拓扑方式

  1. 点列表
  2. 线条带
  3. 线列表
  4. 三角形带
  5. 三角形列表
  6. 具有邻接数据的图元拓扑
  7. 控制点面片列表

索引 index

为三角形指定的顶点顺序叫绕序(winding order)。

顶点绕序

规定三角形正面的顶点连接顺序为顶点绕序,分为顺时针和逆时针。D3D的默认规定中,三角形正面朝向观察者时,顶点绕序为顺时针。
这一顺序可以通过设置D3D的渲染状态来修改。

复制顶点是指被多个三角形共用的顶点,为避免复制顶点在渲染管线中被重复存储和计算,一种解决方案是使用索引
即使用一个顶点列表存储所有顶点的信息,使用一个类型为UINT的索引数组存储每个三角形的顶点信息,但在索引数组不存储顶点的原始信息,而是存储每个顶点在顶点列表中的索引。

对于复杂几何体,顶点数组中的顶点顺序和索引数组中的三角面(三个顶点索引为一组)顺序以优化GPU缓存命中率为主要目的。
其中,索引数组中的三角面顺序采用空间局部连续性算法,由各个三角面的空间连续性决定,在几何体中相邻和共用顶点的三角面在索引数组中也会相邻,以实现在绘制时的连续性。这种优化通常在3D建模软件的导出或向引擎中导入模型的过程中就已完成,常用的算法有 Forsyth 算法 、Tipsify 算法。
顶点数组的重排列在索引数组的重排列后进行,按照索引数组的顺序将顶点不重复地排列。

顶点着色器阶段 vertex shader stage

这一阶段由GPU执行,顶点着色器可以近似视为输入输出均为单个顶点的函数。顶点着色器可以实现变换、光照和位移贴图等。

坐标系变换

世界空间

即全局坐标系。

局部空间

即以单个对象的坐标为原点的简易坐标系。

从局部空间到世界空间的遍传成为世界变换,其变换矩阵称为世界矩阵

世界变换

已知局部空间转世界坐标的变换为\(W=SRT\),其中\(S\)代表该局部空间坐标系的原点在世界坐标中的缩放,\(R\)代表在世界空间中的旋转,\(T\)代表在世界空间的位置(平,移矩阵)。

若有坐标 \(v\) 为以行向量表示的局部空间坐标,则 \(vW\) 为该坐标的世界空间表示。

需要注意,在DirectX中平移矩阵 \(T\) 的平移分量应在最后一行而非最后一列。

观察空间

即位于摄像头可见区域内的空间。

从世界空间到观察空间的变换称为取景变换,变换矩阵称为观察矩阵(View Matrix),其形式为:

\[\begin{bmatrix} u_{x} & v_{x} & w_{x} & 0 \\ u_{y} & v_{y} & w_{y} & 0 \\ u_{z} & u_{z} & w_{z} & 0 \\ -Q*u & -Q*v & -Q*w & 1\end{bmatrix}\]
根据世界空间定义观察空间

已知\(Q\)为摄像机的坐标,\(T\)为摄像机对准的目标点,\(j\)为世界空间中表示向上的向量。则摄像机的观察方向也是观察空间的z轴,表示为:

\[w=\frac{T-Q}{\parallel T-Q \parallel } \]

同时可得与\(w\)垂直、指向观察空间右侧的向量表示为:

\[u=\frac{j\times w}{\parallel j\times w \parallel } \]

最后,同时与\(w\)\(u\)垂直的向量表示为:

\[v=w\times u\]

其中,\(w\)是观察空间的\(z\)轴在世界空间的表示,\(u\)是观察空间的\(x\)轴在世界空间的表示,\(v\)则是\(y\)轴。

由此可得,只要得知摄像机的位置、观察目标的位置和世界空间中表示方向的坐标,就能推导出观察空间。DirectXMath提供了以下方法用于计算观察矩阵:

1
2
3
4
5
XMMATRIX XM_CALLCONV XMMatrixLookAtLH(
    FXMVECTOR EyePosition,   // 摄像机的坐标,即Q
    FXMVECTOR FocusPosition,   // 观察目标的空间,即T
    FXMVECTOR UpDirection);  // 世界空间坐标系中表示向上的向量,即j
)

投影和齐次裁剪空间

曲面细分阶段 Tessellation Stages

可选阶段,略,见14章

几何着色器阶段 Geometry Stages

可选阶段,略,见12章

裁剪 Clip

完全位于视锥体外的几何体需要被丢弃,部分位于视锥体外的几何体也需要将外部的部分裁剪。裁剪后,得到的几何体一定是一个任意内角都小于180°的凸多边形

一种比较流行和核心的裁剪算法是苏泽兰-霍奇曼裁剪算法,但频繁的裁剪不利于现代GPU并行操作,因此引入了保护带裁剪(Guard-Band Clipping)。

光栅化 Rresterzation Stage

这一阶段主要在为投影到主屏幕上的3D三角形计算对应的颜色。

视口变换

通过透视除法\((x/w, y/w, z/w)\)将坐标转换为规格化设备坐标(Normalized Device Coordinates,NDC),随后将归一化的NDC从\([-1,1]\)的范围变换到符合屏幕分辨率的矩形里,这个矩形称为视口(viewport)。

视口变换后,坐标就从三维降维到了二维,其中z轴并未被丢弃,而是映射到了深度缓冲区。深度缓冲区的值范围通常是\([0,1]\),其中0为视锥体的近平面,1为远平面。

深度缓冲区和NDC的z轴范围

OpenGL的规定中,这两者的范围被设计为与\(x\)\(y\)轴保持一致的\([-1,1]\),但现代图形api(D3D、Vulkan和Metal等)规定其范围是\([0,1]\)

这是因为IEEE 754 浮点数的精度分布特性。浮点数基于二进制的科学计数法设计(\(\text{尾数} \times 2^{\text{指数}}\)),这导致数值越接近 0,浮点数的刻度越密集,精度越高;数值越大,精度越低。

在 OpenGL 的 \([-1, 1]\) 范围内,负数区间 \([-1, 0)\) 造成了严重的编码浪费,且精度最高的区域集中在 \(0\)(视锥体中间),无法满足“近平面或极远景需要高精度”的实际需求。现代 API 统一使用 \([0, 1]\) 范围,其最大优势是能完美配合反转 Z(Reversed-Z)技术 , 将近平面映射为 1,远平面映射为 0。利用“越接近 0 精度越高”的浮点数特性,补偿了透视投影对远景深度的严重压缩,从而极大地消除了远景的深度冲突。

背面剔除

若组成三角形的三个顶点顺序为\(v_0\),\(v_1\),\(v_2\),则三角形的法线\(n\)通过如下方式计算:

\[\begin{aligned}e_0=v_1-v_0 /n \\ e_1=v_2-v_0 \\ n=\frac{e_0 \times e_1}{\| e_0 \times e_1 \|}\end{aligned}\]

规定法向量指向的方向为三角形的正面,另一面则为背面,三角面的不同面有绕序的区别。

对于使用正面朝外的三角面进行建模的实体对象,绘制背面朝向观察者的三角面没有意义。背面剔除的目的是将这些三角形从渲染管线中丢弃。

光栅化

狭义上的光栅化指这一阶段,通过三角形的三个顶点计算三边的数学公式,遍历三角形包围盒(完整包含该三角形的最小矩形)中的每一个像素,对每个在三角形内部的像素生成一个片元,片元会携带像素的空间与位置信息、插值后的顶点属性和部分系统内置状态。

片元

即像素片段,一个最终被渲染出的像素往往对应多个像素片段,这些候选的像素片段经过深度测试后才能决定哪一个最终能够被显示在屏幕上。

Early-Z 是光栅化后的一个可选阶段,它会对深度进行预处理,以避免在进入像素着色器后计算大量最终不会被显示的像素片段。但Early-Z存在一定的局限性,如果后续的像素着色器阶段丢弃了片元,那么Early-Z 可能就会失效。

顶点属性插值

通过顶点属性插值,根据三角形的三个顶点存储的数据计算三角形内部的像素的颜色、深度等信息,这种算法叫透视校正插值

像素着色器 Pixel Shader

由GPU执行,对每个像素片段进行处理,计算最终输出的颜色。像素着色器阶段是整个渲染管线中最耗算力也最出效果的阶段。

像素着色器可以丢弃(discard)片元,以实现透明和镂空效果。

输出合并阶段 Output Merger

执行模板测试、深度测试和混合。

输出合并阶段完成后,数据会分别被写入后台缓冲区和深度/模板缓冲区。

深度测试

根据片元的深度信息决定片元是否需要被显示。