如何将压缩的 DDS 格式纹理与 mip 映射一起使用?

How can I use compressed DDS format textures with mip mapping?

直到现在,我将我的 D3D11_TEXTURE2D_DESC::MipLevels 设置为 1,但为了提高性能和地形纹理的质量,我尝试将其交换为带有 mipmap 的纹理。所以这是我用来创建带有 mipmap 的纹理的代码:

 D3D11_TEXTURE2D_DESC t2d;
ZeroMemory(&t2d, sizeof(D3D11_TEXTURE2D_DESC));

UINT BindFlags = (D3D11_BIND_SHADER_RESOURCE | (m_Header.dwMipMapCount ? D3D11_BIND_RENDER_TARGET : 0)); // if the texture has mipmaps then bind it to render target.

t2d.Format = GetDXGIFormat(m_Header.ddspf); // BC2_UNORM
t2d.Width = m_Header.dwWidth;
t2d.Height = m_Header.dwHeight;
t2d.MipLevels = !m_Header.dwMipMapCount ? 1 : 0; // if the texture has mip maps then set it to 0 in order to use them all.
t2d.ArraySize = 1;
t2d.SampleDesc.Count = 1;
t2d.Usage = D3D11_USAGE_DEFAULT;
t2d.BindFlags = BindFlags;
if(!t2d.MipLevels) // only set if the texture has mip maps.
    t2d.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;

D3D11_SUBRESOURCE_DATA sd;
ZeroMemory(&sd, sizeof(D3D11_SUBRESOURCE_DATA));

sd.pSysMem = m_DDSData;

switch (t2d.Format) {
case DXGI_FORMAT_BC1_UNORM:
    sd.SysMemPitch = 8 * (m_Header.dwWidth / 4);
    break;
case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC3_UNORM:
    sd.SysMemPitch = 16 * (m_Header.dwWidth / 4);
    break;
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_B8G8R8A8_UNORM:
    sd.SysMemPitch = m_Header.dwWidth * 4;
    break;
default:
    return Log("Unsupported texture format.");
}

hr = pDevice->CreateTexture2D(&t2d, &sd, &m_pTexture2D);
if (FAILED(hr))
    return Log("Failed to create texture.");

当我的代码运行并找到带有 mip 贴图的纹理时,它最终失败了,这是我在调试时收到的错误消息:

D3D11 ERROR: ID3D11Device::CreateTexture2D: The format (0x4a, BC2_UNORM) cannot be bound as a RenderTarget, or cast to a format that could be bound as a RenderTarget. Therefore this format does not support D3D11_BIND_RENDER_TARGET. [ STATE_CREATION ERROR #92: CREATETEXTURE2D_UNSUPPORTEDFORMAT]

但是如果它找到一个没有 mip 贴图的纹理,或者甚至是一个有 mip 贴图的纹理,但我将纹理描述中的 mip 贴图设置为 1,我不会收到任何错误消息。正如错误消息中所说,我无法将纹理绑定到渲染目标,但如果我尝试使用 D3D11_RESOURCE_MISC_GENERATE_MIPS,我会收到一条错误消息,指出纹理需要绑定到 D3D11_BIND_RENDER_TARGET.

自动生成 mipmap 不支持块压缩格式。您可以使用 CheckFormatSupport.

确认这一点
bool autogen = false;
UINT fmtSupport = 0;
hr = d3dDevice->CheckFormatSupport(format, &fmtSupport);
if (SUCCEEDED(hr) && (fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN))
{
    // 10level9 feature levels do not support auto-gen mipgen for volume textures
    if ((resDim != D3D11_RESOURCE_DIMENSION_TEXTURE3D)
        || (d3dDevice->GetFeatureLevel() >= D3D_FEATURE_LEVEL_10_0))
    {
        autogen = true;
    }
}

通常,您需要离线压缩纹理并在处理过程中生成 mipmap。这些可以存储在 DDS 文件中,然后在运行时使用 mips 加载完整。

有关支持 mipmap 生成、块压缩和 DDS 编解码器的 C++ 库,请参阅 DirectXTex。它还包括 DDSTextureLoader 模块,这是一个轻量级 DDS 文件加载器。

For very large data sets, there have been alternative schemes used where the high-resolution image is compressed using some lossy format (like JPEG) which is loaded at runtime, then a software or GPU-based box filter generates the mips. Then all levels of that texture are compressed using a Fast Block Compression scheme. It doesn't have the same quality as offline compression, but for some scenarios it's worth the trade-off.

Remember that Block Compression formats have a fixed 2:1 or 4:1 compression ratio, but the advantage is that you never have to decompress them as the hardware can use it directly to render.