Alright, been working on setting up my first deferred rendering attempt using a light prepass technique in Direct3D 11.
Anywho, I've been having problems understanding and using render targets. Never really had to do much of anything with them in my previous forward rendering approaches. I'm pretty sure I'm correctly initializing them and binding them to the output merger stage however I'm not getting any results from my first geometry pass.
Now, what I'm doing to test my Geometry buffer pass could be the problem itself and the source of my confusion. I've been unclear as to how to choose which render target is presented with the swap chain. I've been working under the assumption that I just need to make sure I have a render target view that was initialized using the swap chain's backbuffer address and that this render target is what gets presented each frame. So based on that I've been binding my "Presentation" render target to the pipeline instead of what I would be using for my Position and/or Normal render buffers. However, I get nothing but an empty black frame so I assume the buffer isn't getting written to properly. (I'm actually overriding the values written to the buffer with a hard coded color in the pixel shader so I don't think it's related to the shader logic doing something funky, however sending the same "presentation" render target through my forward pass shader works fine...)
So my questions essentially are: am I missing a critical concept or failing to properly set up the Texture2D and Render Target View resources? And is my approach in choosing which render target to present correct, or can I directly bind a specific render target to the swap chain? Also my swap chain has a DXGI_FORMAT_R8G8B8A8_UNORM format for the backbuffer, do the other render target views and textures have to match this?
Edit: With Nathan's clarification and debugging tips I was able to solve my buffer issue. It was actually getting written to however, I had a transposed matrix that was mucking up the vertex transformations. The code below works fine if someone reads this that is interested in it.
Providing the relevant code from my project.
Prepare pipeline for the geometry pass. (Pretty sure I've got this correct)
void GeometryBufferPass::StartRendering(RenderTargetView* _positionRT, RenderTargetView* _normalRT,
DepthBuffer* _depthBuffer, RasterizerState* _rasterizerState) {
static ID3D11RenderTargetView* _renderTargets[2];
static float _ClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // RGBA
pDeviceManager->GetDeviceContext()->ClearRenderTargetView(_positionRT->GetRenderTargetView(), _ClearColor);
pDeviceManager->GetDeviceContext()->ClearRenderTargetView(_normalRT->GetRenderTargetView(), _ClearColor);
pDeviceManager->GetDeviceContext()->ClearDepthStencilView(_depthBuffer->GetDepthBufferView(), D3D11_CLEAR_DEPTH, 1.0f, 1);
pDeviceManager->GetDeviceContext()->VSSetShader(vShader.GetShaderPtr(), 0, 0);
pDeviceManager->GetDeviceContext()->PSSetShader(pShader.GetShaderPtr(), 0, 0);
_renderTargets[0] = _positionRT->GetRenderTargetView();
_renderTargets[1] = _normalRT->GetRenderTargetView();
pDeviceManager->GetDeviceContext()->OMSetRenderTargets(2, _renderTargets, _depthBuffer->GetDepthBufferView());
pDeviceManager->GetDeviceContext()->IASetInputLayout(pVertexLayout);
pDeviceManager->GetDeviceContext()->IASetPrimitiveTopology(topologyType);
pDeviceManager->GetDeviceContext()->RSSetState(_rasterizerState->GetRasterizerState());
pDeviceManager->GetDeviceContext()->VSSetConstantBuffers(0, 1, transformBuffer.GetConstantBuffer());
pDeviceManager->GetDeviceContext()->PSSetConstantBuffers(1, 1, materialBuffer.GetConstantBuffer());
}
Render each object through the geometry pass.
void GeometryBufferPass::Render(Entity &_entity) {
static XMMATRIX _matrix;
static GeometryBufferPass_TransformBuffer _transformBuffer;
static GeometryBufferPass_MaterialBuffer _materialBuffer;
static unsigned int _offset = 0;
_matrix = XMMatrixMultiply(*_entity.GetInstanceObject()->GetScaleMatrix(), *_entity.GetInstanceObject()->GetRotationMatrix());
_matrix = XMMatrixMultiply(_matrix, *_entity.GetInstanceObject()->GetTranslationMatrix());
_transformBuffer.world = XMMatrixTranspose(_matrix);
_matrix = XMMatrixMultiply(_matrix, viewProjectionMatrix);
_transformBuffer.worldViewProjection = XMMatrixTranspose(_matrix);
transformBuffer.Update(&_transformBuffer);
_materialBuffer.specularExponent = _entity.GetRenderObject()->GetMaterial()->GetSpecularExponent();
materialBuffer.Update(&_materialBuffer);
pDeviceManager->GetDeviceContext()->IASetVertexBuffers(0, 1, _entity.GetRenderObject()->GetVertexBuffer()->GetVertexBuffer(), _entity.GetRenderObject()->GetVertexBuffer()->GetVertexStridePtr(), &_offset);
if (_entity.GetRenderObject()->GetVertexBuffer()->GetIndexBuffer() != 0) {
pDeviceManager->GetDeviceContext()->IASetIndexBuffer(_entity.GetRenderObject()->GetVertexBuffer()->GetIndexBuffer(), DXGI_FORMAT_R32_UINT, 0);
pDeviceManager->GetDeviceContext()->DrawIndexed(_entity.GetRenderObject()->GetVertexBuffer()->GetIndexBufferSize(),0,0);
} else pDeviceManager->GetDeviceContext()->Draw(_entity.GetRenderObject()->GetVertexBuffer()->GetVertexBufferSize(), 0);
}
Here is how I create Texture2D and Render Target View objects.
bool Texture2D::InitializeTexture(const unsigned int _width, const unsigned int _height, const bool _isShaderResourceView, const bool _isRenderTargetView) {
if (!StartUp())
return false;
D3D11_TEXTURE2D_DESC _desc;
_desc.Width = _width;
_desc.Height = _height;
_desc.MipLevels = 0;
_desc.ArraySize = 1;
_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; // or DXGI_FORMAT_R8G8B8A8_UNORM? Even though I am writing 4 floats to it...
_desc.Usage = D3D11_USAGE_DEFAULT;
_desc.CPUAccessFlags = 0;
_desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS; // Not sure if I need to generate a mip map chain for my purposes.
unsigned int _bindFlag = 0;
if (_isShaderResourceView)
_bindFlag |= D3D11_BIND_SHADER_RESOURCE;
if (_isRenderTargetView)
_bindFlag |= D3D11_BIND_RENDER_TARGET;
_desc.BindFlags = _bindFlag;
DXGI_SAMPLE_DESC _sampleDesc;
_sampleDesc.Count = 1;
_sampleDesc.Quality = 0;
_desc.SampleDesc = _sampleDesc;
if (FAILED(pDeviceManager->GetDevice()->CreateTexture2D(&_desc, 0, &pTexture)))
return false;
if (_isRenderTargetView)
if (!renderTarget.StartUp(pTexture, _desc.Format))
return false;
return true;
}
Render Target View initialization
bool RenderTargetView::StartUp(ID3D11Resource* _resource, const DXGI_FORMAT _format, const D3D11_RTV_DIMENSION _viewType) {
pDeviceManager = D11DeviceManager::GetSingleton();
D3D11_RENDER_TARGET_VIEW_DESC _desc;
_desc.Format = _format;
_desc.ViewDimension = _viewType;
// Class only handles Texture2D at the moment.
D3D11_TEX2D_RTV _rtv;
_rtv.MipSlice = 1;
_desc.Texture2D = _rtv;
return !FAILED(pDeviceManager->GetDevice()->CreateRenderTargetView(_resource, &_desc, &pRenderTargetView));
}
And figured I might as well post the shader code just in case.
cbuffer TransformBuffer : register(b0) {
float4x4 worldMatrix,
worldViewProjectionMatrix;
};
// Pretty sure constant buffers have to be atleast 16 bytes
// but shader compiler has yet to throw a warning or error.
cbuffer MaterialBuffer : register(b1) {
float materialSpecularExponent;
};
struct vsInput {
float3 positionLS : POSITION;
float3 textureLS : TEXTURE;
float3 normalLS : NORMAL;
};
struct vsOutput {
float4 positionCS : SV_POSITION;
float2 textureLS : TEXTURE;
float3 normalWS : NORMAL;
float3 positionWS : POSITION;
};
struct psOutput {
float4 normalWS : SV_TARGET0;
float4 positionWS : SV_TARGET1;
};
vsOutput VS( in const vsInput _in ) {
vsOutput _out;
_out.positionCS = float4(mul(_in.positionLS, (float3x3) worldViewProjectionMatrix), 1.0f);
_out.positionWS = mul(_in.positionLS, (float3x3) worldMatrix);
_out.normalWS = mul(_in.normalLS, (float3x3) worldMatrix);
_out.textureLS = (float2)_in.textureLS;
return _out;
}
psOutput PS( in const vsOutput _in ) {
psOutput _out;
// Overwriting the pixel shader return values just so I can see if the render
// target is getting written to.
_out.normalWS = float4(0.5f, 1.0f, 0.0f, 1.0f);//float4(normalize(_in.normalWS), materialSpecularExponent);
_out.positionWS = float4(0.5f, 1.0f, 0.0f, 1.0f);//float4(_in.positionWS, 1.0f);
return _out;
}