Unity 2019.3 の HDR ディスプレイ出力機能を試す (2019.3b1)

## はじめに


この記事は [Unityゆるふわサマーアドベントカレンダー2019](https://qiita.com/nkjzm/items/7c933bb5c772a0b75512) の 18 日目の記事です (追加参加) 。

以前書いた " [Unity で HDR (High Dynamic Range) と WCG (Wide Color Gamut) を考える (UnityHDROutputPlugin の解説)](https://qiita.com/tan-y/items/80a7f9021c5ae2ff0271) " という記事で

>次世代 (もう現世代ですが) の映像規格として 4K / HDR が標準化され、一般民生機器でも普通に HDR 対応している昨今、 Unity がいつまでたっても HDR 出力に対応してくれないので、 Editor 上で HDR 出力プレビューができるプラグインを作ってみました。

と書いていたのですが、 **ついに Unity 2019.3 で待望の Windows 10 の HDR ディスプレイ出力機能が実装されました！！**🎉

* [Unity 2019.3 beta](https://unity3d.com/jp/unity/beta/2019.3)

>* Windows: HDRDisplay is now supported for UWP and Windows Standalone for DX11 and Dx12

ということで早速試してみました。

テストしたのは 2019.3b1 です。今後のバージョンで変わっていくと思いますので、あくまで b1 の段階での内容ということでご理解ください。

## 今のところわかったことのまとめ

間違ってたらご指摘お願いします。

* Unity Editor 上は HDR にならない
* Bit Depth = 10bit の挙動は謎
* Bit Depth = 16bit は理解できる挙動なので、今から使うなら 16bit にするのがお勧め
* 実行時に HDR のステータスがわからない (下記くらいは知りたい)
    * SDR か HDR か？ (BackBuffer のフォーマット、色空間)
    * ディスプレイの性能

## 使い方

Unity Editor 上の表示を HDR にするのは今のところはできないっぽいです (探し方があまいだけかも) 。

実際に有効にするにはアプリケーションをビルドします。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/e402df9d-d68a-f760-f353-70ec44ce4a53.png)

 "Project Settings - Player - Other Settings" に "Use display in HDR mode" という Checkbox があるのでチェックを入れ、 "Swap Chain Bit Depth" は Swap Chain に設定する Back Buffer のビット深度を指定するものと思われます (10bit が DXGI_FORMAT_R10G10B10A2_UNORM 、 16bit が DXGI_FORMAT_R16G16B16A16_FLOAT のはず) 。
Color Space は Linear にしておきます。

## 検証手順

では本当に HDR で出てるのか検証してみました。

1. Color Space / HDR 設定まわりを切り替えて何パターンかのビルドを用意する
2. 実行する
3. スクリーンショットをとる
4. ツールで解析して比較する

ビルドするアプリは単純に (数値的に) リニアなグラデーションをかけます。

```glsl
fixed4 frag(v2f i) : SV_Target
{
    float v = i.uv.x * 2.0;
    if (i.uv.y > 0.75)		return fixed4(v, 0.0, 0.0, 1.0);
    else if (i.uv.y > 0.5)	return fixed4(0.0, v, 0.0, 1.0);
    else if (i.uv.y > 0.25)	return fixed4(0.0, 0.0, v, 1.0);
    return fixed4(v, v, v, 1.0);
}
```

ポイントですが、 **右端の最大値を 2.0 としています。** 1.0 だと SDR 範囲なので検証になりません。これを OnRenderImage で destinantion にかけます。

スクリーンショットですが、 Windows 10 1803 くらいから "Windows キー + Alt + PrtSc" で JPEG XR でキャプチャー、保存する機能が搭載されています。 HDR 環境下ではちゃんと HDR で保存されますので、これを使って HDR 映像で保存し、比較していきます。

## 比較結果

JPEG XR を読み込ませて波形モニターで比較します。波形モニターは X 座標に対する輝度の分布がわかるものです。

今回の波形モニターのグラフは scRGB 色空間 (色域 = BT.709, 伝達特性 = Linear) で取得したものです。

微妙なゴミっぽいのはウィンドウタイトルバーのなども含んでいるためと思いますのでその辺はスルーしてください。

### Gamma / SDR

![3_Gamma.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/cf5fba6c-d36a-1324-3ba3-3dac038147f1.png)

![2_Gamma.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/fdce3b9b-f56c-f385-d475-7beef1dd7db2.png)

一応参考用にガンマ空間での結果。ガンマカーブがかかっているのがわかります。右端が 2.0 なので、真ん中の 1.0 で飽和しているのがわかります。

### Linear / SDR

![3_Linear.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/1b09ae05-2a04-8c89-47a0-ad7b1a0d3474.png)

![2_LinearSDR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/dfaecfc6-5a40-848a-4b54-0b40fcc8a8fa.png)

リニア空間にすると 1.0 までリニアに値が上がっています。また、 SDR なので Gamma と同様に 1.0 で飽和しています。

### Linear / HDR 10bit

以下映像のスクリーンショットは省略 (SDR で表現不能なため) 。

![2_LinearHDR10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/828fe285-e373-695e-0d5c-618cb96e86f2.png)


今回一番の謎なのがこの 10bit 。

まず右端のピークが 4.0 になっています。想定の倍になっているのですが、 "何故 2 倍なのか" の理由がよくわかりません。

10bit ということは HDR10 (BT.2100 PQ) じゃないと現在の Windows ては出力できません。なので Unity では BT.2100 PQ 色空間に変換して出力しているはずです。

scRGB → BT.2100 PQ 変換をしないでレンダリングをしている、とも考えたのてすが色自体は色域変換しているらしい色になっている (scRGB 状態と変わらない) のと変換なしならもっとまぶしい表示になるはず (実際 Unity HDR Display Output Plugin で BT.2100 PQ 無変換表示を試してみましたが色合いが変わり、明るくなりました) なので、何かしら色空間変換をしているはずなのですが、何故 2 倍・・・？

### Linear / HDR 16bit

![2_LinearHDR16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211064/0cbb602a-e54b-8f04-2da8-8c19425430dc.png)

これは想定通り、右端が 2.0 。 16bit ということは Windows 的には DXGI_FORMAT_R16G16B16A16_FLOAT の scRGB なのでそのまま無変換で書き出せば OK で一番問題が起こりにくい構成です。

## おわりに

ということでざっと試してみました。

Bit Depth 10bit はいまいちよくわかりませんが (精度がらみが理由かなーとか想像) とりあえずちゃんと HDR ディスプレイ出力が機能しているのははじめの一歩としては非常に満足しています。

10bit か 16bit かは、現在流通している一般的なディスプレイは 10bit なので最終出力が 16bit は過剰なのですが、この辺の扱いは今後明確化されるのでしょうか。

出力が HDR に対応さえすれば確かにあとはどうとでもなりますが、機能面での拡張はまだ必要になってくると思いますので今後のアップデートにも期待です。

とりあえず Unity Editor 自体の HDR 対応がされるまでは HDR Output Plugin の価値はまだありそうですね・・・