This tutorial is part of a Collection: 02. DirectX 10 - Braynzar Soft Tutorials
1410
views
08. Depth Buffer
Here we will learn how to bind a depth buffer to our render target. A depth buffer tests each pixel on the back buffer before presenting it to the screen. If there is a primitive in front of another primitive, then the primitive in front will get its pixels drawn, and the pixels in the primitive behind that are covered up by the pixels in the primitive in front will not get drawn.
I'm trying to make lessons short because I remember always getting bored after a while of trying to work through a big tutorial. This is another short lesson on the depth buffer. The depth buffer tests each pixel, the the pixel with the lowest depth (pixel closest to the screen) will get drawn, the others are discarded. For an example, a cirle that is in front and covers a section of a square. the section of the square that is covered up by the circle will be discarded since the circles pixels will be drawn. You can think of it like painting. Paint a square first, then paint a circle over a section of the square, thats how the depth buffer works. Its not really confusing at all, I hope i didn't make things more confusing by trying to explain this. We start this lesson out by declaring two new interfaces, one for the depth/stencil view, and one for the depth/stencil buffer. ID3D10DepthStencilView* DepthStencilView; ID3D10Texture2D* DepthStencilBuffer; Then we go down to the InitializeDirect3dApp function. This is where we will initialize our buffer and bind it to the target view. We will create a 2D texture description, which will be the description of our depth/stencil buffer, using the D3D10_TEXTURE2D_DESC type. D3D10_TEXTURE2D_DESC depthStencilDesc; Now we fill out the our depth/stencil buffer description. First two lines is the width and height of our depth stencil buffer, which is usually the width and height of our window. The next line is miplevels, we will use these in a later lesson, for a depth stencil buffer, we only need one. ArraySize is the number of textures in an array, we only need one here. The next is the format of our texture, we specify DXGI_FORMAT_D24_UNORM_S8_UINT, which is 24 bits for the depth buffer, and 8 bits for the stencil buffer. After that line is the SampleDesc quality and count. This is used for multi sampling, and we will have a later lesson on it, for now, just use 1 and 0. For usage, we will just use default, but it can be any of the D3D10_USAGE enumerated types. BindFlags is specifying where the resource will be bound to the pipeline. Since this is the depth stencil buffer, we specify D3D10_BIND_DEPTH_STENCIL here. Here we specify how the cpu (our application) will access the resource. Since only the GPU will access by reading and writing to it, we can specify 0 here. The last line describing our texture is other flags, we do not need any for a depth/stencil buffer. depthStencilDesc.Width = Width; depthStencilDesc.Height = Height; depthStencilDesc.MipLevels = 1; depthStencilDesc.ArraySize = 1; depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthStencilDesc.SampleDesc.Count = 1; depthStencilDesc.SampleDesc.Quality = 0; depthStencilDesc.Usage = D3D10_USAGE_DEFAULT; depthStencilDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL; depthStencilDesc.CPUAccessFlags = 0; depthStencilDesc.MiscFlags = 0; Next we create the texture using the CreateTexture2D method of our device interface. The first parameter is a pointer to the our depth/stencil buffer description we just filled out. The second parameter is the data we will fill the texture with, however, since its the depth/stencil buffer, the GPU will be filling it with data, not us. The third is the returned texture we will use to bind to create a depth stencil view. d3dDevice->CreateTexture2D(&depthStencilDesc, NULL, &DepthStencilBuffer); This line is creating out depth stencil view, which we will be binding to the pipeline. The first parameter is the returned depthstencilbuffer from above, the second parameter would be used if we filled out a depth/stencil state, but we don't need to for now so we can just set it to NULL. the third is the returned pointer to the depth/stencil view, which we will use to bind to the pipeline. d3dDevice->CreateDepthStencilView(DepthStencilBuffer, NULL, &DepthStencilView); This line is being modified, we had this in the previous lessons, but the third parameter was set to NULL before, now we set it to the depth stencil view, so we can bind the depth stencil view to the pipeline. d3dDevice->OMSetRenderTargets(1, &RenderTargetView, DepthStencilView); Now we go down to the drawScene function. Here we add a new line, which refreshes the depth buffer each time the drawscene function is called. If we don't do this. all we see is a black screen, or whatever color screen we cleared our target view to. The first parameter is a pointer to the depth/stencil to be cleard. The second is which parts of the buffer we want to clear, which we will be clearing the depth and stencil. The next one is what we clear the value of the depth to, we set 1 for this, because its 0 - 1. The last parameter is the value we clear the stencil to, we will set 0 here since we don't use it. d3dDevice->ClearDepthStencilView(DepthStencilView, D3D10_CLEAR_DEPTH|D3D10_CLEAR_STENCIL, 1.0f, 0); Now we have a depth/stencil buffer! Direct3D will now know which pixels to draw based on their depth into the screen if multiple pixels are competing to be drawn onto the screen! Here's the final code: main.cpp #include <Windows.h> #include <d3d10.h> #include <d3dx10.h> #include <string> #pragma comment(lib, "D3D10.lib") #pragma comment(lib, "d3dx10d.lib") LPCTSTR WndClassName = L"firstwindow"; HWND hwnd = NULL; const int Width = 800; const int Height = 600; bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed); HRESULT hr; ID3D10Device* d3dDevice; IDXGISwapChain* SwapChain; ID3D10RenderTargetView* RenderTargetView; ID3D10Effect* FX; ID3D10InputLayout* VertexLayout; ID3D10Buffer* VertexBuffer; ID3D10Buffer* IndexBuffer; ID3D10EffectTechnique* Technique; ////////////////////new////////////////////////////////////////////////////////////////////// ID3D10DepthStencilView* DepthStencilView; ID3D10Texture2D* DepthStencilBuffer; ////////////////////new////////////////////////////////////////////////////////////////////// bool InitializeDirect3dApp(HINSTANCE hInstance); bool InitScene(); void DrawScene(); bool ReleaseObjects(); int messageloop(); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); struct Vertex { D3DXVECTOR3 pos; D3DXCOLOR color; }; int WINAPI WinMain(HINSTANCE hInstance, //Main windows function HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { if(!InitializeWindow(hInstance, nShowCmd, Width, Height, true)) { MessageBox(0, L"Window Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitializeDirect3dApp(hInstance)) { MessageBox(0, L"Direct3D Initialization - Failed", L"Error", MB_OK); return 0; } if(!InitScene()) { MessageBox(0, L"Scene Initialization - Failed", L"Error", MB_OK); return 0; } messageloop(); if(!ReleaseObjects()) { MessageBox(0, L"Object Releasing - Failed", L"Error", MB_OK); return 0; } return 0; } bool InitializeWindow(HINSTANCE hInstance, int ShowWnd, int width, int height, bool windowed) { typedef struct _WNDCLASS { UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS; WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2); wc.lpszMenuName = NULL; wc.lpszClassName = WndClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, L"Error registering class", L"Error", MB_OK | MB_ICONERROR); return 1; } hwnd = CreateWindowEx( NULL, WndClassName, L"Window Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, NULL, NULL, hInstance, NULL ); if (!hwnd) { MessageBox(NULL, L"Error creating window", L"Error", MB_OK | MB_ICONERROR); return 1; } ShowWindow(hwnd, ShowWnd); UpdateWindow(hwnd); return true; } bool InitializeDirect3dApp(HINSTANCE hInstance) { UINT createDeviceFlags = 0; D3D10_DRIVER_TYPE driverTypes[] = { D3D10_DRIVER_TYPE_HARDWARE, D3D10_DRIVER_TYPE_REFERENCE, }; UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] ); DXGI_SWAP_CHAIN_DESC scd; scd.BufferDesc.Width = Width; scd.BufferDesc.Height = Height; scd.BufferDesc.RefreshRate.Numerator = 60; scd.BufferDesc.RefreshRate.Denominator = 1; scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; scd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //no multisampling scd.SampleDesc.Count = 1; scd.SampleDesc.Quality = 0; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.BufferCount = 1; scd.OutputWindow = hwnd; scd.Windowed = true; scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; scd.Flags = 0; D3D10CreateDeviceAndSwapChain(0, D3D10_DRIVER_TYPE_HARDWARE, 0, 0, D3D10_SDK_VERSION, &scd, &SwapChain, &d3dDevice); ID3D10Texture2D* backBuffer; SwapChain->GetBuffer(0, _uuidof(ID3D10Texture2D), reinterpret_cast<void**>(&backBuffer)); d3dDevice->CreateRenderTargetView(backBuffer, 0, &RenderTargetView); backBuffer->Release(); ////////////////////new////////////////////////////////////////////////////////////////////// D3D10_TEXTURE2D_DESC depthStencilDesc; depthStencilDesc.Width = Width; depthStencilDesc.Height = Height; depthStencilDesc.MipLevels = 1; depthStencilDesc.ArraySize = 1; depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthStencilDesc.SampleDesc.Count = 1; depthStencilDesc.SampleDesc.Quality = 0; depthStencilDesc.Usage = D3D10_USAGE_DEFAULT; depthStencilDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL; depthStencilDesc.CPUAccessFlags = 0; depthStencilDesc.MiscFlags = 0; d3dDevice->CreateTexture2D(&depthStencilDesc, NULL, &DepthStencilBuffer); d3dDevice->CreateDepthStencilView(DepthStencilBuffer, NULL, &DepthStencilView); d3dDevice->OMSetRenderTargets(1, &RenderTargetView, DepthStencilView); ////////////////////new////////////////////////////////////////////////////////////////////// // Setup the viewport D3D10_VIEWPORT vp; vp.Width = Width; vp.Height = Height; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; d3dDevice->RSSetViewports( 1, &vp ); return true; } bool InitScene() { Vertex vertices[] = { {D3DXVECTOR3(-0.5f, -0.5f, 0.5f), D3DXCOLOR (1.0f, 0.0f, 0.0f, 1.0f)}, {D3DXVECTOR3(-0.5f, 0.5f, 0.5f), D3DXCOLOR (0.0f, 1.0f, 0.0f, 1.0f)}, {D3DXVECTOR3( 0.5f, 0.5f, 0.5f), D3DXCOLOR (0.0f, 0.0f, 1.0f, 1.0f)}, {D3DXVECTOR3( 0.5f, -0.5f, 0.5f), D3DXCOLOR (1.0f, 1.0f, 0.0f, 1.0f)} }; D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_IMMUTABLE; bd.ByteWidth = sizeof( Vertex ) * 4; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = 0; bd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; d3dDevice->CreateBuffer( &bd, &InitData, &VertexBuffer ); DWORD indices[] = { 0, 1, 2, 0, 2, 3, }; D3D10_BUFFER_DESC ibd; ibd.Usage = D3D10_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof(DWORD) * 2 * 3; ibd.BindFlags = D3D10_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; D3D10_SUBRESOURCE_DATA iinitData; iinitData.pSysMem = indices; d3dDevice->CreateBuffer(&ibd, &iinitData, &IndexBuffer); UINT stride = sizeof( Vertex ); UINT offset = 0; d3dDevice->IASetVertexBuffers( 0, 1, &VertexBuffer, &stride, &offset ); d3dDevice->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0); D3D10_INPUT_ELEMENT_DESC layout[] = { {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0} }; ID3D10Blob* compilationErrors = 0; HRESULT hr = 0; hr = D3DX10CreateEffectFromFile( L"vertex.fx", NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, d3dDevice, NULL, NULL, &FX, &compilationErrors, NULL ); if(FAILED(hr)) { MessageBoxA(0, (char*)compilationErrors->GetBufferPointer(), 0, 0); compilationErrors->Release(); return false; } Technique = FX->GetTechniqueByName( "Tech" ); D3D10_PASS_DESC PassDesc; Technique->GetPassByIndex( 0 )->GetDesc( &PassDesc ); d3dDevice->CreateInputLayout( layout, 2, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &VertexLayout ); d3dDevice->IASetInputLayout( VertexLayout ); d3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); return true; } bool ReleaseObjects() { if( d3dDevice ) d3dDevice->ClearState(); if( VertexBuffer ) VertexBuffer->Release(); if( IndexBuffer ) IndexBuffer->Release(); if( VertexLayout ) VertexLayout->Release(); if( FX ) FX->Release(); if( RenderTargetView ) RenderTargetView->Release(); if( SwapChain ) SwapChain->Release(); if( d3dDevice ) d3dDevice->Release(); return true; } void DrawScene() { //Draw Scene Here D3DXCOLOR bgColor( 0.0f, 0.0f, 0.0f, 1.0f); d3dDevice->ClearRenderTargetView( RenderTargetView, bgColor ); ////////////////////new////////////////////////////////////////////////////////////////////// d3dDevice->ClearDepthStencilView(DepthStencilView, D3D10_CLEAR_DEPTH|D3D10_CLEAR_STENCIL, 1.0f, 0); ////////////////////new////////////////////////////////////////////////////////////////////// D3D10_TECHNIQUE_DESC techDesc; Technique->GetDesc( &techDesc ); for( UINT p = 0; p < techDesc.Passes; ++p ) { Technique->GetPassByIndex( p )->Apply( 0 ); d3dDevice->DrawIndexed(6, 0, 0); } SwapChain->Present( 0, 0 ); } int messageloop(){ MSG msg; ZeroMemory(&msg, sizeof(MSG)); while(true) { BOOL PeekMessageL( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ); if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else{ // run game code DrawScene(); } } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_KEYDOWN: if( wParam == VK_ESCAPE ){ if(MessageBox(0, L"Are you sure you want to exit?", L"Really?", MB_YESNO | MB_ICONQUESTION) == IDYES) DestroyWindow(hwnd); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } vertex.fx struct VS_OUTPUT //output structure for vertex shader { float4 Pos : SV_POSITION; float4 Color : COLOR0; }; // Vertex Shader VS_OUTPUT VS(float4 inPos : POSITION, float4 inColor : COLOR) { VS_OUTPUT output = (VS_OUTPUT)0; output.Pos = inPos; //No calculations done here, just returns the position of the vertices output.Color = inColor; return output; //send color and position to pixel shader } // Pixel Shader float4 PS(VS_OUTPUT input) : SV_Target { return input.Color; // Set the color of the pixel to what we defined for the vertex. } technique10 Tech { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }
Sign in to comment