DirectXTex : OpenEXRのテクスチャへの読み込み

はじめに

前回の記事ではDirectXTexのDDS読み込みをやりましたが,今回はDirectXTexのライブラリを使ってOpneEXRのファイルをテクスチャとして読み込みをします.
以前の記事でDirectXTexでOpenEXRのテクスチャをDDSにコンバートするための方法を紹介しましたが,今回は直接読みこみます.
最近,HDRディスプレイ向けのコードを書くようになってきていますが,ゲームのランタイムではDDSを使う方が良いことが多いですし,BC6HなどのGPU上でも小さく持てるフォーマットを使うことが多いわけですが,ツールなどを作成する際にはOpenEXRが読めておくと便利なことがあると思いますので対応方法を紹介しておきます.

OpenEXRとは

OpenEXRはILMがオープンソースにしている画像フォーマットでHDR画像を保存するのに適した作りになっています.圧縮に関してもデフォルトでサポートされています.
DCCツールでは,Photoshop CCでも対応している(RGBの色のチャンネルを32bitモードにする必要があります)ので比較的データも作成がしやすいと思います.
http://www.openexr.com/

今回のサンプル


今回のサンプルは以下にアップしています.
https://github.com/shaderjp/ShaderjpDirect3D12Samples/tree/master/D3D12OpenEXRTexure

開発の準備

今回は前回の記事の記事の手法よりも前々回の記事を参考にしていきます.

DirectXTexのライブラリを追加

今回は,DirectXTexのライブラリ自体を使用する必要性があります.
これはソリューションからそのままプロジェクト追加してしまえばOKですね.

依存する外部ライブラリのセットアップ

今回ものOpenEXR対応で必要なライブラリの2つを入れる必要があります.

これらのライブラリを自分でビルドすればOpenEXR対応になりますが,結構ビルドが面倒なのでAdding OpenEXRに書かれているもう1つの手段NuGetからビルド済みパッケージを入手する方法にします.なお,これに関しては,”Building the OpenEXR auxiliary library”の”Using NuGet”のところに書かれています.

パッケージ マネージャー コンソールを開くと下記のような画面がありますが,赤丸で囲った【既定のプロジェクト】を【D3D12OpenEXRTexture】になっているのを確認します.

コンソールにNuGet Galleryの各ページに書かれているPackage Managerのコマンドを入力するとビルド済みのライブラリやヘッダーファイルがダウンロードされます.
ソリューションファイルのあるフォルダ階層にpackagesフォルダというのが出てきているのがわかると思います.
今回は,サンプルを見るとわかりますが,DirectXTexのプロジェクトをソリューションに追加していまス.このライブラリのヘッダーファイルとビルド後のライブラリDirectXTex.libがリンクできる状態にしておきます.

必要なソースの追加

DirectXTexのOpenEXR対応については,さらにヘッダーファイルとソースの追加を行う必要があります.追加するヘッダーファイルとソースは下記です.

これはそのままプロジェクトに追加すればOKです.
今回は,このヘッダーファイルにあるLoadFromEXRFile関数を後程使います.

コードサンプル

今回のコード例は下記です.
まずは,DirectXTexEXR.hを#includeしておいてください.
OpenEXRファイルのロードからテクスチャの生成は,D3D12HelloEXR.cppの277行目あたりからはじまっています.
まずは,LoadFromEXRFileでOpenEXRのファイルをロードします.今回添付している画像は,Photoshopで作成しましたが,Zlibで圧縮しています.今回のサンプルはOpenEXRのファイル自体は圧縮してあるものも大丈夫です.
TexMetadata構造体にテクスチャの幅,高さやミップレベル,フォーマットなどD3D12_RESOURCE_DESCにセットが必要なものは取れると思います.なお,今回はDXGI_FORMAT_R16G16B16A16_FLOATの非圧縮で乗ります.
DDSのロードの時は,LoadDDSTextureFromFileが内部でCreateCommittedResourceしてますが,今回はしてくれないので自分で呼び出します.Heap TypeはD3D12_HEAP_TYPE_DEFAULTでD3D12_HEAP_TYPE_UPLOADからコピーができるようにできるようにD3D12_RESOURCE_STATE_COPY_DESTにしておきます.
m_textureが生成できたらメインメモリからGPUのローカルメモリ上にあるm_textureにデータをコピーするためのtextureUploadHeapを作ります.
ミップマップにも対応するためにD3D12_SUBRESOURCE_DATAを構築していきますが,scratchImageでGetImagesの配列アクセスで取れます.今回はミップマップに対応する処理を書いてはいますが,実際にはミップレベルは1しかないのでこの処理は決め打ちで一番上のレベルだけでいいのかもしれません.
D3D12_SUBRESOURCE_DATAが構築できたらD3DX12.hのUpdateSubresourcesでコピーします.終わったらShaderResouceViewを作成してDescriptor Heapにリソースを登録ですね.
textureUploadHeapのメモリはDiscardResourceで解放しておきましょう.

おわりに

texconvでやっていることをランタイムでやってしまうということではあったのですが,無事にOpenEXRから直接テクスチャを作ることができました.
DirectXTexのライブラリを持ってきたり,OpenEXRやZlibなどを持ってくるので,1ヘッダーファイルと1ソースファイルで済む前回のDDSを読むのに比べると準備が大きいですが,テクスチャを用意する側に事前にコンバートとかしてもらわないで済むのが良いですね.