(Direct3D 10) 创建纹理资源

纹理资源是结构化的数据集合。 通常,颜色值存储在纹理中,并在呈现期间由 管道 在输入和输出的各个阶段进行访问。 创建纹理并定义纹理的使用方式是在 Direct3D 10 中呈现有趣场景的一个重要部分。

尽管纹理通常包含颜色信息,但使用不同的 DXGI_FORMAT 创建纹理可以存储不同类型的数据。 然后,Direct3D 10 管道可以非传统方式利用此数据。

所有纹理都会限制它们消耗的内存量以及它们包含的纹素数。 这些限制由 资源常量指定。

从文件创建纹理

注意

D3DX 实用工具库已弃用Windows 8,不支持 Windows 应用商店应用。

 

在 Direct3D 10 中创建纹理时,还需要创建 视图。 视图是一个对象,它告诉设备在呈现期间应如何访问纹理。 访问纹理的最常见方法是使用 着色器从纹理中读取。 着色器资源视图将告知着色器如何在呈现过程中从纹理读取。 创建纹理时必须使用的视图类型必须指定。

可以通过两种不同的方式创建纹理并加载其初始数据:单独创建纹理和视图,或者同时创建纹理和视图。 API 提供了这两种技术,因此你可以选择哪种技术更适合你的需求。

单独创建纹理和视图

创建纹理的最简单方法是从图像文件加载纹理。 若要创建纹理,只需填充一个结构,并将纹理的名称提供给 D3DX10CreateTextureFromFile

ID3D10Device *pDevice = NULL;
// Initialize D3D10 device...

D3DX10_IMAGE_LOAD_INFO loadInfo;
ZeroMemory( &loadInfo, sizeof(D3DX10_IMAGE_LOAD_INFO) );
loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE;

ID3D10Resource *pTexture = NULL;
D3DX10CreateTextureFromFile( pDevice, L"sample.bmp", &loadInfo, NULL, &pTexture, NULL );

D3DX 函数 D3DX10CreateTextureFromFile 执行三项操作:第一,它创建 Direct3D 10 纹理对象:其次,它读取输入图像文件;第三,它将图像数据存储在纹理对象中。 在上面的示例中,已加载 BMP 文件,但函数可以加载各种文件类型。

绑定标志指示纹理将创建为着色器资源,该资源允许着色器阶段在呈现期间从纹理中读取。

上面的示例未指定所有加载参数。 事实上,只需将加载参数归零,这通常很有利,因为这允许 D3DX 根据输入图像选择适当的值。 如果希望输入图像确定使用创建纹理的所有参数,只需为 loadInfo 参数指定 NULL,如下所示:

D3DX10CreateTextureFromFile( pDevice, L"sample.bmp", NULL, NULL, &pTexture, NULL );

为加载信息指定 NULL 是一种简单而强大的快捷方式。

创建纹理后,需要创建着色器资源视图,以便纹理可以作为着色器的输入进行绑定。 由于 D3DX10CreateTextureFromFile 返回指向资源的指针而不是指向纹理的指针,因此必须确定所加载资源的确切类型,然后可以使用 CreateShaderResourceView 创建着色器资源视图。

D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc;
D3D10_RESOURCE_DIMENSION type;
pTexture->GetType( &type );
switch( type )
{
    case D3D10_RESOURCE_DIMENSION_BUFFER:
    //...
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
    //...
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
    {
        D3D10_TEXTURE2D_DESC desc;
        ID3D10Texture2D *pTexture2D = (ID3D10Texture2D*)pTexture;
        pTexture2D->GetDesc( &desc );
        
        srvDesc.Format = desc.Format;
        srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
        srvDesc.Texture2D.MipLevels = desc.MipLevels;
        srvDesc.Texture2D.MostDetailedMip = desc.MipLevels -1;

    }
    break;
    case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
    //...
    break;
    default:
    //...
    break;
}

ID3D10ShaderResourceView *pSRView = NULL;
pDevice->CreateShaderResourceView( pTexture, &srvDesc, &pSRView );

尽管上述示例创建 2D 着色器资源视图,但用于创建其他着色器资源视图类型的代码非常相似。 任何着色器阶段现在都可以使用此纹理作为输入。

使用 D3DX10CreateTextureFromFileCreateShaderResourceView 创建纹理及其关联视图是准备要绑定到着色器阶段的纹理的一种方法。 另一种方法是同时创建纹理及其视图,这将在下一部分中讨论。

同时创建纹理和视图

Direct3D 10 需要纹理和着色器资源视图才能在运行时从纹理进行读取。 由于创建纹理和着色器资源视图是一项常见任务,因此 D3DX 提供 D3DX10CreateShaderResourceViewFromFile 来执行此操作。

D3DX10_IMAGE_LOAD_INFO loadInfo;
ZeroMemory( &loadInfo, sizeof(D3DX10_IMAGE_LOAD_INFO) );
loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE;
loadInfo.Format = DXGI_FORMAT_BC1_UNORM;

ID3D10ShaderResourceView *pSRView = NULL;
D3DX10CreateShaderResourceViewFromFile( pDevice, L"sample.bmp", &loadInfo, NULL, &pSRView, NULL );

通过单个 D3DX 调用,将创建纹理和着色器资源视图。 loadInfo 参数的功能保持不变;可以使用它来自定义纹理的创建方式,或通过为 loadInfo 参数指定 NULL 从输入文件派生必要的参数。

D3DX10CreateShaderResourceViewFromFile 函数返回的 ID3D10ShaderResourceView 对象稍后可用于检索原始 ID3D10Resource 接口(如果需要)。 这可以通过调用 GetResource 方法来完成。

D3DX 提供了一个函数,用于创建纹理和着色器资源视图作为一种功能;由你决定哪种创建纹理和视图的方法最适合应用程序的需求。

