How to render skybox, then save to a texture?

Started by
8 comments, last by pnt1614 8 years, 8 months ago

Is there possible to render a skybox, then save to a texture? I successfully rendered a skybox, but I failed to save to a texture. Everything is okay when I render something else and save to a texture.

Is there anybody experienced this problem?

Advertisement

Yes this is possible I am assuming you will want to use the resulting texture for something else afterwards in the game. IN that case you will want to do an offscreen render of the sky box into a render target.

Both these tutorials show how this works.

http://www.rastertek.com/dx11tut22.html

http://www.braynzarsoft.net/index.php?p=D3D11RTT

In general it works by replacing the backbuffer with a different rendertarget that you have created. You first ask for the back buffer reference, keep this arround because you will want to restore this after you have drawn to your texture. You then set your new Rendertarget as the back buffer and draw the scene that you want to have displayed in that texture. Restore the orginal back buffer and render the scene that should be seen as the game and use the RenderTarget you created as an input texture to the object you want to show it on or use it for.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

I failed to save to a texture

can you explain your problem in more detail?

Thanks for the replys. When I saved the rendering result, a skybox, to a texture, returned value is S_OK but the texture is black.

I have done the same thing NightCreature83, but the output texture is black. I have also tried with an example downloaded from http://www.braynzarsoft.net/index.php?p=D3D11CUBEMAP and the output texture also black.

This is a C++ code for saving to a texture


        HRESULT hr;
	ID3D11Resource *backbufferRes;
	pRTV->GetResource(&backbufferRes);

	D3D11_TEXTURE2D_DESC texDesc;
	texDesc.ArraySize = 1;
	texDesc.BindFlags = 0;
	texDesc.CPUAccessFlags = 0;
	texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
	texDesc.Width = width;  // must be same as backbuffer
	texDesc.Height = height; // must be same as backbuffer
	texDesc.MipLevels = 1;
	texDesc.MiscFlags = 0;
	texDesc.SampleDesc.Count = 1;
	texDesc.SampleDesc.Quality = 0;
	texDesc.Usage = D3D11_USAGE_DEFAULT;

	ID3D11Texture2D *texture;
	HR(pd3dDevice->CreateTexture2D(&texDesc, 0, &texture));
	pd3dImmediateContext->CopyResource(texture, backbufferRes);

	hr = D3DX11SaveTextureToFile(pd3dImmediateContext, texture, D3DX11_IFF_JPG, L"test1.jpg");
	SAFE_RELEASE(texture);
	SAFE_RELEASE(backbufferRes);

If you want to use the texture as a render target you have to bind it that way my cube descriptors look like this:


    D3D11_TEXTURE2D_DESC cubeDesc;
    ZeroMemory(&cubeDesc, sizeof(D3D11_TEXTURE3D_DESC));
    cubeDesc.Width = cubeMapWidhtHeight;
    cubeDesc.Height = cubeMapWidhtHeight;
    cubeDesc.MipLevels = 0;
    cubeDesc.ArraySize = 6;
    cubeDesc.SampleDesc.Count = 1;
    cubeDesc.SampleDesc.Quality = 0;
    cubeDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    cubeDesc.Usage = D3D11_USAGE_DEFAULT;
    cubeDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
    cubeDesc.CPUAccessFlags = 0;
    cubeDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS | D3D11_RESOURCE_MISC_TEXTURECUBE;

I am generating a cubemap in my game so thats why the array size is 6 and miscflags are set to be a texturecube.

Just for completeness here is how I setup my descriptors for the RTV and SRV which are used for rendering to it and using it as a texture in game:

//Should create a 6 2D rts here instead
D3D11_RENDER_TARGET_VIEW_DESC rtDesc;
rtDesc.Format = cubeDesc.Format;
rtDesc.Texture2DArray.FirstArraySlice = 0;
rtDesc.Texture2DArray.ArraySize = 6;
rtDesc.Texture2DArray.MipSlice = 0;
rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;

// Create the shader resource view for the cubic env map
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = cubeDesc.Format;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srvDesc.TextureCube.MipLevels = 1;
srvDesc.TextureCube.MostDetailedMip = 0;

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

Have you tried using ->GetDesc(&desc) and use that desc. for the temp. texture creation?

.:vinterberg:.

btw if you do no rendering between the texture creation, copy and save operation there is nothing in the back buffer and it will be black or what was there last frame. If you do this after the call to clear the bufffer the texture will have the color of the clear color.

You will want to do that copy just before the present call and do the save after the present because a read back from GPU to disc is a costly operation.

Also read the remarks on this topic: https://msdn.microsoft.com/en-us/library/windows/desktop/ff476392%28v=vs.85%29.aspx because the CopyResource call comes with a few requirements that you have to obey for it to work correctly.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

I successfully save to a texture (for testing), but when I bind it as a shader resource view to the next pass the color background is just one solid color and changed as camera moving.

This is C++ source code:


        textureDesc.Width = mClientWidth;
	textureDesc.Height = mClientHeight;
	textureDesc.MipLevels = 1;
	textureDesc.ArraySize = 1;
	//textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
	textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	textureDesc.SampleDesc.Count = 1;
	textureDesc.Usage = D3D11_USAGE_DEFAULT;
	textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	textureDesc.CPUAccessFlags = 0;
	textureDesc.MiscFlags = 0;
	textureDesc.SampleDesc.Count = 1;
	
	V_RETURN(md3dDevice->CreateTexture2D(&textureDesc, NULL, &m_pBackgroundTexture));

	// Setup the description of the render target view.
	renderTargetViewDesc.Format = textureDesc.Format;
	renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
	renderTargetViewDesc.Texture2D.MipSlice = 0;

	// Create the render target view.
	V_RETURN(md3dDevice->CreateRenderTargetView(m_pBackgroundTexture, &renderTargetViewDesc, &m_pBackgroundRTV));
	

	// Setup the description of the shader resource view.
	shaderResourceViewDesc.Format = textureDesc.Format;
	shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
	shaderResourceViewDesc.Texture2D.MipLevels = 1;

	// Create the shader resource view.
	V_RETURN(md3dDevice->CreateShaderResourceView(m_pBackgroundTexture, &shaderResourceViewDesc, &m_pBackgroundSRV));

When you bind the SRV you need to make sure you are no longer using the RTV, if you have the DX runtime setup to use the debug version and set the output to warnings, you will get a warning in the output when the SRV is still being used as a RTV.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

Thanks NightCreature83. I did it.

This topic is closed to new replies.

Advertisement