3Dの周辺やバーチャルライブの開発を担当

山口智也氏(以下、山口):「Unity Shader Breakdown」という題で、株式会社Colorful Paletteの山口が発表します。よろしくお願いします。

始めに自己紹介をさせてください。山口智也と申します。株式会社Colorful Paletteで『プロジェクトセカイ カラフルステージ! feat. 初音ミク』というゲームの開発チームに所属しています。

職種は、Unityやグラフィックス周りを見ているエンジニアで、現在は3Dのミュージックビデオなど、3Dの周辺やバーチャルライブの開発を担当しています。経歴は、2020年4月に株式会社サイバーエージェントに新卒入社をして、その後株式会社Colorful Paletteに配属となりました。

こういうIDでTwitterやGitHubをやっているので、気になる方はぜひ見てもらえればと思います。

絵に空気感を出すための4つのポストエフェクト

今回のLT(ライトニングトーク)は、Unityでのシェーダ実装に興味がある人と、ゲーム制作で独自の絵作りをしたい人をターゲットにしています。発表のアジェンダは、まず概要を話してから、その後いくつかのシェーダの解説に入って、最後まとめというかたちで締めたいと思っています。よろしくお願いします。

それではさっそく概要です。まずスライドの題の部分、Breakdownは何かというところです。これは映像やVFXの界隈でよく言われているメイキング映像の通称みたいなものです。「Youtube」で「VFX Breakdown」と検索するとよく出てきます。

今回の発表では、エフェクトがかかっていない状態のUnityの絵から、エフェクトを盛っていくというかたちで、シェーダの解説をしたいと思っています。

さっそくですが、今回の解説は、こういう教室の中でUnityちゃんが立っている絵を作ることを最終目標として進めていきます。

具体的には、左側の上の絵が何もエフェクトがかかっていない状態で、下が今回解説する4つの全エフェクトを適用したものです。今回はこの上の絵から、下の絵を作ることを目標に解説をしていきます。

今回解説するポストエフェクトは4つあって、画面の空気感を出すためのポストエフェクトを中心に解説していこうと思っています。

絵に立体的な奥行き感を出す「深度フォグ」

それではシェーダの解説に入っていきます。1つ目は、深度フォグです。このエフェクトは、画面の深度、depthですね、深度を元に指定した色にフェードさせるエフェクトとなっています。これは画面全体の色味や、立体的な奥行きを出すのに有効だと思っています。

今回はユニバーサルレンダーパイプラインというものを使って、サンプルを作成しています。ユニバーサルレンダーパイプラインでは、Render Pipeline Asset、Depth Textureというフラグをtrueにすると、内部でシェーダに渡す用の専用Depth Textureのdepthの書き込みが行われて、それがシェーダに渡されてポストエフェクトに使われるという流れになるので、今回はそれを前提にして作成していきます。

通常のUnityでは、デフォルトが灰色で、単色へ変化させるフォグはあると思うのですが、そことの違いとして、今回はランプテクスチャというものを使って、距離によるフォグの強さや色を自由に制御できるように実装しています。

通常の、単色に対して変化していくフォグではなくて、例えば手前側にかかる色を青にして、奥側にかかる色を赤にするみたいな、そういうところでランプテクスチャを使うことで、かなり自由度が上がるのではないかなと思っています。

このランプテクスチャは、けっこうToonシェーダとかでも使う、色の変化を表すテクスチャになっていると思っていて、UnityのSerializedFieldで、Gradientを作成できると思うのですが、そのGradientから指定したサイズのランプテクスチャを生成する拡張を作成して、今回は対応しました。今回は128×1です。

絵の雰囲気を向上させる「フレア」と「パラ」

次のエフェクトは、フレアとパラというエフェクトです。こちらは、いわゆるアニメの撮影処理でよく用いられるもので、画面全体に、明暗のグラデーションをかける処理になっています。

このエフェクトの効果は、ちょっと曖昧な表現になってしまいますが、雰囲気の向上に効果的かなと思っています。フレアが薄く明るくする光で、パラが暗くする影と思ってもらって大丈夫です。

今回下に出しているサンプルは、左上にふわっとフレアがかかっていて、右下に暗くパラがかかっているような絵になっています。

外側にフェードしていく遠景の範囲の指定と、指定されるフレアによって加算される色の指定をできるように、フレアとパラそれぞれに実装しています。

フレアは画面を明るくしたいので、Unityちゃんの元のカラーに対して加算します。パラは乗算をして、画面に対して暗くしますが、その色に対して乗算されるので、暗くなっていくというところで、そういうブレンドをしています。

