DirectXの話 第114回
Uncharted 2式Filmicトーンマップ
今回はPS3の名作『Uncharted 2』で使用されているトーンマップをやってみました。
今更感があるので詳しい解説はしませんが、HDRレンダリングには欠かせない機能です。
トーンマップで有名な物と言えばReinhardのものかと思います。
『Uncharted 2』ではFilmicトーンマップという、その名の通り映画のフィルムのようなトーンマップです。
GDCの発表によればHaarm-Peter Duiker氏が開発した物で、例としてコダックフィルムのトーンカーブが示されてましたね。
本来はRGBそれぞれにルックアップテーブルを使用する手法なのですが、計3回のテクスチャフェッチは安くありません。
しかし、Jim Hejl氏によって近似式が作成され、それをまた修正したのが今回の手法です。
計算式は割と簡単です。
Func(x) = ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
FinalColor = Func(LinearColor) / Func(LinearWhite)
各変数の意味は以下の通りです。
A~Fまでは曲線の形状を指定するパラメータです。
LinearColorは入力されるカラーです。
LinearWhiteはリニアカラーの白色です。日本語では白点と呼ばれます。
計算式を見ての通り、計算自体は軽いですし、ある程度事前計算しておくことが可能です。
実際の見た目はどうかと言われると…フィルムっぽいと言われればそうなのかな?って感じでしょうか。
正直なところ、よくわからないというのが感想です。
で、今回はHDRの映像が必要だったので自分でレンダリングしようかと思ったのですが、見た目がよろしくないだろうと言うことでテクスチャを貼り付けるだけにしました。
テクスチャは.hdr形式のものを使用しています。
DXSDKのサンプルに入っていたものですが、他のものもネットを探せば結構見つかります。
基本的に浮動小数点バッファで格納されているもので、申し訳程度にランレングス圧縮されています。
α値は持てませんが、Windows7では普通にサムネイル表示してくれます。割と一般的みたいですね。
これをLogLuvに変換し、RGBA8テクスチャに保存して実際には使用しています。
ソースコードはサンプル中の"./data/shaders/include/log_luv.h"にあります。
あと、今回やっているのはブルームくらいですね。
よくある、トーンマップ後に1.0以上のピクセルを抜き出してブルームする手段ではなく、Exposure(露光)に対して閾値を減算し、これでトーンマップを行ったバッファをブルームとして使用しています。
やってみたらなかなか綺麗で、個人的には結構好みの映像になっています。
問題点としては、Exposureによるバイアスをかけたあとにトーンマップをしなければならないため、ブルームバッファ用と通常バッファ用で2回のトーンマップが必要になります。
今回のトーンマップはそんなに重くないのでそれでもいいかもしれませんが、現行世代のコンシューマゲーム機にはちょっと不向きかもしれません。
明順応、暗順応もやってみようかと思ったのですが、そもそもテクスチャが変化しないのでパスしました。
今後の課題ですかね。
また、実装して思ったのですが、色味がかなり変化します。
プログラマが勝手に実装するとデザイナさんからかなり文句が出るでしょうね。
トーンマップをきちんと実装したいと考えている方は、デザイナさんが扱いやすい形のツールやViewerを提供すべきでしょう。
場合によってはExposureをシーンや場所によって設定し、デザイナさんが制御できるようにした方がいいこともあるかもしれません。
こうするとデザイナさんの仕事がかなり増えるのですが、その方がいいという人もいるでしょう。
その辺りは現場ごとにどう実装するかきちんと相談し合うべきだと思います。
プログラマがなんとかしてくれるよ、って思われているのであれば遠慮せずにやっちゃってもいいと思いますが。
LogLuvテクスチャは.hdrと同様にα値が使えません。
とはいっても、HDRテクスチャ自体、環境マップやIBLでもない限りあんまり使わないでしょうから問題ないと思います。
しかし、やはり計算量が多いのが問題でしょう。
環境マップくらいにしか使用しないのであれば、RGBEとか使った方がいいでしょう。
サンプルは下からDLできます。
次回は激しく未定。というか、ネタがない。
そろそろ本格的にKinectをいじろうか迷っているので、そっち方面になるかも。