DirectX DirectX12でのWICを使ったpngの描画
あいさつ
どうも、はかせです。
今日は昨日のオムライスの逆襲なのか
飯テロを食らいました。
@hakase70945250 pic.twitter.com/yOYc5GQ1nF
— 転生ろっさむ@垢ロックで作り直し (@Ev_rossam) 2019年10月3日
こ、こんな飯テロ効かねぇ!(究極のやせ我慢)
さてMSMVP懇親の飯テロをこらえたところで
話はまるっと変わりDirectX12です。
いよいよ今週の土曜日にCEDECがあります。
今日明日でなるべくDirectX12の知識を入れて、
臨みたいと思います。
今回のネタは
「DirectX12でWICを使ったpngの描画」
です。
pngを描画したい
前回まではDirectX12の概要的なものを抑えていきました。
その中でポリゴンを描画するということはできるようになりました。
ポリゴンが描画出来たら次はテクスチャでしょう。
今回はpng画像の描画として
このブログや私のTwitterのアイコンになっている
ハロを描画してみます。
(本当いつ見ても最高にぐうかわ)
どうやってやる?
DirectX12からは11まであったファイルの読み込みとかの
関数が軒並み無くなっているそうです。
なので自作のローダーとか使って
画像を読み込みそれをリソースに割り当てる必要があります。
ただ私は今までデコーダーというものを作ったことがありません。
一応pngがチャンクで分かれてて云々は知っているのですが、
どうにもどう起こせばいいかよくわかりません。
なので「directx12 png 描画」みたいなキーワードでググってたんですが、
英語記事含めヒットはせず・・・
ヒットしたとしても未解決の質問とかばっかり・・・
もうにっちもさっちもいかなくなり
Twitterに呟いたらですね、
通りがかった神様がお告げを授けてくださいました。
「WIC使えばBMPとかと同様に読み込めますよ」
MA・ZI・DE!?
その話を聞くまで私の中で
WIC=DirectX11専用みたいなイメージがありました。
(includeにd3d11.hあったし、ググっても全然記事とか出てこないし)
ただ調べてみたところ12版もあるらしく、
似たサンプルもネットに落ちていました。
それによくよく考えたらWICって
Windows Imaging Componentの略ですもんね。
DirectX11で使えてDirectX12で使えない方が不自然でしたね。
これはもうやるっきゃねぇ。
ということでWICを使ってやります。
テクスチャ読み込み
基本的にソースコードは後述の参考のものと
ほぼ同じなのでここでは私が変えた部分だけを。
参考元ではDDSを使って読み込んでいたのをWICに直しただけですね。
// Note: ComPtr's are CPU objects but this resource needs to stay in scope until // the command list that references it has finished executing on the GPU. // We will flush the GPU at the end of this method to ensure the resource is not // prematurely destroyed. CoInitializeEx(NULL, COINIT_MULTITHREADED); ComPtr<ID3D12Resource> textureUploadHeap; // Load texture from WIC. { std::unique_ptr<uint8_t[]> wicData; D3D12_SUBRESOURCE_DATA subresouceData; ThrowIfFailed(LoadWICTextureFromFile(m_device.Get(), L"Haro.png", &m_texture, wicData, subresouceData)); D3D12_RESOURCE_DESC textureDesc = m_texture->GetDesc(); const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, 1); // Create the GPU upload buffer. ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&textureUploadHeap))); UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, 1, &subresouceData); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); // Describe and create a SRV for the texture. D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; srvDesc.Format = textureDesc.Format; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->GetCPUDescriptorHandleForHeapStart()); m_commandList->DiscardResource(textureUploadHeap.Get(), nullptr); } CoUninitialize();
変更点としては
・subresouceDataを配列からただの変数に変更
・同時に配列数を扱っていた部分を1で固定
・COMなのでCoInitializeExとCoUninitialize追加
という感じになります。
これを実行すると
無事ハロが出ました!
ぐうかわ!!!
CoInitializeとCoInitializeEx
WIC使えますよーというありがたいお言葉を授けてくれたお方からですね、
「CoInitializeEx呼び出さないと使えませんよ」という忠告を受けました。
(ありがたや)
ただここで一つ疑問が生まれます。
私が以前DirectX11で使っていた時はCoInitializeを呼び出して
使っていました。
一体この二つは何が違うんだろうか?
ということでググってみました。
詳しく語るとこの記事の文字数が
大幅に膨れ上がってしまうため簡単にまとめると、
CoInitialize
シングルスレッドで使う
メッセージループに直接ないし間接的に関係している
スレッドでCOMを使う場合に指定
CoInitializeEx
マルチスレッドで使う
メッセージループに直接ないし間接的に関係していない
スレッドでCOMを使う場合に指定
といった感じ。
ちなみにCoInitializeExの第二引数に
どちらにするかを設定することができるため
基本はCoInitializeExを使うべきだそうです。
詳しくは下記の記事を参照
www.kekyo.net
www.kekyo.net
あとがき
今回はDirectX12でWICを使ってpngを描画してみました。
なぜかわからないですけど全然記事がネット上にないんですよね。
みんなググらなくてもこのぐらいできるからですかね?
ただ私はできなかったのでこの世のどこかにはこの記事の需要があると信じたい・・・
今日上がった私の友人の記事で
なぜかべらぼうに持ち上げられてますが、
全然そんな実力はないですw
ちなみにその記事がこちら
tkz9545.hatenablog.com
最近ブログを再開したようで
日々の進捗+おすすめのゲームの紹介をしています。
設計とかAIとかに興味があるらしいです。
多分そっち方面のまさかりだったら泣いて喜ぶと思うので是非。
それでは今回はこの辺でノシ