DirectX12 ④ インデックスバッファの作成
インデックスバッファの作成
GPUにインデックスのデータを渡すためのバッファ。
環境
言語 : C++
開発環境 : Visual Studio 2020
OS : Windows10
CPU : AMD Ryzen5 3600
RAM : 24.0GB
GPU : NVIDIA GeForce GTX 1050
ソースコード
IndexBuffer.h
#pragma once #include <d3d12.h> #include <cstdint> #include <wrl/client.h> #include <iostream> #include "Dx.h" #pragma comment(lib, "d3d12.lib") using namespace Microsoft::WRL; class IndexBuffer { public: IndexBuffer(); bool CreateIndexBuffer(size_t size, uint32_t* data); D3D12_INDEX_BUFFER_VIEW GetIndexBufferView(); private: ComPtr<ID3D12Resource> _pBuffer; D3D12_INDEX_BUFFER_VIEW _indexBufferView; };
IndexBuffer.cpp
#include "IndexBuffer.h" //初期化 IndexBuffer::IndexBuffer() { _indexBufferView = {}; } //インデックスバッファの作成 bool IndexBuffer::CreateIndexBuffer(size_t size, uint32_t* data) { //ヒーププロパティ D3D12_HEAP_PROPERTIES heapProp = {}; heapProp.Type = D3D12_HEAP_TYPE_UPLOAD; //GPUにアップロード heapProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProp.CreationNodeMask = 0; heapProp.VisibleNodeMask = 0; //リソースの設定(バッファ用) D3D12_RESOURCE_DESC desc = {}; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; //バッファ用 desc.Alignment = 0; //配置 desc.Width = size; //リソースの幅(データのサイズ) desc.Height = 1; //リソースの高さ desc.DepthOrArraySize = 1; //深さ desc.MipLevels = 1; //ミップマップはしない desc.Format = DXGI_FORMAT_UNKNOWN; //形式は指定しない desc.SampleDesc.Count = 1; //サンプリングはしない desc.SampleDesc.Quality = 0; desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; desc.Flags = D3D12_RESOURCE_FLAG_NONE; //リソースの作成 HRESULT hResult = dx->GetDevice()->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(_pBuffer.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create IndexBuffer" << std::endl; return false; } //インデックスバッファビュー _indexBufferView.BufferLocation = _pBuffer->GetGPUVirtualAddress(); //アドレス _indexBufferView.Format = DXGI_FORMAT_R32_UINT; //形式はunsigned int 32ビット _indexBufferView.SizeInBytes = static_cast<uint32_t>(size); //データのサイズ //マッピング if (data != nullptr) { void* ptr = nullptr; hResult = _pBuffer->Map(0, nullptr, &ptr); if (FAILED(hResult)) { std::cout << "Failed mapping IndexBuffer" << std::endl; return false; } memcpy(ptr, &data[0], size); //コピー _pBuffer->Unmap(0, nullptr); } return true; } //インデックスバッファビューの取得 D3D12_INDEX_BUFFER_VIEW IndexBuffer::GetIndexBufferView() { return _indexBufferView; }
参考資料
書籍
サイト
DirectX12 ③ 頂点バッファの作成
頂点バッファの作成
GPUに頂点のデータを渡すためのバッファ。
環境
言語 : C++
開発環境 : Visual Studio 2020
OS : Windows10
CPU : AMD Ryzen5 3600
RAM : 24.0GB
GPU : NVIDIA GeForce GTX 1050
ソースコード
VertexBuffer.h
#pragma once #include <d3d12.h> #include <cstdint> #include <wrl/client.h> #include <iostream> #include "Dx.h" #pragma comment(lib, "d3d12.lib") class VertexBuffer { public: VertexBuffer(); bool CreateVertexBuffer(size_t size, size_t stride, const void* data); D3D12_VERTEX_BUFFER_VIEW GetVertexBufferView() const; private: ComPtr<ID3D12Resource> _pVertexBuffer; D3D12_VERTEX_BUFFER_VIEW _vertexBufferView; };
VertexBuffer.cpp
#include "VertexBuffer.h" //初期化 VertexBuffer::VertexBuffer() { _vertexBufferView = {}; } //頂点バッファの作成 bool VertexBuffer::CreateVertexBuffer(size_t size, size_t stride, const void* data) { //ヒーププロパティ D3D12_HEAP_PROPERTIES heapProp= {}; heapProp.Type = D3D12_HEAP_TYPE_UPLOAD; //GPUにアップロード heapProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProp.CreationNodeMask = 0; heapProp.VisibleNodeMask = 0; //リソースの設定(バッファ) D3D12_RESOURCE_DESC desc = {}; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; //バッファ用 desc.Alignment = 0; //配置 desc.Width = size; //リソースの幅 desc.Height = 1; //リソースの高さ desc.DepthOrArraySize = 1; //深さ desc.MipLevels = 1; //ミップマップのレベル desc.Format = DXGI_FORMAT_UNKNOWN; //形式は指定しない desc.SampleDesc.Count = 1; //サンプリングはしない desc.SampleDesc.Quality = 0; desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; desc.Flags = D3D12_RESOURCE_FLAG_NONE; //頂点バッファを作成 HRESULT hResult; hResult = dx->GetDevice()->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(_pVertexBuffer.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create VertexBuffer" << std::endl; return false; } //マッピング void* ptr = nullptr; hResult = _pVertexBuffer->Map(0, nullptr, &ptr); if (FAILED(hResult)) { std::cout << "Failed mapping VertexBuffer" << std::endl; return false; } memcpy(ptr, data, size); //コピー _pVertexBuffer->Unmap(0, nullptr); _vertexBufferView.BufferLocation = _pVertexBuffer->GetGPUVirtualAddress(); //アドレス _vertexBufferView.SizeInBytes = static_cast<uint32_t>(size); //頂点データのサイズ _vertexBufferView.StrideInBytes = static_cast<uint32_t>(stride); //1頂点あたりのデータサイズ return true; } //頂点バッファビューの取得 D3D12_VERTEX_BUFFER_VIEW VertexBuffer::GetVertexBufferView() const { return _vertexBufferView; }
参考資料
書籍
サイト
DirectX12 ② 初期化
DirectX12の初期化
言語 : C++
開発環境 : Visual Studio 2020
OS : Windows10
CPU : AMD Ryzen5 3600
RAM : 24.0GB
GPU : NVIDIA GeForce GTX 1050
画面のクリアまで
ヘッダファイル
Dx.h
#pragma once #include <dxgi1_4.h> #include <d3d12.h> #include <wrl/client.h> #include <cstdint> #include <iostream> #include <vector> #pragma comment(lib, "d3d12.lib") #pragma comment(lib, "dxgi.lib") using namespace Microsoft::WRL; constexpr uint32_t FRAME_BUFFER_COUNT = 2; class Dx { public: Dx(); bool Init(uint32_t width, uint32_t height, HWND hwnd); void Terminate(); void BeginRender(); void EndRender(); void ResetCmdList(); void ExcuteCmdList(); ID3D12Device* GetDevice(); ID3D12GraphicsCommandList* GetCmdList(); uint32_t GetWindowWidth(); uint32_t GetWindowHeight(); uint32_t GetCurrentBackBufferIndex(); private: void Present(uint32_t interval); void WaitGPU(); bool CreateFactory(); bool CreateDevice(); bool CreateCommandQueue(); bool CreateSwapChain(); bool CreateCommandAllocator(); bool CreateCommandList(); bool CreateRenderTarget(); bool CreateFence(); bool CreateDepthStencil(); void CreateViewPort(); void CreateScissorRect(); private: HWND _hwnd; uint32_t _width, _height; //ウィンドウの高さと幅 ComPtr<IDXGIFactory4> _pFactory; //ファクトリー ComPtr<ID3D12Device> _pDevice; //デバイス ComPtr<ID3D12CommandQueue> _pCmdQueue; //コマンドキュー ComPtr<IDXGISwapChain3> _pSwapChain; //スワップチェイン ComPtr<ID3D12Resource> _pRenderTargets[FRAME_BUFFER_COUNT]; //レンダーターゲット ComPtr<ID3D12CommandAllocator> _pCmdAllocator[FRAME_BUFFER_COUNT]; //コマンドアロケーター ComPtr<ID3D12GraphicsCommandList> _pCmdList; //コマンドリスト ComPtr<ID3D12DescriptorHeap> _pHeapRTV; //レンダーターゲット用のディスクリプタヒープ ComPtr<ID3D12RootSignature> _pRootSignature; //ルートシグネチャ ComPtr<ID3D12PipelineState> _pPipelineState; //パイプラインステート ComPtr<ID3D12Fence> _pFence; //フェンス ComPtr<ID3D12DescriptorHeap> _pHeapDSV; //デプスステンシルビュー用のディスクリプタヒープ ComPtr<ID3D12Resource> _pDepthStencilBuffer; //デプスステンシルバッファ uint32_t _currentBackBufferIndex; //バックバッファーのインデックス HANDLE _fenceEvent; //フェンスイベント uint64_t _fenceCount[FRAME_BUFFER_COUNT]; //フェンスカウント D3D12_CPU_DESCRIPTOR_HANDLE _handleRTV[FRAME_BUFFER_COUNT]; //レンダーターゲットビューのハンドル D3D12_CPU_DESCRIPTOR_HANDLE _handleDSV; //デプスステンシルビューのハンドル D3D12_VIEWPORT _viewPort; D3D12_RECT _scissorRect; }; extern Dx* dx; //グローバル変数
コンストラクタと初期化関数
Dx.cpp
Dx* dx; Dx::Dx() { _hwnd = nullptr; _currentBackBufferIndex = 0; _fenceEvent = nullptr; _handleDSV = {}; _height = 0; _width = 0; _scissorRect = {}; _viewPort = {}; for (uint32_t i = 0; i < FRAME_BUFFER_COUNT; i++) { _fenceCount[i] = 0; _handleRTV[i] = {}; } } bool Dx::Init(uint32_t width, uint32_t height, HWND hwnd) { HRESULT hResult; #if defined(DEBUG) || defined(_DEBUG) { ComPtr<ID3D12Debug> debug; hResult = D3D12GetDebugInterface(IID_PPV_ARGS(debug.GetAddressOf())); if (SUCCEEDED(hResult)) { debug->EnableDebugLayer(); } } #endif _hwnd = hwnd; _width = width; _height = height; if (!CreateFactory()) { return false; } if (!CreateDevice()) { return false; } if (!CreateCommandQueue()) { return false; } if (!CreateSwapChain()) { return false; } if (!CreateCommandAllocator()) { return false; } if (!CreateCommandList()) { return false; } if (!CreateRenderTarget()) { return false; } if (!CreateDepthStencil()) { return false; } if (!CreateFence()) { return false; } CreateViewPort(); CreateScissorRect(); _pCmdList->Close(); return true; }
デバイスの作成(NVIDIAのグラボを使用する場合)
Dx.cpp
//DXGIファクトリーの作成 bool Dx::CreateFactory() { HRESULT hResult; hResult = CreateDXGIFactory1(IID_PPV_ARGS(_pFactory.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create DXGIFactory" << std::endl; return false; } return true; } //デバイスの作成 bool Dx::CreateDevice() { HRESULT hResult; //アダプター列挙 std::vector <IDXGIAdapter*> adapters; IDXGIAdapter* tmpAdapter = nullptr; for (uint32_t i = 0; _pFactory->EnumAdapters(i, &tmpAdapter) != DXGI_ERROR_NOT_FOUND; ++i) { adapters.push_back(tmpAdapter); } //アダプターの選択 for (auto adpt : adapters) { DXGI_ADAPTER_DESC adesc = {}; adpt->GetDesc(&adesc); std::wstring strDesc = adesc.Description; //NVIDIAのグラボを探す if (strDesc.find(L"NVIDIA") != std::string::npos) { tmpAdapter = adpt; break; } } //フィーチャレベル列挙 D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, }; //デバイスの作成 //フィーチャーレベルを探す for (D3D_FEATURE_LEVEL l : levels) { hResult = D3D12CreateDevice(tmpAdapter, l, IID_PPV_ARGS(&_pDevice)); if (hResult == S_OK) { break; } } if (hResult != S_OK) { std::cout << "Failed to create Device" << std::endl; return false; } tmpAdapter->Release(); //使い終わったらリリース return true; }
デバイスの作成(グラボを指定しない場合)
Dx.cpp
//DXGIファクトリーの作成 bool Dx::CreateFactory() { HRESULT hResult; hResult = CreateDXGIFactory1(IID_PPV_ARGS(_pFactory.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create DXGIFactory" << std::endl; return false; } return true; } //デバイスの作成 bool Dx::CreateDevice() { HRESULT hResult; //フィーチャレベル列挙 D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, }; //デバイスの作成 //フィーチャーレベルを探す for (D3D_FEATURE_LEVEL l : levels) { hResult = D3D12CreateDevice(nullptr, l, IID_PPV_ARGS(&_pDevice)); if (hResult == S_OK) { break; } } if (hResult != S_OK) { std::cout << "Failed to create Device" << std::endl; return false; } return true; }
コマンドキューの作成
Dx.cpp
//コマンドキューの作成 bool Dx::CreateCommandQueue() { D3D12_COMMAND_QUEUE_DESC cmdQueueDesc = {}; cmdQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; cmdQueueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; cmdQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; cmdQueueDesc.NodeMask = 0; HRESULT hResult = _pDevice->CreateCommandQueue(&cmdQueueDesc, IID_PPV_ARGS(_pCmdQueue.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create CommnadQueue" << std::endl; return false; } return true; }
スワップチェインの作成
Dx.cpp
//スワップチェインの作成 bool Dx::CreateSwapChain() { DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferDesc.Width = _width; swapChainDesc.BufferDesc.Height = _height; swapChainDesc.BufferDesc.RefreshRate.Numerator = 60; swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; swapChainDesc.SampleDesc.Count = 1; swapChainDesc.SampleDesc.Quality = 0; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = FRAME_BUFFER_COUNT; swapChainDesc.OutputWindow = _hwnd; swapChainDesc.Windowed = TRUE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; ComPtr<IDXGISwapChain> swapChain; HRESULT hResult = _pFactory->CreateSwapChain(_pCmdQueue.Get(), &swapChainDesc, swapChain.GetAddressOf()); if (FAILED(hResult)) { std::cout << "Failed to create IDXGISwapChain" << std::endl; return false; } //IDXGISwapChain3を取得 hResult = swapChain.As(&_pSwapChain); if (FAILED(hResult)) { std::cout << "Failed to get IDXGISwapChain3" << std::endl; return false; } //バックバッファ番号を取得 _currentBackBufferIndex = _pSwapChain->GetCurrentBackBufferIndex(); swapChain.Reset(); //解放 return true; }
コマンドアロケータの作成
Dx.cpp
//コマンドアロケータの作成 bool Dx::CreateCommandAllocator() { HRESULT hResult; for (uint32_t i = 0; i < FRAME_BUFFER_COUNT; i++) { hResult = _pDevice->CreateCommandAllocator( D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(_pCmdAllocator[i].GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create CommandAllocator" << std::endl; return false; } } return true; }
コマンドリストの作成
Dx.cpp
//コマンドリストの作成 bool Dx::CreateCommandList() { HRESULT hResult = _pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, _pCmdAllocator[_currentBackBufferIndex].Get(), nullptr, IID_PPV_ARGS(_pCmdList.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create CommandList" << std::endl; return false; } return true; }
レンダーターゲットビューの作成
Dx.cpp
//レンダーターゲットビューの作成 bool Dx::CreateRenderTarget() { //ディスクリプタヒープの作成 D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; heapDesc.NumDescriptors = FRAME_BUFFER_COUNT; heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; heapDesc.NodeMask = 0; HRESULT hResult = _pDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(_pHeapRTV.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create DescriptorHeap" << std::endl; return false; } D3D12_CPU_DESCRIPTOR_HANDLE handle = _pHeapRTV->GetCPUDescriptorHandleForHeapStart(); uint32_t incrementSize = _pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); for (uint32_t i = 0; i < FRAME_BUFFER_COUNT; i++) { hResult = _pSwapChain->GetBuffer(i, IID_PPV_ARGS(_pRenderTargets[i].GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to get RenderTargets" << std::endl; return false; } D3D12_RENDER_TARGET_VIEW_DESC viewDesc = {}; viewDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; viewDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; viewDesc.Texture2D.MipSlice = 0; viewDesc.Texture2D.PlaneSlice = 0; _pDevice->CreateRenderTargetView(_pRenderTargets[i].Get(), &viewDesc, handle); _handleRTV[i] = handle; handle.ptr += incrementSize; } return true; }
フェンスの作成
Dx.cpp
//フェンスの作成 bool Dx::CreateFence() { for (uint32_t i = 0; i < FRAME_BUFFER_COUNT; i++) { _fenceCount[i] = 0; } HRESULT hResult = _pDevice->CreateFence(_fenceCount[_currentBackBufferIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(_pFence.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create Fence" << std::endl; return false; } _fenceCount[_currentBackBufferIndex]++; //イベントの作成 _fenceEvent = CreateEvent(nullptr, false, false, nullptr); if (_fenceEvent == nullptr) { return false; } return true; }
デプスステンシルビューの作成
Dx.cpp
//デプスステンシルビューの作成 bool Dx::CreateDepthStencil() { D3D12_HEAP_PROPERTIES heapProp = {}; heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; heapProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; heapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; heapProp.CreationNodeMask = 1; heapProp.VisibleNodeMask = 1; D3D12_RESOURCE_DESC desc = {}; desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; desc.Alignment = 0; desc.Width = _width; desc.Height = _height; desc.DepthOrArraySize = 1; desc.MipLevels = 1; desc.Format = DXGI_FORMAT_D32_FLOAT; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; D3D12_CLEAR_VALUE clearValue; clearValue.Format = DXGI_FORMAT_D32_FLOAT; clearValue.DepthStencil.Depth = 1.0f; clearValue.DepthStencil.Stencil = 0; HRESULT hResult = _pDevice->CreateCommittedResource(&heapProp, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue, IID_PPV_ARGS(_pDepthStencilBuffer.GetAddressOf())); if (FAILED(hResult)) { std::cout << "Failed to create DepthStencilBuffer" << std::endl; return false; } D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; heapDesc.NumDescriptors = 1; heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; heapDesc.NodeMask = 0; hResult = _pDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&_pHeapDSV)); if (FAILED(hResult)) { std::cout << "Failed to create DescriptorHeap for DepthStencilView " << std::endl; return false; } D3D12_CPU_DESCRIPTOR_HANDLE handle = _pHeapDSV->GetCPUDescriptorHandleForHeapStart(); uint32_t incrementSize = _pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); D3D12_DEPTH_STENCIL_VIEW_DESC viewDesc = {}; viewDesc.Format = DXGI_FORMAT_D32_FLOAT; viewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; viewDesc.Texture2D.MipSlice = 0; viewDesc.Flags = D3D12_DSV_FLAG_NONE; _pDevice->CreateDepthStencilView(_pDepthStencilBuffer.Get(), &viewDesc, handle); _handleDSV = handle; return true; }
ビューポート、シザー矩形の作成
Dx.cpp
//ビューポートの作成 void Dx::CreateViewPort() { _viewPort.TopLeftX = 0; _viewPort.TopLeftY = 0; _viewPort.Width = static_cast<float>(_width); _viewPort.Height = static_cast<float>(_height); _viewPort.MinDepth = 0.0f; _viewPort.MaxDepth = 1.0f; } //シザー矩形の作成 void Dx::CreateScissorRect() { _scissorRect.left = 0; _scissorRect.right = _width; _scissorRect.top = 0; _scissorRect.bottom = _height; }
終了処理
Dx.cpp
//終了処理 void Dx::Terminate() { WaitGPU(); if (_fenceEvent != nullptr) { CloseHandle(_fenceEvent); _fenceEvent = nullptr; } _pHeapRTV.Reset(); } //GPUの処理待機 void Dx::WaitGPU() { //シグナル処理 _pCmdQueue->Signal(_pFence.Get(), _fenceCount[_currentBackBufferIndex]); //イベントを設定 _pFence->SetEventOnCompletion(_fenceCount[_currentBackBufferIndex], _fenceEvent); //待機処理 WaitForSingleObjectEx(_fenceEvent, INFINITE, false); _fenceCount[_currentBackBufferIndex]++; }
レンダリング
Dx.cpp
//描画開始 void Dx::BeginRender() { //コマンドの記録開始 _pCmdAllocator[_currentBackBufferIndex]->Reset(); _pCmdList->Reset(_pCmdAllocator[_currentBackBufferIndex].Get(), nullptr); //リソースバリア D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = _pRenderTargets[_currentBackBufferIndex].Get(); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; _pCmdList->ResourceBarrier(1, &barrier); //レンダーターゲットの設定 _pCmdList->OMSetRenderTargets(1, &_handleRTV[_currentBackBufferIndex], false, &_handleDSV); //クリアカラー(赤) float clearColor[] = { 1.0f, 0.0f, 0.0f, 1.0f }; //レンダーターゲットビューをクリア _pCmdList->ClearRenderTargetView(_handleRTV[_currentBackBufferIndex], clearColor, 0, nullptr); //デプスステンシルバッファクリア _pCmdList->ClearDepthStencilView(_handleDSV, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); //ビューポートとシザー矩形をセット _pCmdList->RSSetViewports(1, &_viewPort); _pCmdList->RSSetScissorRects(1, &_scissorRect); } //描画終了 void Dx::EndRender() { //リソースバリア D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = _pRenderTargets[_currentBackBufferIndex].Get(); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; _pCmdList->ResourceBarrier(1, &barrier); //コマンドリストを閉じる _pCmdList->Close(); //コマンドを実行 ID3D12CommandList* ppCmdLists[] = { _pCmdList.Get() }; _pCmdQueue->ExecuteCommandLists(1, ppCmdLists); //画面に表示 Present(1); } //コマンドリストのリセット void Dx::ResetCmdList() { //_pCmdAllocator->Reset(); _pCmdList->Reset(_pCmdAllocator->Get(), nullptr); } //コマンドリストの実行 void Dx::ExcuteCmdList() { ID3D12CommandList* ppCmdLists[] = { _pCmdList.Get() }; _pCmdQueue->ExecuteCommandLists(1, ppCmdLists); //シグナル処理 uint64_t currentValue = _fenceCount[_currentBackBufferIndex]; _pCmdQueue->Signal(_pFence.Get(), currentValue); if (_pFence->GetCompletedValue() != currentValue) { auto event = CreateEvent(nullptr, false, false, nullptr); _pFence->SetEventOnCompletion(currentValue, event); WaitForSingleObject(event, INFINITE); CloseHandle(event); } _pCmdAllocator[_currentBackBufferIndex]->Reset(); _pCmdList->Reset(_pCmdAllocator[_currentBackBufferIndex].Get(), nullptr); } //表示 void Dx::Present(uint32_t interval) { //画面に表示 _pSwapChain->Present(interval, 0); //シグナル処理 uint64_t currentValue = _fenceCount[_currentBackBufferIndex]; _pCmdQueue->Signal(_pFence.Get(), currentValue); //バックバッファ番号を更新 _currentBackBufferIndex = _pSwapChain->GetCurrentBackBufferIndex(); //描画待機 if (_pFence->GetCompletedValue() < _fenceCount[_currentBackBufferIndex]) { _pFence->SetEventOnCompletion(_fenceCount[_currentBackBufferIndex], _fenceEvent); WaitForSingleObjectEx(_fenceEvent, INFINITE, false); } _fenceCount[_currentBackBufferIndex] = currentValue + 1; }
getter関数
Dx.cpp
//デバイスの取得 ID3D12Device* Dx::GetDevice() { return _pDevice.Get(); } //コマンドリストの取得 ID3D12GraphicsCommandList* Dx::GetCmdList() { return _pCmdList.Get(); } //ウィンドウの高さの取得 uint32_t Dx::GetWindowWidth() { return _width; } //ウィンドウの幅の取得 uint32_t Dx::GetWindowHeight() { return _height; } //バックバッファのインデックスを取得 uint32_t Dx::GetCurrentBackBufferIndex() { return _currentBackBufferIndex; }
実行結果
クリアカラーで赤を指定しているため、赤い画面が表示されている。
参考資料
書籍
サイト
DirectX12 ① ウィンドウの作成
開発環境
言語 : C++
開発環境 : Visual Studio 2020
OS : Windows10
CPU : AMD Ryzen5 3600
RAM : 24.0GB
GPU : NVIDIA GeForce GTX 1050
DirectX12について
ここでは、Direct3D 12のことをDirectX12と呼ぶ。DirectX12は、Microsoftが開発する、DirectX12互換GPUを搭載したPCにおいてグラフィックス機能や計算機能をアプリケーションで利用すためのAPIである。
Win32 APIについて
ウィンドウの表示にはWin32 APIを使う。
Win32 APIは、ウィンドウの描画などWindowsの機能を使用するためのAPIである。
DirectX12はOpenGLのようにglutやGLFWなどの簡単にウィンドウを表示するための機能がないため、Win32 APIによってウィンドウの表示を行う。
main.cpp
#include "App.h" int main() { App app(1080, 720); app.Run(); }
App.h
#pragma once #include <Windows.h> #include <cstdint> #include <string> class App { public: App(uint32_t width, uint32_t height); void Run(); private: bool InitApp(); bool InitWindow(); void MainLoop(); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); private: const std::wstring WindowClassName = L"WindowClass"; uint32_t _width; uint32_t _height; HWND _hwnd; HINSTANCE _hInstance; };
App.cpp
#include "App.h" App::App(uint32_t width, uint32_t height) { _width = width; _height = height; _hwnd = nullptr; _hInstance = nullptr; } void App::Run() { if (!InitApp()) { return; } MainLoop(); } //初期化 bool App::InitApp() { if (!InitWindow()) { return false; } return true; } //ウィンドウの初期化 bool App::InitWindow() { _hInstance = GetModuleHandle(nullptr); if (_hInstance == nullptr) { return false; } //ウィンドウの設定 WNDCLASSEX wc = {}; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; //水平方向と垂直方向のサイズ変更で再描画 wc.lpfnWndProc = WndProc; //ウィンドウプロシージャの登録 wc.hIcon = LoadIcon(_hInstance, IDI_APPLICATION); //アイコン wc.hCursor = LoadCursor(_hInstance, IDC_ARROW); //マウスカーソル wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //背景色は黒 wc.hInstance = _hInstance; //インスタンスハンドル wc.lpszMenuName = nullptr; //メニュー wc.lpszClassName = WindowClassName.c_str(); //ウィンドウクラスの名前 wc.hIconSm = LoadIcon(_hInstance, IDI_APPLICATION); //小さいアイコン RegisterClassEx(&wc); //ウィンドウクラスの登録 //ウィンドウサイズ RECT rc = {}; rc.right = static_cast<long>(_width); //ウィンドウの幅 rc.bottom = static_cast<long>(_height); //ウィンドウの高さ auto style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; AdjustWindowRect(&rc, style, false); _hwnd = CreateWindowEx( 0, WindowClassName.c_str(), L"Title", style, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, _hInstance, nullptr ); ShowWindow(_hwnd, SW_SHOWNORMAL); SetFocus(_hwnd); return true; } //メインループ void App::MainLoop() { MSG msg = {}; while (WM_QUIT != msg.message) { if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE == true)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { // ここに描画処理を書く } } } //ウィンドウプロシージャ LRESULT CALLBACK App::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); break; default: break; } return DefWindowProc(hwnd, msg, wParam, lParam); }
実行結果