D3D10/D3D11中的纹理资源

【翻译】D3D10/D3D11中的纹理资源

本文翻译自DXSDK,其中DX11与DX10相一致,故只翻译了DX10部分。
翻译:Chu @ XDU 2012/11/19
转载请注明出处。

纹理资源

纹理资源是一种被设计用来结构化储存一系列像素的集合。不同于缓冲(Buffer),纹理可以在被Shader单元使用的时候被纹理采样器(Texture Sampler)过滤(Filter)①。纹理的类型决定了纹理是如何被过滤的。一个像素代表了能在管线中被读写的最小单位。每个像素由1到4个部分组成②,对应DXGI格式(见DXGI_FORMAT)中的一种。

译注:①Shader读取纹理的时候由于有纹理采样器的影响,所得到的并不一定是原始的像素数据,而是经过插值等操作的结果,这是纹理区别于Buffer 的地方。②以RGB为例,一个像素使用RGBA(GL与DX10/11相同,对应DX9中的ARGB,其中A为Alpha通道)四个通道来表示,故由四部 分组成,若每个部分使用一个byte表示,那么一个像素的大小就是4字节,对应DXGI_FORMAT_R8G8B8A8_*

纹理被作为一种结构化资源创建,故其大小未知。一个纹理可能在创建的时候指明或者没有指明格式,无论如何只要当纹理被作为资源视图(Resource View)绑定到了管线上,那么它的类型必须是精确定义的。

纹理类型

这里有这样几种纹理格式:1D,2D,3D,每种纹理可以包含或者不包含Mipmap。D3D10还支持纹理数组(Texture Array)和多重采样纹理(Multisampled Texture)。

一维纹理(1D Texture)

一维纹理用最简单的形式来储存纹理数据,所以能够使用一维纹理坐标进行定位。它能够被直观的看做一个一维的像素数组,如下图所示。

 每一个像素遵照格式定义由一些颜色分量组成。你也可以像下图一样为之增添Mipmap。

 每个Mipmap细节是一个原始纹理二分之一大小的纹理。越上的层次包含了更多的细节,之后的层次将会越来越小。以一维的Mipmap为例,最小的Mipmap只包含一个像素。不同的Mipmap之间使用一个名为LOD(Level Of Detail,细节等级)的索引进行区别。当所要渲染的图元远离摄像机的时候,你可以使用LOD来选取一个更小的纹理③。

译注:③所谓Mipmap就是一组对原始纹理进行缩小的缩略图,大小按照两倍关系依次减小。虽然这样导致一张纹理占用的内存更大了(原始贴图30%大小),但是考虑一个事实,如果纹理显示在屏幕上的时候只有原来二分之一的大小,那么采样器要进行大量的插值来适应这一变化,这样一来大量消耗了时间,对于实时渲染而言影响很大。所以通过Mipmap预先生成纹理以减少采样次数从而加快渲染速度。

一维纹理数组

D3D10还有一种新的结构用来储存一组纹理。一个纹理数组概念上类似于下图。

这张纹理数组包含了三张纹理,每张纹理的宽度都为5(这是第一层的元素数量)。每张纹理同样包含了三层的Mipmap。

注意D3D中纹理数组中包含的纹理是同类型的,这就意味着数组中每张纹理必须有相同的纹理类型和大小(包含了纹理的宽度和Mipmap层数)。当然你可以创建不同大小的纹理数组,只要数组中所有的纹理能够匹配大小④。

译注:④这大概是说数组中各个纹理所占用的内存大小必须相同,但是你可以只使用其中的一部分来储存纹理。

二维纹理和二维纹理数组(2D Texture)

一个二维纹理数据包含了一个二维的像素表格。每个像素使用向量(u,v)来进行定位。由于这是二维的纹理资源,故可以包含Mipmap和子资源(Subresource)。一个完整的二维纹理资源如图所示。

这个纹理资源包含了一个3x5的纹理,以及含自身在内共三层Mipmap。

2D纹理数组同一维纹理数组要求类似,这就是说每个纹理必须有相同的像素格式以及维数(包含Mipmap)。它拥有和一维纹理类似的布局除了纹理数据是二维的。看上去如图所示。

这个纹理数组包含三张纹理,每个纹理大小3x5,共包含两层的Mipmap。

使用二维纹理数组作为立方纹理(Texture Cube)

一个立方纹理是一个拥有6张纹理的二维纹理数组,每一面都是一个正方形,一个完整的立方纹理看上去就像这样。

