You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DirectX11与HLSL中Texture2DArray的创建及赋值问题咨询

关于D3D11中创建Texture2DArray着色器资源视图的解答

一、创建Texture2DArray SRV的正确流程

要将多个WIC加载的纹理合并为单个Texture2DArray的SRV,核心是先创建Texture2DArray类型的GPU资源,再为其生成对应的着色器资源视图,具体步骤如下:

    1. 统一源纹理规格:所有通过WICCreateTexture创建的源纹理,必须保证格式、分辨率、MIP层级数量、采样参数完全一致,Texture2DArray要求所有子纹理的参数严格匹配。
    1. 定义Texture2DArray的资源描述:
    D3D11_TEXTURE2D_DESC arrayDesc = {};
    // 从任意一个源纹理提取基础参数
    ID3D11Texture2D* pFirstTex = nullptr;
    pFirstSRV->GetResource((ID3D11Resource**)&pFirstTex);
    D3D11_TEXTURE2D_DESC texDesc;
    pFirstTex->GetDesc(&texDesc);
    
    arrayDesc.Width = texDesc.Width;
    arrayDesc.Height = texDesc.Height;
    arrayDesc.MipLevels = texDesc.MipLevels;
    arrayDesc.ArraySize = 你的纹理总数; // 比如有3张纹理就设为3
    arrayDesc.Format = texDesc.Format;
    arrayDesc.SampleDesc = texDesc.SampleDesc;
    arrayDesc.Usage = D3D11_USAGE_DEFAULT;
    arrayDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    arrayDesc.CPUAccessFlags = 0;
    arrayDesc.MiscFlags = 0;
    
    pFirstTex->Release();
    
    1. 提取所有源纹理的像素数据:
      WICCreateTexture生成的是已初始化的GPU资源,需要通过Map操作读取每个纹理的像素数据:
    std::vector<D3D11_SUBRESOURCE_DATA> subresources(arrayDesc.ArraySize * arrayDesc.MipLevels);
    ID3D11DeviceContext* pDeviceContext = nullptr;
    pDevice->GetImmediateContext(&pDeviceContext);
    
    for (int arrayIdx = 0; arrayIdx < arrayDesc.ArraySize; ++arrayIdx) {
        ID3D11Texture2D* pTex = nullptr;
        pSrcSRVs[arrayIdx]->GetResource((ID3D11Resource**)&pTex);
        
        for (int mipIdx = 0; mipIdx < arrayDesc.MipLevels; ++mipIdx) {
            D3D11_MAPPED_SUBRESOURCE mapped;
            pDeviceContext->Map(pTex, mipIdx, D3D11_MAP_READ, 0, &mapped);
            
            int subresourceIdx = mipIdx + arrayIdx * arrayDesc.MipLevels;
            subresources[subresourceIdx].pSysMem = mapped.pData;
            subresources[subresourceIdx].SysMemPitch = mapped.RowPitch;
            subresources[subresourceIdx].SysMemSlicePitch = mapped.DepthPitch;
            
            pDeviceContext->Unmap(pTex, mipIdx);
        }
        pTex->Release();
    }
    pDeviceContext->Release();
    
    1. 创建Texture2DArray资源并生成SRV:
    ID3D11Texture2D* pTexArray = nullptr;
    HRESULT hr = pDevice->CreateTexture2D(&arrayDesc, subresources.data(), &pTexArray);
    
    // 创建对应的着色器资源视图
    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
    srvDesc.Format = arrayDesc.Format;
    srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
    srvDesc.Texture2DArray.MipLevels = arrayDesc.MipLevels;
    srvDesc.Texture2DArray.FirstMip = 0;
    srvDesc.Texture2DArray.ArraySize = arrayDesc.ArraySize;
    srvDesc.Texture2DArray.FirstArraySlice = 0;
    
    ID3D11ShaderResourceView* pArraySRV = nullptr;
    hr = pDevice->CreateShaderResourceView(pTexArray, &srvDesc, &pArraySRV);
    
    // 释放临时资源
    pTexArray->Release();
    
    完成后即可将pArraySRV绑定到着色器的Texture2DArray槽位使用。

二、代码正确性分析

若你尝试直接将vector<ID3D11Resource*>或vector<ID3D11ShaderResourceView*>的指针赋值给subresource.pSysMem,这是完全错误的。pSysMem需要的是纹理像素数据的内存缓冲区指针,而非D3D接口对象的指针,直接传接口指针会导致GPU读取无效内存,引发崩溃或渲染异常。

三、subresource.pSysMem的正确赋值方式

subresource.pSysMem既不是vector<ID3D11Resource*>的起始指针,也不是vector<ID3D11ShaderResourceView*>的起始指针,而是每个子纹理对应MIP层级的像素数据缓冲区指针。

具体操作逻辑:

  • 对每个源纹理的每个MIP层级执行Map操作,获取像素数据的pData;
  • 将这些pData分别填入D3D11_SUBRESOURCE_DATA结构体数组的pSysMem字段,同时设置对应的SysMemPitch和SysMemSlicePitch;
  • 最终将这个结构体数组的起始地址传给CreateTexture2D的第二个参数。

内容的提问来源于stack exchange,提问作者Jason Woo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 02:47:51