Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3D11: Creating a cube map from 6 images

How do I create a cube map in D3D11 from 6 images? All the examples I've found use only one .dds. Specifically, how do I upload individual faces of the cube texture?

like image 603
SurvivalMachine Avatar asked Oct 14 '13 15:10

SurvivalMachine


People also ask

How do you make a cube map?

Legacy Cubemap AssetsSelect Assets > Create > Legacy > Cubemap from the menu, and drag six textures into empty slots in the inspector. Textures for the corresponding cubemap face. Width and Height of each Cubemap face in pixels. The textures will be scaled automatically to fit this size.

What is a cubemap file?

Cubemaps provide a simple method of environment mapping, in which distant scenery - such as skies and surrounding environments - is mapped to a panoramic texture. Under the hood, these textures are stored as a series of six images mapped to the inside faces of a cube.

How does a cube map work?

In computer graphics, cube mapping is a method of environment mapping that uses the six faces of a cube as the map shape. The environment is projected onto the sides of a cube and stored as six square textures, or unfolded into six regions of a single texture.

What is cube map texture?

A Cubemap Texture is a texture, where each mipmap level consists of six 2D images which must be square. The 6 images represent the faces of a cube. The texture coordinate used to access a cubemap is a 3D direction vector which represents a direction from the center of the cube to the value to be accessed.


2 Answers

It works like this:

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);

This creates six "red" images, for the CubeMap.

like image 183
Vertexwahn Avatar answered Oct 30 '22 17:10

Vertexwahn


I know this question is old, and there is already a solution.

Here is a code example that loads 6 textures from disk and puts them together as a cubemap:

Precondition:

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

Pointer to a ShaderResourceView and an array filled with the six textures from disc. I use the order right, left, top, bottom, front, back.

// 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;

If anyone reads this question again, maybe try this one. Warning: this function is not threadsafe, because i have to use the deviceContext.

like image 21
kaiser Avatar answered Oct 30 '22 17:10

kaiser