当一个包含6张纹理的二维纹理数组被作为立方纹理视图(CubeTextureView)绑定到管线上之后,能够在Shader中通过内建的立方纹理函数(Cube Map Function)读取其内容。立方纹理通过一个从立方纹理中央出发的向量来定位像素。

三维纹理(3D Texture)

三维纹理包含三维空间的像素 (也被称为体纹理(Volume Texture)) 。既然是纹理资源,它当然也拥有Mipmap层次。如图所示。

当一个三维纹理的Mipmap组(Mipmap Slice)被作为渲染目标绑定(使用一个渲染目标视图(Render-Target View)),这张三维纹理将表现成一张拥有N个组的二维纹理。通过声明一组SV_RenderTargetArrayIndex,将在geometry-shader阶段选取特定的渲染组。

由于不存在三维纹理数组的概念,三维纹理的子资源就是一个Mipmap层。

子资源(Subresources)

D3D10的API可以引用整个资源或者资源的一部分,为了确定使用资源的某个部分,D3D创建了一个新的术语叫做子资源(Subresource),表面资源的一个子集。

一个缓冲(Buffer)被定义成一个单独的子资源。纹理比较复杂在于有许多不同的纹理类型(一维,二维,等等)。其中的一些支持Mipmap层次以及(或者)纹理数组。以一个最简单的情况进行说明:一张一维纹理被定义成一个子资源,如下图所示。

 

此处意味着一个子资源包含一组由像素数组组成的一维纹理。

如果你扩展成三层的Mipmap,那么看上去像这样。

想一下一张纹理由三张子纹理组成,每张子纹理都可以被视为一个子资源。所以这个一维纹理包含了三个子资源。一张子纹理(子资源)可以通过细节等级(LOD)进行索引。当使用一组纹理数组时,访问一张特定的子资源需要同时指定LOD和特定的纹理。API将这两种信息绑定在了一起,以0为起始索引来访问所有的子资源。

选择子资源

有些API会访问整个资源(例如CopyResource),其他的会访问一部分资源(例如UpdateSubresource或者CopySubresourceRegion)。访问部分资源的API基本上使用一个视图描述(例如D3D10_TEX2D_ARRAY_DSV)来确定要访问的子资源。

下面这些插图描述了如何用视图访问纹理数组。

纹理组(Array Slice)

给出一个纹理数组,每张纹理都包含Mipmap细节,一个纹理组(Array Slice)(使用白色矩形表示)包含了一张纹理以及所有的子纹理,如下图所示。

 细节组(Mip Slice)

一个细节组(使用白色矩形表示)包含数组中每个纹理的一个Mipmap层,如图所示。

选择单个子资源

你可以使用这两种方式去定位一个子资源,如图所示。

选择多个子资源

或者你可以通过这两种方式再加上Mipmap层次数量和纹理数量来选择多个子资源。

 不管你用的是那种类型的纹理,有或者没有Mipmap,有或者没有纹理数组,你可以使用这个有用的函数,D3D10CalcSubresource,来计算某个子资源的索引。

强类型vs弱类型

创建一个强类型的资源将在创建的时候约束其类型。这允许运行时最优化访问,尤其当资源在创建时使用标志指定这个资源不能够被程序锁定(Mapped)。使用确定的类型创建的资源将不能通过视图方式被重新定义。

对于一个弱类型的资源,数据类型在创建的时候是未知的。程序必须选择一种有效的弱类型(见DXGI_FORMAT)。你必须定义分配内存的大小以及运行时是否需要在Mipmap中产生子纹理。然而,确切的数据类型(比如是否会被定义成整数、小数、无符号整数等等)是不必要的,除非资源被通过视图绑定到了管线上。如上,纹理格式在绑定之前是可变的,就被称为是弱类型存储。弱类型存储的好处就是能够被复用或者重新定义成其他格式,只要新的格式所占用的字节数能够符合旧的数据类型。

一个资源能够被多次绑定到管线的各个阶段,只要绑定的时候拥有唯一一个有效的确定类型的视图。例如,一个资源可以在创建的时候声明DXGI_FORMAT_R32G32B32A32_TYPELESS,而在管线的不同阶段同时以DXGI_FORMAT_R32G32B32A32_FLOAT或者DXGI_FORMAT_R32G32B32A32_UINT被使用。

猜你喜欢

转载自blog.csdn.net/linuxheik/article/details/84872159