ここで『プロセカ(プロジェクトセカイ)』の例コーナー、みたいなかたちで作ってみました。『プロジェクトセカイ』でも、これに近いフレアやパラ表現が実装されています。

今回の例だと『ワーワーワールド』という楽曲のミュージックビデオの1場面です。こちらの絵は、画面の上部から下方向に、大きい薄紫色のフレアがかかっているようになっています。『プロジェクトセカイ』でもこういうところで使用しています。

絵を柔らかくふんわりとした雰囲気にする「ディフュージョン」

次のエフェクトです。ディフュージョンというエフェクトは、画面全体の光の拡散の表現に使っています。こちらもアニメとかイラストとかの表現でよく使われるものかなと思います。

これを使うことの効果は、ちょっとまた曖昧な表現にはなってしまうのですが、全体の絵が柔らかいふんわりとした雰囲気になったり、ちょっとコントラスト感が出る効果があるかなと思っています。

実装は、まず元のポストエフェクト適用前のカラーを、解像度を落としたバッファである縮小バッファにコピーをして、その縮小バッファに対してコントラストの調整をかけます。下の絵がわかりやすいのですが、明るい色と暗い色でだいぶ差が出たかなと思います。

コントラストを調整した縮小バッファに対して、今回は単純なガウシアンブラーを適用しました。実際ガウシアンブラーを適用したのが左下の絵です。ガウシアンブラーを適用してぼかした絵を、元の解像度のカラーにブレンドして、合成をして、ふわっとブラーを乗っけるかたちになっています。

今回スクリーン合成というところで、明るくするスクリーン合成を使ったのですが、合成の仕方で見た目もかなり変わってきます。気になる方は例えば加算や、アルファブレンドなど、いろいろな加算や合成の方法があるので、試してもらえるといいかなと思います。

引き続き『プロセカ』の例コーナーです。『プロジェクトセカイ』で使用している例として、こちらは『ウミユリ海底譚』という楽曲の1場面です。ここではディフュージョンと、被写界深度での背景ぼかしを併用することで、全体がふわっとした雰囲気になっていると思います。

光が差し込むエフェクト「ゴッドレイ」

それでは最後、ゴッドレイというエフェクトを説明していこうと思います。ゴッドレイは、けっこうコンシューマーゲームや3Dのゲームでよく見る表現かなと思います。光が差し込んでいるような、いわゆるVolumetric Lighting的な表現になっています。

今回実装は、URP(Universal Render Pipeline)標準のディレクショナルライトで生成されるデプシャドウで生成されるShadow Mapを使ったRaymarchingを実現しています。

今回は、Raymarchingについての細かい説明は省かせてもらうのですが、こういう方針で実装しています。

実装の手法は、画面の各ピクセルからレイを飛ばして、一定間隔でさっきのShadow Mapのサンプリングを行います。一定間隔でサンプリングするというところで、サンプリング間隔ごとに光が遮蔽されてないポイント、つまりShadow Mapのdepthで遮蔽されてる点が取れると思うのですが、遮蔽がされていないポイントで適当な係数をかけつつ、アルファ値を加算していきます。

例えばこのキャラクターで遮蔽されているところはアルファ値が加算されなくて、遮蔽されていないところはアルファ値が加算されてるので、こういう光のレイに沿った光線が出来上がるという流れです。

こちらのゴッドレイですが、単純な処理をしてしまうと、各ピクセルごとにレイを飛ばして、かつ、そのレイのサンプル数の数でいわゆるShadow Mapのフェッチが走るので、処理負荷が非常に高いです。

何も工夫をしないと、サンプル数を上げれば上げるほど品質が上がってしまうので、いくつか工夫を行っています。

今回は、各ピクセルごとに深度テクスチャのサンプリングを行って、この深度テクスチャはShadow Mapではなくて、画面の通常の深度テクスチャのサンプリングを行いました。

右のサンプリングポイントがそのピクセルに対応する深度を超えたら、そのサンプリングを停止するという処理を行ってます。オブジェクトの後ろの点でサンプリングを行うのは非常に無駄なので、そこで停止をして、そこの無駄を削減しています。

もう1点、負荷軽減のためにループ数を減らすと、上の画像のようなカクカクした粗さが見えてしまうという問題がありました。サンプリング数を増やすと滑らかになって、品質が上がるのですが、そのサンプリング数を減らした時の粗さを軽減するために、サンプリングの開始位置を、擬似乱数を使ってピクセルごとにずらしています。

