3.11.1像素着色器管道输出
像素着色器阶段从光栅化器阶段接收其输入片段。这意味着像素着色器程序将使用的输入属性也由光栅化器生成。我们已经在光栅化器部分看到,它基于被光栅化的基元内片段的采样位置生成插值属性数据,该位置通常是像素的中心(尽管有时来自其他采样位置)。我们还看到,可以在像素着色器程序中指定各种插值修改器关键字,该程序将指示光栅化器为每个输入属性使用特定的插值模式。这些插值模式在不同的场景中都很有用,必须适当选择,以确保正确计算输入属性。我们将在这里更详细地探讨这些插值模式。
1.属性插值/Attribute Interpolation
插值属性的过程需要三条不同的信息。第一个是将被插值的数据——被插值的基本体的顶点的属性。这包括它们的位置和属性值。插值所需的第二条信息是需要插值属性数据的点的位置。这或多或少决定了插值值将接收到每个顶点属性的多少。所需的最后一条信息是应该使用的插值技术。该最后一项对上述前两项执行实际插值。插值模式由使用像素着色器输入签名声明的插值修饰符决定。
线性模式插值
使用线性插值模式时,为每个片段生成的属性将进行线性插值,同时考虑透视效果。透视正确插值的需要源于这样一个事实,即透视投影不是线性运算,并且这种插值是在投影之后执行的。这意味着标准的线性插值不能在空间中的顶点之间使用,而是必须考虑每个顶点的深度。
透视效果可以在插值过程中通过在插值之前将每个顶点属性除以其距查看器的深度来说明。每个顶点的深度值都是在投影后,但在转换为标准化设备坐标之前作为其(W值)。还计算W的倒数,然后与这些修改后的属性一起插值。在为每个光栅化的片段插值所有这些值后,使用W的插值倒数提取原始所需属性,这将产生透视校正插值。这是最常见的插值模式,三维模型上的纹理坐标提供了一个完美的示例,说明何时需要这些坐标。透视校正插值不仅适用于纹理坐标,而且适用于线性空间(如世界空间或视图空间)的位置或方向矢量(或任何其他线性属性))进入投影后阶段。
透视模式插值noperspective mode
使用透视插值模式时,插值属性将根据其在渲染目标上的二维位置进行严格插值。本质上,在执行插值之前,可以将几何体视为投影到下一个目标上。此插值模式根据顶点的位置在顶点之间实现标准线性插值。只要被插值的顶点都在同一深度,就可以在没有透视校正的情况下进行属性插值,例如在构建屏幕用户界面渲染时。
质心模式插值The centroid mode
质心插值模式旨在为MSAA渲染模式中的特殊情况提供更合适的插值模式。当一个像素被基元部分覆盖并且MSAA被启用时,光栅化器将为该像素生成一个片段。然而,如果基元仅覆盖像素内的几个样本,而不覆盖像素的中心,则正常线性插值模式仍将使用像素的中心作为插值函数的输入位置。因此,在仅覆盖一部分样本位置的情况下,顶点属性可能被外推到三角形的真实边缘之外。对于不需要外推法的情况,可以通过在输入变量声明中添加质心修饰符,在每个属性的基础上使用质心采样。使用时,质心采样会将受影响的属性插值到保证被三角形覆盖的点。所使用的位置是具体实施的,但一般位于覆盖的样本点的平均值。
采样模式插值The sample mode
采样插值模式在MSAA渲染模式中使用的每个采样点提供插值。当为每个MSAA样本执行像素着色器以在每个单独的样本位置提供属性时,这很有用。MSAA主题及其与像素着色器的关系将在下一节中进一步讨论。
2.多样本消除混合Multisample Anti-Aliasing
可以将几个附加的系统值语义声明为像素着色器的输入,以便在启用MSAA时为控制其行为提供一些有趣的可能性。Direct3D11提供了几种可以更改“标准”MSAA行为的方法。这些更改基于绑定到管道的像素着色器,以及它如何解密输入和输出属性。
预采样执行Per-sample execution
第一个这样的修改是可以为每个子样本运行像素着色器,而不是每个像素运行一次。当像素阴影处理带有SV_SampleIndex系统值语义附加的输入时,会触发此行为,该系统值提供当前正在处理的子样本的索引。如果输入属性标记为采样插值模式,则也会触发此操作。我们将在本节稍后更详细地讨论SV_SampleIndex的使用。
子样本覆盖Subsample coverage
与MSAA系统的第二种可能交互涉及SV_Coverage系统值语义的使用。当使用此语义解密输入属性时,它会提供一个无符号整数值,其中每个位对应于当前像素的一个子样本。这基本上向像素着色器指示在光栅化期间哪些子采样被检测为被光栅化器阶段覆盖。稍后我们将看到该系统值语义如何也可以用作输出属性,以对将与像素着色器的结果一起写入的选定子样本执行自定义修改。这允许实现自定义覆盖掩码,这通常用于alpha到覆盖算法。
3.碎片定位Fragment Location
另外两个系统值语义可以作为像素着色器的输入来访问,以识别片段的位置,即片段最终写入的位置。这些属性可以用于帮助像素着色器程序处理片段。
源位置Source position
当像素着色器声明具有SV_Positionsystem值语义的输入属性时,像素着色器将接收光栅化器阶段生成的四坐标片段位置。一般来说,这个位置最重要的部分是X和Y坐标,它们指示碎片在当前渲染目标中的位置。在大多数情况下,这些坐标将指示具有0.5像素偏移的像素中心位置。当使用多个纹理生成像素着色器结果时,这可用于识别其他纹理中需要采样的位置。一个常见的例子是使用多个纹理作为延迟渲染的G-buffer。
除了像素中心位置,还可以使用该系统值语义来获得当前片段的质心位置。如上所述,中心位置保证在原始边界内,并且通常用于确保用于插值的坐标不会延伸到原始边界之外。如果使用质心插值修改器来声明该语义值,则可以接收插值中使用的质心值。
光栅化器阶段生成的深度值也可从SV_Position系统值语义中获得。这是归一化的设备坐标深度,因此其值将在[0,1]的范围内。这可用于在使用此深度信息的像素着色器内执行计算,也可用于使用自定义深度值修改光栅化生成的深度值。我们将在本节后面看到像素着色器如何使用SV_depth系统值语义修改其深度值。
片段目的Fragment destination
除了能够接收生成片段的位置之外,片段的最终目的地也可以声明为输入。如果有一个标准的、非数组的渲染目标绑定用于接收来自管道的输出,则片段的输出位置或多或少由上面讨论的SV_position语义来描述。但是,如果使用基于阵列的渲染目标来生成场景的多个同时渲染,则还必须使用渲染目标阵列索引来确定片段最终写入的位置。这通常用于生成各种形式的环境映射,如第13章所示。
管道通过解释SV_RenderTargetArrayIndex系统值语义来确定要将基元应用于哪个渲染目标切片。此参数也可以用作像素着色器的输入属性。这允许像素着色器程序对片段执行选择性处理,该处理取决于最终接收片段的渲染目标切片。
4.几何定向Geometric Orientation
我们可以为像素着色器的输入声明的最后一个专用输入属性是SV_IsFrontFace系统值语义。该参数提供生成片段的基元的方向的指示。这是一个布尔属性,当片段由前向基元生成时为true,而当片段由后向基元产生时为false。您可能还记得,光栅化器状态可用于确定哪个顶点缠绕定义了基本体的前向方向,以及要剔除这些方向中的哪些。如果允许对两个方向进行光栅化,则此系统值将指定光栅化器阶段检测到的方向。由于点和线基元没有方向的概念,因此从这两种基元类型中的任何一种生成的片段都将始终为此输入属性生成true值。但是,如果在线框模式下光栅化三角形基本体(这基本上从三角形的边生成线),则仍然使用三角形方向信息。