I'm sure I'm just missing some simple step that I've been too blind to notice so far, but I cannot seem to get depth testing to work at all. This is with DirectX 11.
The code that should set it all up:
DXGI_SWAP_CHAIN_DESC swapDesc = { };
swapDesc.BufferDesc.Width = 0;
swapDesc.BufferDesc.Height = 0;
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapDesc.BufferDesc.RefreshRate.Numerator = 0;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.BufferCount = 1;
swapDesc.OutputWindow = hwnd;
swapDesc.Windowed = TRUE;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapDesc.Flags = 0;
UINT flg = 0;
#if MAGE_DEBUG
flg |= D3D11_CREATE_DEVICE_DEBUG;
#endif
GFX_THROW_INFO(D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
flg,
nullptr, 0,
D3D11_SDK_VERSION, &swapDesc, &mSwap, &mDevice, nullptr,
&mContext));
COMptr<ID3D11Resource> backBuffer;
GFX_THROW_INFO(mSwap->GetBuffer(0, __uuidof(ID3D11Resource), &backBuffer));
GFX_THROW_INFO(mDevice->CreateRenderTargetView(backBuffer.Get(), nullptr, &mTarget));
LOG_INFO("Setting depth stencil dimensions ({}, {})", width, height);
COMptr<ID3D11Texture2D> depthStencil;
D3D11_TEXTURE2D_DESC texDesc = { };
texDesc.Width = width;
texDesc.Height = height;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_D32_FLOAT;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
GFX_THROW_INFO(mDevice->CreateTexture2D(&texDesc, nullptr, &depthStencil));
D3D11_DEPTH_STENCIL_DESC depth = { };
depth.DepthEnable = TRUE;
depth.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depth.DepthFunc = D3D11_COMPARISON_LESS;
COMptr<ID3D11DepthStencilState> depthState;
GFX_THROW_INFO(mDevice->CreateDepthStencilState(&depth, &depthState));
D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc = { };
dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
dsvDesc.Texture2D.MipSlice = 0;
GFX_THROW_INFO(mDevice->CreateDepthStencilView(depthStencil.Get(), &dsvDesc, &mDepthStencilView));
mContext->OMSetDepthStencilState(depthState.Get(), 1);
mContext->OMSetRenderTargets(1, mTarget.GetAddressOf(), mDepthStencilView.Get());
LOG_INFO("Setting viewport dimensions ({}, {})", width, height);
D3D11_VIEWPORT vp;
vp.Width = (float) width;
vp.Height = (float) height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0.0f;
vp.TopLeftY = 0.0f;
mContext->RSSetViewports(1, &vp);
And of course, before every frame I call the following:
mContext->ClearRenderTargetView(mTarget.Get(), color);
mContext->ClearDepthStencilView(mDepthStencilView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
But unfortunately, the result ends up being this (note that the crysis nanosuit model is behind the goblin head) I believe this could potentially also be why the goblin model is rendering incorrectly even when alone but haven't figured that one out yet.
Example 1
And with just the goblin, looking from an angle
Example 2
If anyone can help me figure out why its not working, I'd greatly appreciate it!
EDIT
After some more frustrating testing I discovered the depth testing was broken because of some test text rendering I was doing with DirectX ToolKit's SpriteBatch and SpriteFont classes. Has anyone come across this issue before? I don't really want/need the toolkit for anything other than text rendering and perhaps loading dds textures so I'm hoping if I want to use those classes I don't need to drastically change my existing code?
DirectX Tool Kit does not 'capture/restore' state like the legacy D3DX9/D3DX10 sprite did. This was inefficient and relied on some hacky back-door functionality to capture the 'state block' for Direct3D 10+. In most cases, you are already going to set the bulk of the commonly used state to set up for the next draw call anyhow.
Instead, I have fully documented all state impacted by each class. You are expected to change all required state after the DirectX Tool Kit object renders. For example, SpriteBatch docs state:
SpriteBatch makes use of the following states:
BlendState
Constant buffer (Vertex Shader stage, slot 0)
DepthStencilState
Index buffer
Input layout
Pixel shader
Primitive topology
RasterizerState
SamplerState (Pixel Shader stage, slot 0)
Shader resources (Pixel Shader stage, slot 0)
Vertex buffer (slot 0)
Vertex shader
So in short, you just need to set the DepthStencilState to what you want to use after you call SpriteBatch::End.
As a general habit for state management, you should set all state you rely on every frame. While in Direct3D 11 the 'last state' at the time you call Present is still there at the start of the next frame, this isn't true of DirectX 12. As such, you should make a habit of at the start of a new frame setting everything like current render target, viewport, render states you expect to be present for your whole scene, etc.
For example, most "HUD" rendering is done last, so the state changes by SpriteBatch would normally be reset on the next frame's start--again, assuming you set up the required state at the start of the frame rather than assuming it remains unchanged over many frames.
TL;DR: Move this code to just after you clear the render target each frame:
mContext->OMSetDepthStencilState(depthState.Get(), 1);
mContext->OMSetRenderTargets(1, mTarget.GetAddressOf(), mDepthStencilView.Get());
D3D11_VIEWPORT vp = { 0.f, 0.f, float(width), float(height), D3D11_MIN_DEPTH, D3D11_MAX_DEPTH };
mContext->RSSetViewports(1, &vp);
Related
I am currently working on a school project using DirectX11 and have started making the back buffer here. I believe I have followed everything correctly but, when creating my DepthStencilView, I am getting Null as return; I'm probably doing somthing stupid but I cant seem to work it out.
Here are all the relevant code snippets.
//Depth and Stencil Buffer
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = _WindowWidth;
depthStencilDesc.Height = _WindowHeight;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count = 1;
depthStencilDesc.SampleDesc.Quality = 0;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;
_pd3dDevice->CreateTexture2D(&depthStencilDesc, nullptr, &_depthStencilBuffer);
_pd3dDevice->CreateDepthStencilView(_depthStencilBuffer, nullptr, &_depthStencilView);
_pImmediateContext->OMSetRenderTargets(1, &_pRenderTargetView, _depthStencilView);
In my cleanup function:
if (_depthStencilView)_depthStencilView->Release();
if (_depthStencilBuffer) _depthStencilBuffer->Release();
In my draw function:
//Clear depth/stencil
_pImmediateContext->ClearDepthStencilView(_depthStencilView, D3D11_CLEAR_STENCIL, 1.0f, 0);
I worked out how to fit it, was just the order moved things around it worked perfectly.
I was trying to implement depth buffer into my renderer in DirectX 11.0, but I encountered specyfic problem. I'm new in DirectX so it might be stupid question, but I can't fix it by myself. I checked many tutorials about this topic and each show how to do this more or less the same.
I have got two triangles on the scene. When I enable depth everythink disappers and I have got blue screen (background color) only.
To enable depth buffer I firstly created "Depth Stencil Texture Description" and created "Depth Stencil Buffer" with "Depth Stencil View". Then as last parameter of function OMSetRenderTargets I set DepthStencilView. After that I created "Depth Stencil State".
D3D11_TEXTURE2D_DESC depthStencilTextureDesc;
depthStencilTextureDesc.Width = width;
depthStencilTextureDesc.Height = height;
depthStencilTextureDesc.MipLevels = 1;
depthStencilTextureDesc.ArraySize = 1;
depthStencilTextureDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilTextureDesc.SampleDesc.Count = 1;
depthStencilTextureDesc.SampleDesc.Quality = 0;
depthStencilTextureDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilTextureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilTextureDesc.CPUAccessFlags = 0;
depthStencilTextureDesc.MiscFlags = 0;
hr = Device->CreateTexture2D(&depthStencilTextureDesc, nullptr, DepthStencilBuffer.GetAddressOf());
if (FAILED(hr))
{
Logger::Error("Error creating depth stencil buffer!");
return false;
}
hr = Device->CreateDepthStencilView(DepthStencilBuffer.Get(), nullptr, DepthStencilView.GetAddressOf());
if (FAILED(hr))
{
Logger::Error("Error creating depth stencil view!");
return false;
}
Logger::Debug("Successfully created depth stencil buffer and view.");
DeviceContext->OMSetRenderTargets(1, RenderTargetView.GetAddressOf(), DepthStencilView.Get());
Logger::Debug("Binding render target output merge successfully.");
D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
ZeroMemory(&depthStencilDesc, sizeof(D3D11_DEPTH_STENCIL_DESC));
depthStencilDesc.DepthEnable = true;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
hr = Device->CreateDepthStencilState(&depthStencilDesc, DepthStencilState.GetAddressOf());
if (FAILED(hr))
{
Logger::Error("Error creating depth stencil state!");
return false;
}
Then I set viewport depth with this code:
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
Then I moved to my Render function and added clearing depth stencil and setting state like this:
...
DeviceContext->ClearDepthStencilView(DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
...
DeviceContext->OMSetDepthStencilState(DepthStencilState.Get(), 0);
And... It doesn't work. If change last parameter of OMSetRenderTargets from DepthStencilView.Get() to nullptr it works. So it seams like I did somethink wrong with depth stencil, but I'm not sure what. I created gist for this Renderer.cpp HERE. Please help me solve this, becase I'm stucked in this and I don't know what to do.
When creating a Depth/Stencil View, make sure that the MSAA settings for Sample and Count are the same for both the Render Target View and the Depth Stencil View.
The DSV may need additional information when being created for an MSAA target. Here is an example of how my DSV is created (note that I am not using the Stencil Buffer and instead chose to get more precision on my depth buffer):
//Describe our Depth/Stencil Buffer
D3D11_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = activeDisplayMode.Width;
depthStencilDesc.Height = activeDisplayMode.Height;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_R32_TYPELESS;
depthStencilDesc.SampleDesc.Count = sampleLevel;
depthStencilDesc.SampleDesc.Quality = qualityLevel;
depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;
if (MSAAEnabled == true)
{
//Need a DSVDesc to let it know to use MSAA
D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
ZeroMemory(&depthStencilViewDesc, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
depthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT;
depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
depthStencilViewDesc.Texture2D.MipSlice = 0;
dev->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer);
dev->CreateDepthStencilView(depthStencilBuffer, &depthStencilViewDesc, &depthStencilView);
}
else
{
//Don't need a DSVDesc
dev->CreateTexture2D(&depthStencilDesc, NULL, &depthStencilBuffer);
dev->CreateDepthStencilView(depthStencilBuffer, NULL, &depthStencilView);
}
I will summerize what I found with GaleRazorwind help. I fixed my problem by setting depthStencilTextureDesc multisampling values to the same values from BufferDesc.
I would like to scale a texture I created from AcquireNextFrame.
Here is my code :
if (gRealTexture == nullptr) {
D3D11_TEXTURE2D_DESC description;
texture2D->GetDesc(&description);
description.BindFlags = 0;
description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
description.Usage = D3D11_USAGE_STAGING;
description.MiscFlags = 0;
hr = gDevice->CreateTexture2D(&description, NULL, &gRealTexture);
if (FAILED(hr)) {
if (gRealTexture) {
gRealTexture->Release();
gRealTexture = nullptr;
}
return NULL;
}
}
gImmediateContext->CopyResource(gRealTexture, texture2D);
D3D11_MAPPED_SUBRESOURCE mapped;
hr = gImmediateContext->Map(gRealTexture, 0, D3D11_MAP_READ_WRITE, 0, &mapped);
if (FAILED(hr)) {
gRealTexture->Release();
gRealTexture = NULL;
return NULL;
}
unsigned char *source = static_cast<unsigned char *>(mapped.pData); //Here I get the pixel buffer data
Problem is that it is in Full HD Resolution (1920x1080). I would like to decrease the resolution (1280x720 for example) because I need to send source over network. And I don't really need a Full HD image.
Is it possible to do it with DirectX easily before I get the pixel buffer ?
Thanks
Create a smaller resolution texture, render the texture2d to the smaller texture using a fullscreen quad (but shrinking to the new size). Make sure bilinear filtering is on.
Then copy and map the smaller texture. CopyResource needs the same dimensions.
Some resources:
DX11 Helper Library
Render To Texture
DX11 Post Processing blur
The blur setup is the same as what I'm talking about, only instead of using a blur shader you use a simple texture shader.
I tried to implement the depth buffer in Direct3D 11, but it turns out to not be as easy as I fought. Here's my problem : Whenever I'm calling this function :
m_DeviceContext->OMSetRenderTargets(1, &m_RTV, m_DepthStencilView);
With the 3rd parameter as my depth stencil view, I see nothing in my window ; everything is black. If I put nullptr then all my geometries are rendered without any depth testing (like it was before I atempt to implement depth). Here's how I'm creating my depth buffer and my depth stencil view :
D3D11_TEXTURE2D_DESC depthBufferDesc;
ZeroMemory(&depthBufferDesc, sizeof(D3D11_TEXTURE2D_DESC));
depthBufferDesc.Width = iwidth;
depthBufferDesc.Height = iheight;
depthBufferDesc.MipLevels = 1;
depthBufferDesc.ArraySize = 1;
depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthBufferDesc.SampleDesc.Count = 1;
depthBufferDesc.SampleDesc.Quality = 0;
depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
hr = m_Device->CreateTexture2D(&depthBufferDesc, nullptr, &m_DepthStencilBuffer);
hr = m_Device->CreateDepthStencilView(m_DepthStencilBuffer, nullptr, &m_DepthStencilView);
I search for quite some time to find the solution but I didn't help me. I also checked the viewport but it doesn't work. I also clean up the view every frame.
Can you help me out please ? I'll appreciate it :) Thanks.
You probably forgot to clear your depth buffer to 1.0 before trying to use it.
I have in my CreateDeviceResources method the following code: (the method is called at initial once).
What do i need to do to create a method change the texture?
void SetTexture(...textureinput...);
Do i need to run below code everytime a texture needs to be changed? or can I somehow just change some data in memory?
I have found that I would like to use ID3D11DeviceContext::UpdateSubresource, but havent been able to find a sample on how to use it.
auto textureData = reader->ReadData("SIn.Win8\\texturedata.bin");
D3D11_SUBRESOURCE_DATA textureSubresourceData = {0};
textureSubresourceData.pSysMem = textureData->Data;
// Specify the size of a row in bytes, known a priori about the texture data.
textureSubresourceData.SysMemPitch = 1024;
// As this is not a texture array or 3D texture, this parameter is ignored.
textureSubresourceData.SysMemSlicePitch = 0;
// Create a texture description from information known a priori about the data.
// Generalized texture loading code can be found in the Resource Loading sample.
D3D11_TEXTURE2D_DESC textureDesc = {0};
textureDesc.Width = 256;
textureDesc.Height = 256;
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = 0;
// Most textures contain more than one MIP level. For simplicity, this sample uses only one.
textureDesc.MipLevels = 1;
// As this will not be a texture array, this parameter is ignored.
textureDesc.ArraySize = 1;
// Don't use multi-sampling.
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
// Allow the texture to be bound as a shader resource.
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
ComPtr<ID3D11Texture2D> texture;
DX::ThrowIfFailed(
m_d3dDevice->CreateTexture2D(
&textureDesc,
&textureSubresourceData,
&texture
)
);
// Once the texture is created, we must create a shader resource view of it
// so that shaders may use it. In general, the view description will match
// the texture description.
D3D11_SHADER_RESOURCE_VIEW_DESC textureViewDesc;
ZeroMemory(&textureViewDesc, sizeof(textureViewDesc));
textureViewDesc.Format = textureDesc.Format;
textureViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
textureViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
textureViewDesc.Texture2D.MostDetailedMip = 0;
ComPtr<ID3D11ShaderResourceView> textureView;
DX::ThrowIfFailed(
m_d3dDevice->CreateShaderResourceView(
texture.Get(),
&textureViewDesc,
&textureView
)
);
// Once the texture view is created, create a sampler. This defines how the color
// for a particular texture coordinate is determined using the relevant texture data.
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
// The sampler does not use anisotropic filtering, so this parameter is ignored.
samplerDesc.MaxAnisotropy = 0;
// Specify how texture coordinates outside of the range 0..1 are resolved.
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
// Use no special MIP clamping or bias.
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
// Don't use a comparison function.
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
// Border address mode is not used, so this parameter is ignored.
samplerDesc.BorderColor[0] = 0.0f;
samplerDesc.BorderColor[1] = 0.0f;
samplerDesc.BorderColor[2] = 0.0f;
samplerDesc.BorderColor[3] = 0.0f;
ComPtr<ID3D11SamplerState> sampler;
DX::ThrowIfFailed(
m_d3dDevice->CreateSamplerState(
&samplerDesc,
&sampler
)
);
If you want to update the same texture at runtime, you need to use Map
Maptype needs to be D3D11_MAP_WRITE_DISCARD
Also your texture needs to be created with the Dynamic flag instead of default, and cpu access flag needs to be set to D3D11_CPU_ACCESS_WRITE
If gives you access to D3D11_MAPPED_SUBRESOURCE , and you can set the new data using pData
Depending on the case it can be nicer to just recreate a texture, it's on a case by case basis (dynamic is nice if texture changes often)