さやちゃんぐbotブログ

シェーダーで遊んだりするブログです。

そもそも色ってなんだろーなーとか思いながらHDRPでカラーグレーディングのシェーダーを描く。

Hoi、さやちゃんぐbotです。
色ってなんでしょうね。世の中の写真や映像を見た時に、なんかいいかんじの色だと感じる時もあれば、いまいちだなーという場合もあります。
音楽などでも同じなのですが、この手の物理と審美的なことが絡む話題は、波動についての話、デジタル処理する時の電気的な特性の話、センサーの話、再生するデバイスの話、規格の話、心理物理学の話、ツールの特性と使い方の話などなど、いろいろなあれこれについてある程度以上知っておく必要があり、なかなか複雑です。
それはともかく、自分が使っているツールでなんとかより良い表現方法に到達したい、より良いものを楽しみたいというのがひとつのゴールではあります。
先日HDRPに触っていた時は、「もうちょっとマシな色あいにしたい」と思いました。ここがスタートです。
さあ、色というものをちょっと調べながら、HDRPのカスタムポストプロセスでカラーグレーディングのシェーダーを書いてみることにしましょう。

HDRPではリッチな絵作りが可能になった反面、ルックに影響するパラメータが多く、それぞれの意味と使い方を把握するまでにハードルがあります。
明るさと色に対して影響の大きいものを書き並べてみましょう。

  • ライトオブジェクトと空のインテンシティ
  • 露出
  • マテリアルのテクスチャとアルベドカラー

これらは光源、カメラ、素材の物理的な特性を数値として地道に設定していくしかありません。
そして、この設定の後にカラーグレーディングを加えることになります。書籍『カラーグレーディング101』によれば、映画の展開のムードや登場人物の心情に応じた色調整を行う処理です。

https://www.borndigital.co.jp/book/18745.html

 

HDRPのポストプロセッシングには、カラーグレーディングを行うためにColor AdjustmentsとWhite Balanceという機能があります。

f:id:sayachang_bot:20201108160101p:plain

おそらくは、これで大体の調整はできるハズです。色温度が変更できるし、露出、コントラスト、色相、彩度と一通りのパラメータに手を入れることができ、さらにカラーフィルターで追加の色を加えることすらできます。
ところが、これがやってみるとなかなか難しい。明るすぎたり暗すぎたり、あるいは少し変更するだけで青か黄色か緑が強くなりすぎて、どう変えればいいのかも戻し方もわからなくなってしまうということがしばしば起きます。これは手を動かす前に何か調べ物をするのが良さそうです。
でも、いったい何を調べればいいの?

 

ここでひとつのヒントに出会いました。AfterEffectやPhotoshopには「自然な彩度」という機能があります。ポスプロには彩度を調整する機能がありますが、さらに「自然」という形容詞が付け加えられています。もしかしたら、ここに何か秘密があるのかもしれません。

とにかく、実装と調べ物を進めていきましょう。まずは単純に彩度を変更するシェーダーを描いてみます。これにはHDRPのCustom Passを利用し、ポスプロシェーダーを描きます。
HSVのSが彩度です。SはSaturationですが、Chromaと呼ぶこともあります。彩度を上げるというのは、クロマ値を大きくすることで実現できます。
そうとわかれば、今知っている知識と持っているコードスニペットを組み合わせれば実装できそうです。
RGBからHSV変換し、Sの値を変更してからRGBに戻すのです。
シェーダーでHLSLを書いてみましょう。RGBとHSVを変換する関数はググるといくつか見つかるので、そのまま流用します。
さて、クロマを増やしてみます。

float3 hsv = rgb2hsv(col);
hsv.y *= 2.0;
col = hdv2rgb(hsv);

f:id:sayachang_bot:20201108160425p:plain

f:id:sayachang_bot:20201108160458p:plain

2倍するというおおざっぱな指定では、全体の色あいが崩れてしまいます。もう少しこれを調整できるロジックが必要そうです。
また試しに逆にクロマを減らし、ゼロにしてみます。

f:id:sayachang_bot:20201108160554p:plain

グレーになりました。RGBとHSVを変換する関数を読むと、白に対して線形補完しているので確かにこんなかんじになりそうです。また、この動きはツールでカラーグレーディングをいじっている時にもまれに良く見る色あいです。

もっとマシにできるのでしょうか。世の中には「自然な彩度」という機能が出回っているので、何かやり方があるハズです。もしかしたら、英語で書かれた説明や実装が見つかるかもしれません。
ここで「自然な彩度」でググってみると、どうやら英語ではvibranceと表現するようです。さらに、GLSLで公開された実装も見つかりました。
これを参考に、HLSLを書いてHDRPで使えるようにしてみます。

vibrance.HLSL

float3 vibrance(float3 col) {
float amount = _VibranceAmount;

float lum = bt601Lum(col);
float3 mask = (col - lum.xxx);
mask = clamp(mask, 0.0, 1.0);
float lumMask = bt601Lum(mask);
return lerp(lum.xxx, col, 1.0 + amount * (1.0 - lumMask));
}

白ではなく、輝度の値を使った灰色を使って線形補完しています。また、輝度を元にマスクの値を用意していて、これでより鮮やかさが制御できるかもしれません。もう少し調整できるよう、外からパラメータを与えられるようにしてみました。
※輝度については、下に補足を記載しておきます

f:id:sayachang_bot:20201108160731p:plain

f:id:sayachang_bot:20201108160801p:plain

クロマだけを変更するより、だいぶ調整がやりやすくなりました。灰色になることもなく、あまりにも色が変わり過ぎることもないようです。また、自然な彩度という機能の特徴である、青成分が特に鮮やかさを得るということも確認できています。

これらふたつを組み合わせ、いいかんじにパラメータを整えればなんとか使い物になるのではないでしょうか。
また、先ほどのHSVでの彩度調整機能には、Value値の変更、一定範囲でクロマ値のクランプを追加します。

f:id:sayachang_bot:20201108160847p:plain

f:id:sayachang_bot:20201108160916p:plain

元の画像から受けるくすんだ印象が緩和され、青みがより鮮やかになり、肌色は生気を得ました。
また、微調整で陰の濃さもある程度までは変更できるようです。

このシェーダーはGitHubに置いてありますので、良ければお試しください。

github.com

 

いかがでしょうか。
色を調整するカラーグレーディングシェーダーを自作することの可能性が見えたのではないでしょうか。
今回はHDRP固有の話ではありませんが、この記事が色について知見を得る一助となりましたら幸いです。

ではでは、良いHDRPライフを。

 

おまけの補足

輝度(ルミナンス)については、グレースケールについての素晴らしい記事がありますので、ぜひ読んでください。

qiita.com

 

CEDEC+KYUSHU 2017での川瀬さんの講演資料もとても良い資料です。

実践的なHDR出力対応 ~レンダリングパイプラインの構築~

https://www.siliconstudio.co.jp/rd/presentations/files/CEDEC_KYUSHU2017/cedec_kyushu_2017_hdr_kawase.pdf