DirectX11与HLSL中Texture2DArray的创建及赋值问题咨询
关于D3D11中创建Texture2DArray着色器资源视图的解答
一、创建Texture2DArray SRV的正确流程
要将多个WIC加载的纹理合并为单个Texture2DArray的SRV,核心是先创建Texture2DArray类型的GPU资源,再为其生成对应的着色器资源视图,具体步骤如下:
- 统一源纹理规格:所有通过
WICCreateTexture创建的源纹理,必须保证格式、分辨率、MIP层级数量、采样参数完全一致,Texture2DArray要求所有子纹理的参数严格匹配。
- 统一源纹理规格:所有通过
- 定义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();- 提取所有源纹理的像素数据:
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();- 提取所有源纹理的像素数据:
- 创建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
相关产品推荐
相关产品推荐

