如何用ID3D11Device::CreateTexture2D创建带Mipmap的纹理数组?
解决DirectX 11纹理数组同时设置ArraySize和MipLevels时CreateTexture2D失败的问题
你遇到的0x80070057(无效参数)错误,核心原因是子资源数据的排列顺序不符合DirectX 11的要求。
DirectX 11中,纹理数组的子资源布局规则是:先遍历所有Mip层级,再切换到下一个数组元素。换句话说,子资源的索引顺序是:
- 数组元素0的Mip 0 → 数组元素0的Mip 1 → ... → 数组元素0的Mip m-1
- 数组元素1的Mip 0 → 数组元素1的Mip 1 → ... → 数组元素1的Mip m-1
- ...
- 数组元素n-1的Mip 0 → ... → 数组元素n-1的Mip m-1
而你的代码里是先按数组索引分组,再填充Mip层级,完全搞反了顺序,导致CreateTexture2D接收的子资源数据和纹理描述不匹配,触发无效参数错误。
修正后的代码
// Setup the description of the texture. textureDesc.Height = height; textureDesc.Width = width; textureDesc.MipLevels = mipLevels; textureDesc.ArraySize = count; textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; textureDesc.SampleDesc.Count = 1; textureDesc.SampleDesc.Quality = 0; textureDesc.Usage = D3D11_USAGE_IMMUTABLE; textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; textureDesc.CPUAccessFlags = 0; textureDesc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA* subData = new D3D11_SUBRESOURCE_DATA[count * mipLevels]; // 修正子资源顺序:先遍历Mip层级,再遍历数组元素 for (int m = 0; m < mipLevels; ++m) { int currentWidth = width >> m; if (currentWidth == 0) currentWidth = 1; // 确保最小Mip层级宽度至少为1 for (int i = 0; i < count; ++i) { int subResourceIndex = m * count + i; if (m == 0) { // Mip 0使用原始图像数据 subData[subResourceIndex].pSysMem = imageDataArray[i]; subData[subResourceIndex].SysMemPitch = (UINT)(width * 4); } else { // Mip层级>0使用预生成的Mip数据 subData[subResourceIndex].pSysMem = mipsPtr[i][m-1]; subData[subResourceIndex].SysMemPitch = (UINT)(currentWidth * 4); } subData[subResourceIndex].SysMemSlicePitch = 0; // 2D纹理不需要SlicePitch } } // Create the texture. HRESULT hResult = device->CreateTexture2D(&textureDesc, subData, &texture); if (FAILED(hResult)) { delete[] subData; // 记得释放内存,避免泄漏 return false; } delete[] subData;
额外注意事项
- Mip层级尺寸检查:确保每个Mip层级的宽高至少为1,如果原始尺寸不是2的幂,手动计算Mip尺寸时要处理边界情况。
- 内存泄漏防护:用
new分配的subData数组,无论CreateTexture2D成功与否都要释放。 - 原始数据索引修正:原代码中
imageDataArray[i*mipLevels]存在逻辑错误,每个数组元素对应一个Mip0数据,所以修正为imageDataArray[i],可根据实际数据结构调整。
内容的提问来源于stack exchange,提问作者Tenebre
相关产品推荐
相关产品推荐

