2022年12月16日金曜日

Bloom

今回はBloomについて。

DirectX12の魔導書に続き、HLSLシェーダーの魔導書も購入した。

前書の方では結果に欠陥があって自分で解決しろというスタイルだったので試してもなかったが、今作ってるレンダリングエンジンの機能に加えるため作ってみることにした。


処理は2つに分かれていて、1つ目が高輝度部分抽出で、2つ目が高輝度部分のブラー処理。
最後に元の画像と、ぼかした画像を加算合成するという流れ。


高輝度部分抽出


まず、HDRレンダリングを行うためにDXGI_FORMAT_R32G32B32A32_FLOATの中間レンダーターゲットを用意する。
元になる画像をこの中間レンダーターゲットにコピーする際、
dot( color.rgb, float3( 0.2125f, 0.7154f, 0.0721f )) ;
この内積の結果が1以上の場合出力するとなっているが、真っ黒な絵しか出力されなかった。
ライトを強めにするとか書いてあるが、コピー部分にはライトが関係なさそうでよくわからない。
ネットで調べてみたところ、同じように出来上がった画像の高輝度部分を抽出する場合、
color.rgb = saturate( color.rgb - 0.9f ) * 10.0f ;
こんな感じになっていた。
実際にこんな方法で抽出した場所を光らせても、求めてるものと違うような気がするがとりあえずはこれでやってみることにする。


ブラー処理 


これは以前作った処理を呼び出せば良いと思ったんだけど、少し問題があった。
静止画の場合は問題なさそうだけど、画面が動くとぼかしの品質が悪くてぼやぼやする感じになった。
ブラーを掛ける前のリソースはミップマップテクスチャでないと品質的に耐えられなさそうなのでミップマップ化する処理を間に追加し、そのミップマップテクスチャでブラーをかけることにした。


最終的な処理の流れ


処理フロー図


1.元画像準備


ブルーム対象の画像。
高輝度のものだけを出力した画像が渡された場合は、次の処理をスキップできるようにした。


2.高輝度部分抽出


今回は色の各成分が0.9以上の箇所を抽出するようにしてみたが、実際には使えないと思ってる。
モデルのEmissiveが値を持っている箇所のみをレンダリングした画像を元画像として出力する仕組みを作ってみる予定。


3.高輝度画像ミップマップ化


ファイル指定のテクスチャをミップマップ付きで用意する仕組みはあったけど、動的なリソースに対してミップマップを作る仕組みがなかった。
なので任意のSRVを指定してミップマップテクスチャを作成する仕組みを用意した。


4.ブラー処理


ミップマップテクスチャを元にブラー処理をかける。


5.元画像とぼかし画像の加算合成


最後は元画像と、ブラー画像を加算合成する。
ブラー画像に対する重みパラメータと、合成後の掛け目のパラメータを用意した。


出力結果


通常レンダリング結果

このレンダリング結果に対してブルーム処理をかけても、高輝度部分が抽出できなかった。

鏡面反射

スペキュラの計算を付け加えて全体をテカテカにして、これに対してブルーム処理をかけてみる。

ブルーム結果

それっぽい結果になった。

ブルーム結果2

パラメータを変えて、ブラー画像を2倍にして、合成結果に0.5かけたもの。


HDRレンダリングってなんだ?


高輝度抽出画像は最初DXGI_FORMAT_R32G32B32A32_FLOATでやっていたが、いつものDXGI_FORMAT_R8G8B8A8_UNORMでも結果が変わらなかったので戻した。
シェーダの結果として1以上の明るさを設定できるんだろうけど、レンダーターゲットはDXGI_FORMAT_R8G8B8A8_UNORMのままなので、1以上は1扱いでそのまま出力されたのか?
レンダーターゲットもDXGI_FORMAT_R32G32B32A32_FLOATで作ればもっと眩しい感じになるのか?
そもそもそれっぽく見せるために、光源をぼかして範囲を広げて周りに光を漏れさせた絵を用意したけど、そんな事せずに光ってる部分の値を1000とか1万とかにすると、ディスプレイ自体がめちゃくちゃ光ってそういうふうに見せてくれないのかな?






0 件のコメント:

コメントを投稿