了解如何创建纹理及其着色器资源视图后,下一部分将介绍如何使用着色器从该纹理读取) 采样 (。

创建空纹理

有时,应用程序需要创建纹理并计算要存储在纹理中的数据,或使用图形 管道 呈现到此纹理,然后在其他处理中使用结果。 这些纹理可由图形管道或应用程序本身更新,具体取决于创建纹理时为纹理指定的 用法 类型。

呈现为纹理

在运行时创建要填充数据的空纹理时,最常见的情况是应用程序希望呈现为纹理,然后在后续传递中使用呈现操作的结果。 为此创建的纹理应指定默认 用法

下面的代码示例创建一个空纹理,管道可以呈现该纹理,并随后用作 着色器的输入。

// Create the render target texture
D3D10_TEXTURE2D_DESC desc;
ZeroMemory( &desc, sizeof(desc) );
desc.Width = 256;
desc.Height = 256;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;

ID3D10Texture2D *pRenderTarget = NULL;
pDevice->CreateTexture2D( &desc, NULL, &pRenderTarget );

创建纹理需要应用程序指定有关纹理将具有的属性的一些信息。 纹素中纹理的宽度和高度设置为 256。 对于此呈现目标,只需一个 mipmap 级别即可。 只需要一个呈现器目标,因此数组大小设置为 1。 每个纹素包含四个 32 位浮点值,可用于存储非常精确的信息, (DXGI_FORMAT) 。 只需要每个像素一个样本。 用法设置为默认值,因为这样可以在内存中最有效地放置呈现器目标。 最后,指定了纹理将绑定为呈现目标和不同时间点的着色器资源这一事实。

无法绑定纹理以直接呈现到管道;使用呈现目标视图,如以下代码示例所示。

D3D10_RENDER_TARGET_VIEW_DESC rtDesc;
rtDesc.Format = desc.Format;
rtDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
rtDesc.Texture2D.MipSlice = 0;

ID3D10RenderTargetView *pRenderTargetView = NULL;
pDevice->CreateRenderTargetView( pRenderTarget, &rtDesc, &pRenderTargetView );

呈现器目标视图的格式只需设置为原始纹理的格式。 资源中的信息应解释为 2D 纹理,我们只想使用呈现目标的第一个 mipmap 级别。

与必须创建呈现目标视图以便将呈现目标绑定到管道的输出类似,必须创建着色器资源视图,以便将呈现目标作为输入绑定到管道。 以下代码示例对此进行了演示。

// Create the shader-resource view
D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
srDesc.Format = desc.Format;
srDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = 1;

ID3D10ShaderResourceView *pShaderResView = NULL;
pDevice->CreateShaderResourceView( pRenderTarget, &srDesc, &pShaderResView );

着色器资源视图说明的参数与呈现器-目标视图说明的参数非常相似,并且出于相同原因而选择。

手动填充纹理

有时,应用程序希望在运行时计算值,将其手动放入纹理中,然后让图形 管道 在以后的呈现操作中使用此纹理。 为此,应用程序必须以允许 CPU 访问基础内存的方式创建一个空纹理。 这是通过创建动态纹理并通过调用特定方法获取对基础内存的访问权限来完成的。 下面的代码示例演示如何实现此操作。

D3D10_TEXTURE2D_DESC desc;
desc.Width = 256;
desc.Height = 256;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
ID3D10Texture2D *pTexture = NULL;
pd3dDevice->CreateTexture2D( &desc, NULL, &pTexture );

请注意,格式设置为每像素 32 位,其中每个组件由 8 位定义。 用法参数设置为动态,而绑定标志设置为指定着色器将访问纹理。 纹理描述的其余部分类似于创建呈现目标。

调用 Map 使应用程序能够访问纹理的基础内存。 然后,检索到的指针用于用数据填充纹理。 可以在以下代码示例中看到这一点。

D3D10_MAPPED_TEXTURE2D mappedTex;
pTexture->Map( D3D10CalcSubresource(0, 0, 1), D3D10_MAP_WRITE_DISCARD, 0, &mappedTex );

UCHAR* pTexels = (UCHAR*)mappedTex.pData;
for( UINT row = 0; row < desc.Height; row++ )
{
    UINT rowStart = row * mappedTex.RowPitch;
    for( UINT col = 0; col < desc.Width; col++ )
    {
        UINT colStart = col * 4;
        pTexels[rowStart + colStart + 0] = 255; // Red
        pTexels[rowStart + colStart + 1] = 128; // Green
        pTexels[rowStart + colStart + 2] = 64;  // Blue
        pTexels[rowStart + colStart + 3] = 32;  // Alpha
    }
}

pTexture->Unmap( D3D10CalcSubresource(0, 0, 1) );

多个呈现目标

使用 OMSetRenderTargets) ,一次最多可将八个呈现目标视图绑定到管道 (。 对于每个像素 (或每个样本(如果) 启用了多重采样),则为每个呈现目标视图单独进行混合。 两个混合状态变量(BlendEnable 和 RenderTargetWriteMask)是 8 个数组,每个数组成员对应于呈现目标视图。 使用多个呈现目标时,每个呈现目标必须是同一 资源类型 , (缓冲区、1D 纹理、2D 纹理数组等) ,并且必须具有相同的维度 (3D 纹理的宽度、高度、深度以及纹理数组) 的数组大小。 如果呈现目标是多重采样的,则它们必须具有每个像素的样本数相同。

无论有多少呈现目标处于活动状态,都只能有一个深度模具缓冲区处于活动状态。 使用纹理数组作为呈现目标时,所有视图维度必须匹配。 呈现目标不需要具有相同的纹理格式。

资源 (Direct3D 10)