2.2.3采样器状态对象
本节中考虑的最后一个对象是采样器状态对象。采样器状态对象用于指定着色器程序对纹理资源进行采样时使用的所有参数。对纹理进行采样的过程包括查找纹理资源的几个像素,并将它们与开发人员选择的机制相结合,以减少几种常见的伪影,并提高纹理查找操作的性能。所有主要的GPU设计都包括额外的硬件功能来实现这些采样操作,因此使用它们通常比从可编程着色器中模拟相同的采样过程快得多。
可以使用采样器状态对象指定的选项包括用于确定要采样的位置的纹理坐标寻址模式、采样过程中要执行的过滤类型、几个LOD参数、纹理的边框颜色以及可用于修改采样函数返回的数据的比较函数。这提供了一系列可以执行的不同类型的采样,这些选项可以对纹理采样操作的性能产生很大影响。因此,对于正在采样的纹理的意图消除情况,正确配置对象是很重要的。
采样器状态对象实际上不是与缓冲区和文本相同意义上的资源,但它们是像可编程管道中的资源一样管理的,所以我们在这里将它们包括在内。我们将在以下章节中更详细地探讨它们,首先考虑它们是如何创建的,然后简要回顾它们在可编程着色器阶段中的使用方式。
创建采样器状态对象
在了解采样器对象如何在着色器程序中使用的细节之前,我们首先需要了解它到底能做什么。最好通过查看用于创建采样器对象的过程来描述这一点,因为在创建过程中必须指定其所有各种选项。与我们在本章中看到的其他对象类型一样,采样器状态对象是通过填写描述结构,然后将该结构传递给设备方法来创建的。在这种情况下,我们使用ID3DllDevice::CreateSamplerState()方法来生成ID3DllSamplerSate对象。
struct D3D11_SAMPLER_DESC {
D3D11_FILTER Filter;
D3D11_TEXTURE_ADDRESS_M0DE AddressU;
D3D11_TEXTURE_ADDRESS_M0DE AddressV;
D3D11_TEXTURE_ADDRESS_M0DE AddressW;
FLOAT MipLODBias;
UINT MaxAnisotropy;
D3D11_C0MPARIS0N_FUNC ComparisonFunc;
FLOAT BorderColor[4];
FLOAT MinLOD;
FLOAT MaxLOD;
}
第一个参数可能是所有参数中最明显的。Filter结构成员指定在采样过程中在几种不同情况下执行的过滤类型。纹理缩小、放大和mip映射都是不同类型的采样操作,可以应用不同的过滤质量。
当纹理出现在离查看器足够远的位置,使其单个像素(通常称为纹理像素,是纹理像素的缩写)小于输出渲染目标像素时,就会发生纹理缩小。因为纹理中的纹素小于屏幕像素,所以当多个纹素从一帧到另一帧穿过一个像素时,纹理可能会显得闪闪发光或弹出。如果选择适当的过滤机制,这种影响可以大大减少,甚至消除。纹理放大发生在相反的情况下。当近距离观察纹理时,单个纹素将覆盖多个屏幕像素,从而产生“块状”外观。在某些情况下,这是所需的行为,但在其他情况下,如果对纹理进行过滤以降低大纹素的可见性,则可以生成质量更好的图像。最后要考虑的纹理采样情况是mip映射。我们已经在本章前面的纹理资源讨论中讨论了mip映射。本质上,mip贴图提供纹理资源的多分辨率表示,并且可以指定在mip贴图采样过程中执行的过滤类型.
描述结构有一个筛选器参数,它表示这三个筛选场景都是用一个枚举指定的。可用的过滤模式如清单2.48所示。正如您所看到的,每个枚举的过滤器类型都指定了在上述三个条件下如何对纹理进行采样——MIN对应于纹理缩小,MAG对应于纹理放大,MIP对应于文本MIP映射.
enum D3D11_FILTER {
D3D11_FTLTER_MIN_MAG_MIP_P0INT,
D3D11_FILTER_MIN_MAG_P0INT_MIP_LINEAR,
D3D11_FILTER_MIN_P0INT_MAG_LINEAR_MIP_P0INT,
D3D11_FILTER_MIN_P0INT_MAG_MIP_LINEARJ
D3D11_FILTER_MIN_LINEAR_MAG_MIP_P0INTJ
D3D11_FILTER_MIN_LINEAR_MAG_P0INT_MIP_LINEARJ
D3D11_FILTER_MIN_MAG_LINEAR_MIP_P0INTJ
D3D11_FILTER_MIN_MAG_MIP_LINEARJ
D3Dll_FTLTER_ANISOTROPIC,
D3Dll_FILTER_COMPARISON_MIN_MAG_MIP_POINT,
D3Dll_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR,
D3Dll_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINTJ
D3D11_FILTER_C0MPARIS0N_MIN_P0INT_MAG_MIP_LINEAR,
D3D11_FILTER_C0MPARIS0N_MIN_LINEAR_MAG_MIP_P0INT,
D3Dll_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
D3Dll_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINTJ
D3Dll_FILTER_COMPARISON_MTN_MAG_MIP_LINEARJ
D3Dll_FILTER_COMPARISON_ANISOTROPICJ
D3D11_FILTER_TEXT_1BIT
}
对于这些场景中的每一种,可用的滤波类型都是点采样、线性采样和各向异性采样。点采样只是返回输入纹理坐标所在的纹理元素。这是最便宜的采样形式,但在大多数情况下也会产生最低的图像质量。线性采样提供了更高质量的采样,其中对输入纹理坐标周围的纹素进行插值,以在所选纹素之间的某个位置找到近似值。这会在纹素之间产生更平滑的转换,但除了在返回结果之前对采样数据执行一些算术运算外,还需要读取额外的纹素。最后一种选择是使用各向异性采样,这是一种质量高得多的采样技术。当以不垂直于相机视线的任何角度观看纹理时,各向异性过滤会执行多个采样,以确定观看者可见的平均颜色,并返回该组合颜色。最大样本数在采样器状态描述结构的Max各向异性参数中指定。尽管这种滤波模式产生了最好的结果,但由于产生最终样本值所需的带宽和计算量要高得多,因此使用它可能会非常昂贵。
在D3Dll_FILTER枚举的前半部分中,我们看到了可以使用的各种过滤类型的组合。在枚举的后半部分,我们看到了与前半部分列表的重复,只是在值名称中添加了COMPARISON。这表明,在组合结果之前,采样过程中使用的每个单独样本都将用于比较函数(稍后将进行讨论)。这允许对比较结果进行过滤,而不是先过滤文本然后进行比较。
采样器描述结构中的下三个选项指定了与纹理的X、Y和Z坐标相对应的U、V和W方向上的纹理寻址模式。这些模式允许您指定在采样期间使用[0,1]范围之外的纹理坐标时要采取的操作。可以为每个方向指定不同的寻址模式。当纹理坐标大于1时,可以让采样器将其重新包裹到0,从而有效地再次“包裹”纹理。如果纹理坐标大于2,纹理将被再次包裹,以此类推。这允许纹理的许多副本出现在有纹理的表面上。另一种可能的模式是镜像寻址模式,它本质上在每个整数坐标上翻转纹理。这也允许纹理的许多副本可见,但会翻转纹理的每个连续副本的方向。您还可以指定一个钳制模式,在该模式中,纹理坐标被“钳制”到[0,1]范围。这样可以有效地使纹理的边界值显示在纹理之外的任何位置。此模式的另一种选择是边界寻址模式,在该模式中,当坐标在[0,1]范围之外时,采样器状态可以指定替换颜色以返回。边界颜色是在采样器描述对象的BorderColor参数中指定的。最后,您可以使用一次镜像模式,在该模式中使用纹理坐标的绝对值,然后以与箝位纹理寻址模式相同的方式进行箝位。
MipLODBias、MinLOD和MaxLOD参数都用于操纵采样过程中使用的mipmap级别。最小和最大参数指定了采样期间可以访问的最小和最大级别,而biasparameter提供了一个恒定的偏移量,以添加到采样硬件选择的mip映射级别。在所有这些参数中,0是最详细的mip-map级别,因此添加正偏差将选择不太详细的mip-map级别。
采样器状态描述结构中的最后一个成员是ComparisonFuncparameter。这指示在执行过滤操作之前应该对纹理样本执行何种类型的比较。比较中使用的另一个值在纹理对象采样方法调用中提供。如果比较通过,结果为1;如果比较失败,结果为0。然后根据所选的过滤方法将每个单独比较的结果进行组合,并返回。
使用采样器
要使用采样器对象,必须首先按照上面的详细说明创建它,然后将其绑定到一个可编程管道阶段。每个可编程级可以同时绑定多达16个不同的采样器对象,并且同一采样器状态对象可以同时在多个可编程级中使用。在状态对象绑定到管道阶段后,将在该阶段运行的HLSL程序必须声明一个适当的HLSL采样器状态对象,该对象对应于特定的采样器槽。然后,着色器程序可以将SamplerState对象传递给各种纹理资源类型提供的多种采样方法之一。通过在采样方法中必须传递SamplerState对象作为自变量,D3D11允许一个der程序中的多个纹理资源同时使用相同的采样对象。由于着色器程序中可以使用大量可用资源(最多128个),如果多次需要相同的选项集,共享这些状态将带来显著的好处