お久しぶりですNKのS.Tです。ちょうど1年ぶりの投稿となります(その間に社名が2回変わったのは秘密)
前回は三角形の描画まででしたので今回はテクスチャーを追加してみます。
■環境
OS: Windows 10
IDE: Visual Studio 2017 Community
SDK: Windows 10 SDK (10.0.15063.468)
■初期設定
IDEをVisual Studio 2017に変更しましたが参照設定等は前回と同じです。
ビルドできない場合はSDKが足りないので、Visual Studio 2017のインストーラーからSDKをいろいろ入れてみてください(適当)
■コーディング
今回もわかりやすさ重視でクラス等は作成せず、main.cppのみで進めます。
インデックスバッファや定数バッファも作成しないので、おそらく最短のテクスチャー描画プログラムではないでしょうか。
以下、ソース変更点です。
テクスチャーのみを表示するので色データを削除してテクスチャーのUV座標を追加します。
1 2 3 4 |
struct Vertex{ XMFLOAT3 position; XMFLOAT2 uv; }; |
1 2 3 4 |
D3D12_INPUT_ELEMENT_DESC inputElementDescs[] = { {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}, }; |
一枚絵のビットマップを表示したいので三角形から四角形に変更します。
1 2 3 4 5 6 7 8 |
Vertex triangleVertices[] = { {{-0.25f, 0.25f*g_aspectRatio, 0.0f}, {0.0f, 0.0f}}, {{ 0.25f, 0.25f*g_aspectRatio, 0.0f}, {1.0f, 0.0f}}, {{ 0.25f, -0.25f*g_aspectRatio, 0.0f}, {1.0f, 1.0f}}, {{-0.25f, 0.25f*g_aspectRatio, 0.0f}, {0.0f, 0.0f}}, {{ 0.25f, -0.25f*g_aspectRatio, 0.0f}, {1.0f, 1.0f}}, {{-0.25f, -0.25f*g_aspectRatio, 0.0f}, {0.0f, 1.0f}}, }; |
1 |
g_commandList->DrawInstanced(6, 2, 0, 0); |
空のルートシグネチャを作成していた部分にテクスチャーとサンプラーを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// テクスチャーの記述子ヒープを渡す D3D12_DESCRIPTOR_RANGE descriptorRange = {}; D3D12_ROOT_PARAMETER rootParameter = {}; D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; D3D12_STATIC_SAMPLER_DESC staticSamplerDesc = {}; ComPtr<ID3DBlob> blob = {}; descriptorRange.NumDescriptors = 1; descriptorRange.BaseShaderRegister = 0; descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; rootParameter.DescriptorTable.NumDescriptorRanges = 1; rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRange; // サンプラーの設定(s0) staticSamplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; staticSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; staticSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; staticSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; staticSamplerDesc.MipLODBias = 0.0f; staticSamplerDesc.MaxAnisotropy = 16; staticSamplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; staticSamplerDesc.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; staticSamplerDesc.MinLOD = 0.0f; staticSamplerDesc.MaxLOD = D3D12_FLOAT32_MAX; staticSamplerDesc.ShaderRegister = 0; staticSamplerDesc.RegisterSpace = 0; staticSamplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; rootSignatureDesc.NumParameters = 1; rootSignatureDesc.pParameters = &rootParameter; rootSignatureDesc.NumStaticSamplers = 1; rootSignatureDesc.pStaticSamplers = &staticSamplerDesc; if(FAILED(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr))) return FALSE; if(FAILED(g_device->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&g_rootSignature)))) return FALSE; |
テクスチャー用に用意したビットマップを読み込み初期化を行います。
簡易読み込みのためアルファ値には対応していません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
// ビットマップファイルを読み込み // (DDB&GetPixelでピクセルデータを読み込む簡易版なのでアルファ値には対応してません) HBITMAP hBitmap; hBitmap = (HBITMAP)LoadImage(0, _T("texture.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); if(!hBitmap) return FALSE; HDC hMemDC; BITMAP bmp; hMemDC = CreateCompatibleDC(NULL); SelectObject(hMemDC, hBitmap); GetObject(hBitmap, sizeof(BITMAP), &bmp); DeleteObject(hBitmap); std::vector<uint32_t> pixel; for(int y=0; y<bmp.bmHeight; y++){ for(int x=0; x<bmp.bmWidth; x++){ COLORREF color = GetPixel(hMemDC, x, y); BYTE r = color&0xFF; BYTE g = (color>>8)&0xFF; BYTE b = (color>>16)&0xFF; pixel.push_back((r<<16)|(g<<8)|b); } } DeleteObject(hMemDC); // テクスチャー用のリソースを作成 D3D12_HEAP_PROPERTIES heapProperties = {}; heapProperties.Type = D3D12_HEAP_TYPE_CUSTOM; heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK; heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0; heapProperties.CreationNodeMask = 1; heapProperties.VisibleNodeMask = 1; D3D12_RESOURCE_DESC resourceDesc = {}; resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; resourceDesc.Width = bmp.bmWidth; resourceDesc.Height = bmp.bmHeight; resourceDesc.DepthOrArraySize = 1; resourceDesc.MipLevels = 1; resourceDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; resourceDesc.SampleDesc.Count = 1; resourceDesc.SampleDesc.Quality = 0; resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; if(FAILED(g_device->CreateCommittedResource(&heapProperties, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&g_rTexture)))) return FALSE; // テクスチャー用の記述子ヒープを作成 D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {}; descriptorHeapDesc.NumDescriptors = 1; descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; descriptorHeapDesc.NodeMask = 0; if(FAILED(g_device->CreateDescriptorHeap(&descriptorHeapDesc, IID_PPV_ARGS(&g_dhTexture)))) return FALSE; // テクスチャー用のシェーダーリソースビューを作成 D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = {}; D3D12_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc = {}; shaderResourceViewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; shaderResourceViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shaderResourceViewDesc.Texture2D.MipLevels = 1; shaderResourceViewDesc.Texture2D.MostDetailedMip = 0; shaderResourceViewDesc.Texture2D.PlaneSlice = 0; shaderResourceViewDesc.Texture2D.ResourceMinLODClamp = 0.0F; shaderResourceViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; cpuDescriptorHandle = g_dhTexture->GetCPUDescriptorHandleForHeapStart(); g_device->CreateShaderResourceView(g_rTexture.Get(), &shaderResourceViewDesc, cpuDescriptorHandle); // 画像データをサブリソースへコピー D3D12_BOX box = {0, 0, 0, (UINT)bmp.bmWidth, (UINT)bmp.bmHeight, 1}; if(FAILED(g_rTexture->WriteToSubresource(0, &box, &pixel[0], sizeof(uint32_t)*bmp.bmWidth, sizeof(uint32_t)*bmp.bmWidth*bmp.bmHeight))) return FALSE; |
描画部分でテクスチャーをレジスタに設定します。
1 2 3 4 |
// テクスチャーをシェーダーのレジスタに設定(t0) ID3D12DescriptorHeap *descriptorHeap[] = {g_dhTexture.Get()}; g_commandList->SetDescriptorHeaps(_countof(descriptorHeap), descriptorHeap); g_commandList->SetGraphicsRootDescriptorTable(0, g_dhTexture->GetGPUDescriptorHandleForHeapStart()); |
最後にHLSLの変更点です。
ここでも色データを削除してテクスチャー関連を追加しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Texture2D<float4> tex0 : register(t0); SamplerState samp0 : register(s0); struct PSInput{ float4 position : SV_POSITION; float4 uv : TEXCOORD; }; PSInput VSMain(float4 position : POSITION, float4 uv : TEXCOORD) { PSInput result; result.position = position; result.uv = uv; return result; } float4 PSMain(PSInput input) : SV_TARGET { return tex0.Sample(samp0, input.uv); } |
実行するとウィンドウが表示され中央にビットマップが表示されているはずです。
前回と同様にD3D12CreateDeviceが失敗する場合はビデオカードがDirectX12に対応していないのでg_useWarpDeviceをtrueにしてみてください。
WARPデバイス(ソフトウェア)を使用するようになりますのでまず動くと思います。
ソースはこちらからダウンロード出来ます。
Windows10と同時に出てきたDirectX12は登場から2年経ちましたが、amazonで書籍を検索してみたところ英語版が1冊・日本語版は0冊でした…
一体誰に需要があるのか謎で本当に遊んでみた記事になってしまいましたが、また何かできたらいいなと思っています。