2.2.2纹理资源
正如我们在最后几节中所看到的,有无数不同的缓冲区资源,以及为各种用途配置它们的许多不同方法。然而,缓冲区只是资源故事的一半。纹理为基于GPU作为渲染处理器的资源提供了不同的概念。
“纹理”一词指的是一种在性质上与图像或类似图像的内存资源。这是一个非常松散的定义,因为有一系列不同的纹理类型,具有不同的维度、拓扑和多重采样特性。这些使得“类图像”一词看起来有些不合时宜,因为有些纹理根本不是传统的二维图像。这些纹理资源和图像之间的共同联系是顶点元素的概念,它在所有纹理类型中都是相同的。像素(或纹理中所指的纹素)是所有纹理所包含的最小数据元素。每个像素最多由四个分量表示。组件的格式各不相同,具体取决于纹理资源的功能。
虽然纹理资源仍然是GPU可用的内存块(缓冲区资源也是如此),但额外的专用硬件可用于某些纹理操作,这可以提供比缓冲区上的相应操作更高的效率。这方面的一个例子是GPU中的纹理过滤硬件。由于额外的硬件,使用纹理资源在两个相邻数据元素之间进行插值比使用缓冲资源更快。此外,某些功能自然更适合纹理,例如渲染目标或深度模版目标。由于缓冲区和纹理具有不同的质量,因此必须针对特定情况选择适当的资源类型。此外,纹理支持使用mip贴图的能力,这对于渲染纹理映射的几何体时获得良好的性能和视觉质量至关重要。
我们将在本章中更详细地探索纹理资源类型。我们从关于纹理的一般性讨论开始,以及关于它们的用途和可用操作的一些具体细节。接下来将更详细地介绍在C++和HLSL中使用、创建和操作每种类型的纹理资源。
通用纹理属性
,纹理资源有ID、2D和3D版本。由于它们在尺寸上的差异,它们使用的特定内存布局彼此不同。这些类似于您期望在C/C++中看到的不同维度的数组之间布局的差异。作为从使用角度如何组织这些布局的指示,请考虑图2.21中所示的图形表示。即使使用不同的布局,纹理资源也共享许多其他特性。在继续研究每种纹理类型之前,我们将探索其中的一些常见特性。
如图2.21所示,纹理是根据熟悉的X、Y和Z轴排列的。该图还包括额外的轴描述,命名为U、V和W。这些表示Direct3D 11使用的纹理寻址方案,其中纹理在X、Y和Z方向上的总大小(无论大小)被映射到[0,1]的范围内。这样做是为了提供一种方便的纹理采样方法。如果在地址u=0.5处对一维纹理进行采样,则无论纹理是16个元素还是1600个元素,都将接收到位于纹理中点的元素。在执行采样时,这是一个非常重要的考虑因素,当我们在“采样器状态对象”一节中讨论采样器时,将进一步考虑这一点。
纹理资源mip贴图
所有不同类型的纹理都共享mip贴图的概念。mip贴图非常简单地表示纹理的低分辨率版本。纹理通常包含多个mip贴图级别,每个连续级别都提供纹理内容的自缩放副本。在最高级别的分辨率不会添加有用的信息,甚至可能有助于渲染工件的情况下,使用mip贴图可以实现较低分辨率的纹理查找。一个常见的例子是,在远离摄影机的地方渲染纹理模型,并且当模型移动时,应用于模型的纹理看起来闪闪发光。这是由于渲染图像的采样模式的分辨率远低于纹理内容的采样模式。通过查找适当的mip贴图级别来降低有效纹理分辨率,可以使两种采样模式更紧密地结合在一起,实际上消除了这种闪烁的效果。
图2.22显示了三种纹理类型的mip贴图。由于映射还减少了正在使用的资源的有效大小,因此它显著地减少了纹理缓存抖动,当纹理缓存由于加载了大量未使用的内存而不断被强制错过时,就会发生这种情况,这最终会导致非常高的内存请求延迟,并降低性能。
每个mip映射都被认为是资源本身中的一个子资源。每个mip映射级别沿每个维度将资源的大小减少两倍。mip贴图级别的数量受到包含单个纹理的最低级别的限制,这是合乎逻辑的,因为您不能降低1x1纹理的分辨率。我们将在本章后面介绍如何在创建资源视图时选择子资源,以及如何操作资源内容。
纹理资源数组
几种类型的纹理资源可以被创建为纹理数组。例如,可以将单个2D纹理创建为2D纹理子资源的数组。这允许单个资源包含所谓的许多单独的文本切片。如图2.23所示
当资源被创建为数组时,每个单独的纹理切片都可以被资源视图进行选择,并像使用独立的资源一样使用。这允许将纹理资源用作更高级别的数据结构,该数据结构在每个纹理切片中封装多个不同的内容。例如,访问多个纹理切片可以简化某些形式的纹理图谱,这些图谱本质上是包含多个单独纹理的纹理资源。然后,纹理图集可以用于多个对象渲染,这使它们可以连续渲染,而无需在绘制调用之间修改管道状态。对基于数组的资源的访问大大简化了这类技术。
可以为1D和2D纹理类型以及纹理立方体类型(这是2D纹理阵列的一种形式)创建纹理阵列,但不允许为3D纹理创建纹理阵列。在实践中,这种限制并不是真正的问题,因为具有3D纹理的阵列本质上代表4D数据资源。这种资源的内存消耗将随着每个维度中的资源大小而快速增长。然而,如果需要这样的数据结构,则应用程序可以简单地使用多个单独的3D纹理资源,或者可以简单地创建3D纹理,其中第三维度被指定为基本记录大小的倍数,并且可以由着色器程序手动索引,或者用选择资源的适当子区域的一系列资源视图来实现。
子资源
在讨论mip映射级别和资源的数组元素时,我们引入了子资源的概念。此名称用于标识资源的完整子部分。例如,纹理数组的每个元素的每个mip映射级别都是唯一的子资源。为了帮助选择特定的子资源,每个子资源都有一个子资源索引,通过该索引可以识别它。子资源索引的编号从阵列的第一个元素的最高分辨率mip映射级别开始,并为该元素内的每个mip映射级递增。计数在数组的第二个元素的最高分辨率mip映射级别上继续,并一直持续到所有资源都有索引为止。当我们在本章末尾考虑操纵资源的方法时,这些索引将非常重要。
纹理2D多采样资源
另一个选项可用于二维纹理资源,旨在提高图像质量。二维纹理可以创建为多采样纹理,并可用于实现多采样抗锯齿(MSAA)。这种资源类型背后的想法是,对于每个像素,多个子样本实际上存储在像素边界内的模式中。当进行渲染时,这些子样本用于在子像素级别上确定一个像素应该从正在光栅化的给定基元接收到的覆盖量。这使得每个像素都可以从多个子采样中生成,从而通过有效地提高渲染目标的采样率来提高几何体边缘的质量。具有asubsample模式的示例像素如图2.24所示
根据硬件支持,应用程序最多可以选择32个子样本。在“纹理2D”部分,我们将看到如何为给定的硬件配置创建具有有效样本数的纹理。使用MSAA时必须小心,因为所讨论的资源消耗的内存量实际上是所使用的子样本数的乘积。关于MSAA为什么有用的更多细节,以及如何使用这些资源的信息,请参见第3章的“光栅化器”、“像素着色器”和“输出合并”部分