D3D11:从6张图像创建立方体贴图

6

我应该如何从6张图片中创建一个D3D11立方体映射?我找到的所有示例都只使用了一个.dds文件。具体来说,我该如何上传立方体纹理的各个面?

2个回答

8
它的工作原理是这样的:
D3D11_TEXTURE2D_DESC texDesc;
texDesc.Width = description.width;
texDesc.Height = description.height;
texDesc.MipLevels = 1;
texDesc.ArraySize = 6;
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDesc.CPUAccessFlags = 0;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;

D3D11_SHADER_RESOURCE_VIEW_DESC SMViewDesc;
SMViewDesc.Format = texDesc.Format;
SMViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
SMViewDesc.TextureCube.MipLevels =  texDesc.MipLevels;
SMViewDesc.TextureCube.MostDetailedMip = 0;

D3D11_SUBRESOURCE_DATA pData[6];
std::vector<vector4b> d[6]; // 6 images of type vector4b = 4 * unsigned char

for (int cubeMapFaceIndex = 0; cubeMapFaceIndex < 6; cubeMapFaceIndex++)
{   
    d[cubeMapFaceIndex].resize(description.width * description.height);

    // fill with red color  
    std::fill(
        d[cubeMapFaceIndex].begin(), 
        d[cubeMapFaceIndex].end(), 
        vector4b(255,0,0,255));

    pData[cubeMapFaceIndex].pSysMem = &d[cubeMapFaceIndex][0];// description.data;
    pData[cubeMapFaceIndex].SysMemPitch = description.width * 4;
    pData[cubeMapFaceIndex].SysMemSlicePitch = 0;
}

HRESULT hr = renderer->getDevice()->CreateTexture2D(&texDesc, 
    description.data[0] ? &pData[0] : nullptr, &m_pCubeTexture);
assert(hr == S_OK);

hr = renderer->getDevice()->CreateShaderResourceView(
    m_pCubeTexture, &SMViewDesc, &m_pShaderResourceView);
assert(hr == S_OK);

这会创建六个“红色”图像,用于CubeMap。

如果你想用文件中的纹理来填充立方体贴图数据,而不是在这里使用红色,该怎么办? - PinkTurtle
1
请注意:使用类似 http://openil.sourceforge.net/ 或者 http://cimg.eu/ 这样的图像加载器在 CPU 端初始化纹理。 - PinkTurtle
如何加载纹理数据:https://bitbucket.org/Anteru/d3d12sample/src/bf8c36ada43287ef3d786d99bc0d4d4b9eb9f394/inc/ImageIO.h?at=default - Vertexwahn

3

我知道这个问题很久远了,而且已经有了解决方案。

这里是一个代码示例,它从磁盘加载6个纹理并将它们组合成立方体贴图:

前置条件:

ID3D11ShaderResourceView* srv = 0;
ID3D11Resource* srcTex[6];

这是一个指向ShaderResourceView的指针和一个由六个来自磁盘的纹理填充的数组。我按照顺序使用右、左、上、下、前、后的顺序。

// Each element in the texture array has the same format/dimensions.
D3D11_TEXTURE2D_DESC texElementDesc;
((ID3D11Texture2D*)srcTex[0])->GetDesc(&texElementDesc);

D3D11_TEXTURE2D_DESC texArrayDesc;
texArrayDesc.Width = texElementDesc.Width;
texArrayDesc.Height = texElementDesc.Height;
texArrayDesc.MipLevels = texElementDesc.MipLevels;
texArrayDesc.ArraySize = 6;
texArrayDesc.Format = texElementDesc.Format;
texArrayDesc.SampleDesc.Count = 1;
texArrayDesc.SampleDesc.Quality = 0;
texArrayDesc.Usage = D3D11_USAGE_DEFAULT;
texArrayDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texArrayDesc.CPUAccessFlags = 0;
texArrayDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;

ID3D11Texture2D* texArray = 0;
if (FAILED(pd3dDevice->CreateTexture2D(&texArrayDesc, 0, &texArray)))
    return false;

// Copy individual texture elements into texture array.
ID3D11DeviceContext* pd3dContext;
pd3dDevice->GetImmediateContext(&pd3dContext);
D3D11_BOX sourceRegion;

//Here i copy the mip map levels of the textures
for (UINT x = 0; x < 6; x++)
{
    for (UINT mipLevel = 0; mipLevel < texArrayDesc.MipLevels; mipLevel++)
    {
        sourceRegion.left = 0;
        sourceRegion.right = (texArrayDesc.Width >> mipLevel);
        sourceRegion.top = 0;
        sourceRegion.bottom = (texArrayDesc.Height >> mipLevel);
        sourceRegion.front = 0;
        sourceRegion.back = 1;

        //test for overflow
        if (sourceRegion.bottom == 0 || sourceRegion.right == 0)
            break;

        pd3dContext->CopySubresourceRegion(texArray, D3D11CalcSubresource(mipLevel, x, texArrayDesc.MipLevels), 0, 0, 0, srcTex[x], mipLevel, &sourceRegion);
    }
}

// Create a resource view to the texture array.
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
viewDesc.Format = texArrayDesc.Format;
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
viewDesc.TextureCube.MostDetailedMip = 0;
viewDesc.TextureCube.MipLevels = texArrayDesc.MipLevels;

if (FAILED(pd3dDevice->CreateShaderResourceView(texArray, &viewDesc, &srv)))
    return false;

如果有人再次阅读这个问题,可以尝试使用这个。警告:该函数不是线程安全的,因为我必须使用设备上下文。

1
这正确吗?我认为我必须将MiscFlags设置为D3D11_RESOURCE_MISC_TEXTURECUBE。 - Thomas
1
是的,你说得对,在我的原始代码中我有一个条件: texArrayDesc.MiscFlags = isCubeMap ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;isCubeMap是创建纹理的函数参数,我会编辑我的答案。谢谢。 - kaiser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接