これをやることで、ピクセルごとに各ピクセルでサンプリング位置にバラつきが出るので、ステップ感をごまかすことができます。

乱数を使ってずらすという工夫としてもう1点、擬似乱数の生成に用いるseed値を、経過する時間で変動させることで、時間方向でサンプリングして、実際サンプリングされる位置を増やして、ある程度、粗さは減らせるのかなと思っています。

ただ、実際に使用する場合を考えた時には、どうしても乱数やノイズを使うと、ノイズ感が出てしまうので、実際に使用する場合は、何かしらのブラー処理などでノイズ感を低減する工夫が必要になるかなと思います。

モバイルゲームでゴッドレイを使う時は、先ほどの乱数を使ったサンプリング数のテンポラルフィードバック的な手法と、ブラーでのぼかしの兼ね合いで処理負荷を削る方針でやっていくかなと個人的には思っています。

全エフェクトの紹介が終わったので、最後まとめとします。

エフェクトを使って空気感のある絵が完成

まず、ベースのテクスチャに対してゴッドレイをかけて、差し込む光源を表現します。

深度フォグによって、空間の色味や奥行き感の向上を行います。

次にディフュージョンで全体の雰囲気感を上げて、かつ、オブジェクト間のブラーを合成してオブジェクト同士の境界がぼけることで、よりふわっとした絵になります。個人的には、このエフェクトがかなりリッチな雰囲気の向上に役立っているのかなと思います。

最後にフレアとパラで、全体の絵のまとまりや、光源が意識される絵になるのかなと思っています。

今回使ったエフェクトはこれで全部完了で、改めてベースのテクスチャを見てみます。ベースの絵に対して、空気感のある絵にできました。

今回の場合、わずか4つですね。4つのポストエフェクトの追加で、空気感を演出できました。今回はURPで実装したのですが、標準のポストプロセッシングスタック、ボリュームのブルーム、被写界深度などのポストエフェクトを併用して作ることもできると思うので、いいかなと思います。

今回は、少し複雑なロジックも含みつつ、比較的シェーダ初心者向けのLTだったのですが、少しのシェーダ実装でゲームなどの絵作りにかなり自由度が生まれると思うので、ぜひ挑戦してもらいたいなと思っています。

最後に、今回の実装のサンプルは、こちらのレポジトリに含まれるので、気になる方はぜひ見てもらえればと思います。URLをすぐ覚えるのは難しいと思うので、私のIDだけ覚えてもらって、ここから飛んでもらえればいいかなと思います。

それでは今回の発表は以上となります。ありがとうございました。

司会者:ありがとうございます。それでは質問いくつか拾っていきたいと思います。 1つ目、この発表の表現は、URPじゃないと再現できないものでしょうか、という質問がありました。

山口:今回使っているシェーダ表現は、わりと一般的なシェーダやグラフィックスの処理で行っているので、ビルトインのRender Pipelineとかでも深度テクスチャを書き込む処理を行えば、だいたい再現はできるかなと思っています。

とはいえ、今回サンプルはURPで作成しているので、そちら見ていただく場合は、URPを使ってもらうのがわかりやすいかなと思います。

司会者:ありがとうございます。次に、『プロセカ』ではRaymarching volumeは入っているんでしょうか、負荷が気になります、という質問がありました。

山口:結論から言うと、現在のミュージックビデオや『プロセカ』のCDにはこの表現は入っていません。モバイルでの負荷も個人的には検証したいと思っているのですが、プロダクトで検証した負荷については今回は持っていないです。

司会者:次に、これはゴッドレイのとこかな。時間をseedにした時に、チラつきなどは発生しないのでしょうか、という質問がありました。

山口:チラつきなどは、発生はします。発生自体はするのですが、ピクセル単位のチラつきになるので、画面全体のチラつきにはなりづらいかなと思っています。

とはいえ、どうしても時間で乱数変化させた時のノイズ感やピクセルごとのチラつきは解像度によっては出てしまうので、それを低減する工夫も、実際入れるとなったら必要なのかなと思っています。

司会者:最後に、テンポラルなアプローチだと認識したのですが、カメラが動いた時のゴースティングの対策などはされているのでしょうか、という質問がありました。

山口:ありがとうございます。今回のゴッドレイのノイズの処理だと、ゴースティングは発生しないと思っています。というのは、前フレームの情報を使ってノイズの生成をしていないので、今回はゴースティングは起きないかなと認識しています。

司会者:ありがとうございます。