D3D12渲染技术之渲染管线
渲染管线指的是通过虚拟相机看到的内容生成2D图像的整个步骤序列,在博客D3D12渲染技术概述中介绍过渲染管线,本篇博客具体讲解各个模块的作用,先看下图所示:
- Input Assembler Stage
上图中Input Assembler Stage表示的是从存储器读取几何数据(顶点和索引)并使用它来组装几何图元(例如,三角形,线条)。 (简单地说,它们定义了如何将顶点组合在一起以形成基元。)
Vertices
先看看点的概念,我们使用的3D模型,它们都是由点组成的,比如下图所示的:
从本质上讲,Direct3D中的顶点可以包含除空间位置之外的其他数据,这使我们可以执行更复杂的渲染效果。 Direct3D使我们可以灵活地定义自己的顶点格式,可以根据正在进行的渲染效果定义几种不同的顶点格式。-
Primitive Topology
顶点缓冲区只是将一个顶点列表存储在连续的内存中, 但是,它没有说明如何将这些顶点组合在一起形成几何图元。 例如,顶点缓冲区中的每两个顶点是应该解释为一条线还是应该将顶点缓冲区中的每三个顶点解释为三角形? 我们告诉Direct3D如何通过指定原始拓扑从顶点数据形成几何图元:
void ID3D12GraphicsCommandList::IASetPrimitiveTopology(
D3D_PRIMITIVE_TOPOLOGY Topology);
typedef enum D3D_PRIMITIVE_TOPOLOGY
{
D3D_PRIMITIVE_TOPOLOGY_UNDEFINED = 0,
D3D_PRIMITIVE_TOPOLOGY_POINTLIST = 1,
D3D_PRIMITIVE_TOPOLOGY_LINELIST = 2,
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP = 3,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST = 4,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP = 5,
D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ = 10,
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ = 11,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ = 12,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ = 13,
D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST = 33,
D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST = 34,
.
.
.
D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST = 64,
} D3D_PRIMITIVE_TOPOLOGY;
所有绘图调用将使用当前设置的基本拓扑,通过命令列表更改拓扑, 以下代码说明:
mCommandList->IASetPrimitiveTopology(
D3D_PRIMITIVE_TOPOLOGY_LINELIST);
/* …draw objects using line list… */
mCommandList->IASetPrimitiveTopology(
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
/* …draw objects using triangle list… */
mCommandList->IASetPrimitiveTopology(
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
/* …draw objects using triangle strip… */
另外还有Point List,Line Strip,Line List,Triangle Strip,Triangle List等,这些在D3D9中就讲解过,这里就不重复了,再介绍下一个阶段:
-
Vertex Shader Stage
在组合基元后,将顶点送到顶点着色器阶段, 顶点着色器可以被认为是输入顶点并输出顶点的函数。 绘制的每个顶点都将通过顶点着色器进行抽取;事实上,我们可以考虑硬件上发生的以下情况:
for(UINT i = 0; i < numVertices; ++i)
outputVertex[i] = VertexShader( inputVertex[i] );
顶点着色器函数是我们实现的,但它由GPU为每个顶点执行,因此它非常快。
我们可以在顶点着色器中执行许多特殊效果,例如变换,光照和置换贴图。 请记住,我们不仅可以访问输入顶点数据,还可以访问存储在GPU内存中的纹理和其他数据,例如转换矩阵和场景灯光。
顶点着色器一个重要的能力就是处理各种矩阵变换,这个也是一个老问题了,在我写的以前博客中有关于这方面的介绍可编程流水线和固定流水线,这里就不重复了。
-
Tessellation Stage
Tessellation是指细分网格的三角形以添加新的三角形,比较常见的是LOD算法用的就是Tessellation。
我们可以实现细节层次(LOD)机制,其中相机附近的三角形被细分以添加更多细节,并且远离相机的三角形不被细分。
在内存中保留一个更简单的低多边形网格(低多边形意味着低三角形数),并在运行中添加额外的三角形,从而节省内存。也可以在更简单的低多边形网格上执行动画和物理等操作,并且仅使用细分的高多边形网格进行渲染。
曲面细分阶段是Direct3D 11的新功能,它们提供了一种在GPU上细分几何体的方法, 在Direct3D 11之前,如果您想要实现一种曲面细分形式,则必须在CPU上完成,然后必须将新的曲面细分几何体上传回GPU进行渲染。 但是,将新几何体从CPU内存上传到GPU内存的速度很慢,并且还会增加CPU计算细分的负担。 出于这个原因,在Direct3D 11之前,曲面细分方法对于实时图形并不是非常流行。Direct3D 11提供了一个API,可以在具有Direct3D 11功能的视频卡的硬件中完全进行曲面细分。 这使细分成为一种更具吸引力的技术。 曲面细分阶段是可选的(如果要进行曲面细分,则只需使用它)。
Geometry Shader Stage
几何阶段处理很重要的,很多效果都是基于此完成的,我们后面会做详细的介绍,几何着色器很强大,举个例子,如果我们绘制三角形列表,那么几何着色器的输入将是定义三角形的三个顶点。 (请注意,三个顶点已经通过顶点着色器。)几何着色器的主要优点是它可以创建或销毁几何体。 例如,输入基元可以扩展为一个或多个其他基元,或者几何着色器可以选择不基于某些条件输出基元。 这与顶点着色器形成对比,顶点着色器无法创建顶点:它输入一个顶点并输出一个顶点, 几何着色器的常见示例是将点扩展为四边形或将线扩展为四边形。Rasterization Stage
光栅化阶段的主要工作是从投影的3D三角形计算像素颜色,它包括视口变换,背面剔除,顶点插值等,读者可以参考我以前写的博客,这里就不介绍了。。。。Viewport Transform
视口转换剪切后,硬件可以进行透视裁剪,从均匀裁剪空间转换为规范化设备坐标(NDC)。 一旦顶点位于NDC空间中,形成2D图像的2D x和y坐标将转换为后视缓冲区中称为视口的矩形。 在该变换之后,x坐标和y坐标以像素为单位, 通常视口变换不会修改z坐标,因为它用于深度缓冲,但它可以通过修改D3D12_VIEWPORT结构的MinDepth和MaxDepth值来实现, MinDepth和MaxDepth值必须介于0和1之间。Pixel Shader Stage
像素着色器也是在GPU上执行的程序, 为每个像素片段执行像素着色器,并使用插值的顶点属性作为输入来计算颜色,既可以执行简单的返回颜色操作,也可以执行更复杂的操作,例如每像素照明,反射和阴影效果。Output Merger Stage
在像素着色器生成像素片段之后,它们移动到渲染管线的输出合并(OM)阶段。 在该阶段,可以拒绝一些像素片段(例如,从深度或模板缓冲器测试),未被拒绝的像素片段被写入后缓冲区, 在此阶段也进行混合,其中像素可以与当前在后缓冲器上的像素混合而不是完全覆盖它。总结:
以上讲解的都是关于D3D12渲染管线的理论知识,我们要搞清楚渲染管线的每个阶段负责哪些事情,后面的博客我们会讲解具体如何使用。
上一篇: D3D12渲染技术之顶点着色器
下一篇: D3D渲染技术之简易框架