I am currently implementing diffuse irridiance(A part of Image based lightning of PBR) in my game engine. I got to the point where I have to take an HDR Image and turn it into a cubemap. I am currently using a EquirectangularToCubemap shader and its working fine. I was able to project the HDR image to a (unit)cube. Now comes the part where I am stuck, I can't turn this cube to a cubemap. I tried using 1 TextureCube, 6 RenderTargetView's and a ShaderResourceView. My plan was to render the (unit)cube 6 times from different view projection with a FOV of 90 to capture the whole side in each of the render target, and lastly copy each of the output of the render target to the corresponding side of the Texture cube.
I don't know how to do this ^.
NOTE: I am using DirextX11 as the rendering backend.
Here is the pseudo code about my problem(which is not working)
glm::mat4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f);
glm::mat4 captureViews[] =
{
glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)),
glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)),
glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f))
};
//Create the TextureCube
D3D11_TEXTURE2D_DESC textureDesc = {};
textureDesc.Width = 512;
textureDesc.Height = 512;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 6;
textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
textureDesc.CPUAccessFlags = 0;
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
textureDesc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE;
ID3D11Texture2D* tex = nullptr;
DX_CALL(DX11Internal::GetDevice()->CreateTexture2D(&textureDesc, nullptr, &tex));
// Create the Shader Resource view for the texture cube
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Format = textureDesc.Format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.MipLevels = 1;
DX_CALL(DX11Internal::GetDevice()->CreateShaderResourceView(tex, &srvDesc, &mSRV));
//Create the Render target views
Vector<ID3D11RenderTargetView*> rtvs;
for (Uint i = 0; i < 6; i++)
{
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc = {};
renderTargetViewDesc.Format = textureDesc.Format;
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
renderTargetViewDesc.Texture2D.MipSlice = 0;
ID3D11RenderTargetView* view = nullptr;
DX11Internal::GetDevice()->CreateRenderTargetView(tex, &renderTargetViewDesc, &view);
rtvs.push_back(view);
}
tex->Release();
auto deviceContext = DX11Internal::GetDeviceContext();
for (Uint i = 0; i < 6; ++i)
{
float clearColor[4] = { 1.0f, 0.1f, 0.1f, 1.0f };
deviceContext->ClearRenderTargetView(rtvs[i], clearColor);
Vault::Get<Shader>("EquirectangularToCubemap.hlsl")->Bind();
auto data = captureProjection * captureViews[i];
cbuffer->Bind();
cbuffer->SetData(&data);
texture->Bind(0);
tempPipeline->Bind();
deviceContext->OMSetRenderTargets(1, &rtvs[i], nullptr);
//I am rendering the cube here from different view projection to capture the faces, but I dont't know where to copy the data to the //side of the TextureCube :( [Note that I am doing this only once]
RenderCommand::DrawIndexed(tempPipeline, 36);
}
Thanks in advance!
You are not specifying which slices you want to write to when creating render views. The correct description for slices is:
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc = {};
renderTargetViewDesc.Format = textureDesc.Format;
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
renderTargetViewDesc.Texture2DArray.MipSlice = 0;
renderTargetViewDesc.Texture2DArray.FirstArraySlice =i;
renderTargetViewDesc.Texture2DArray.ArraySize = 1;
(Note : if you use MSAA, ViewDimension will become D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY)
Also to create the shader view for your resource, since you want to create a default one, you can pass NULL instead of a home made D3D11_SHADER_RESOURCE_VIEW_DESC
DX_CALL(DX11Internal::GetDevice()->CreateShaderResourceView(tex, NULL, &mSRV));
You can also create another render view that maps the whole cube map in one go :
DX11Internal::GetDevice()->CreateRenderTargetView(tex, NULL, &cubeMapFullView);
But in that case you will need to use Geometry Shader to replicate geometry across slices (using SV_RenderTargetArrayIndex), or use vendor specific extensions that provide the same kind of feature.