2018の12日目の記事です。2018(以下、TDF)に参加しました。TDFは、日本国内で唯一のデモパーティです。デモに関心のある人々が一堂に会してコンペティションを行ったり、技術を共有したりといったイベントをデモパーティと呼びます。サウンド:sadakkey)という作品を発表しました。Compoにて、本作品が1位に選ばれました!この記事では『WORMHOLE』の映像制作技術について解説します。ソースコードを公開していますので、ご興味のある方はそちらもご確認いただければと思います(スターください!)。https://github.com/gam0022/unity-demosceneサウンド編についてはさだきちさんが解説されています。不思議な球体がワームホールを介して非現実なデジタル空間と水平線の広がる自然空間を行き来する映像を制作しました。不思議な球体がトンネルを進んでいくと、周囲を明滅する光がだんだんとモノクロからカラフルに変わっていきます。トンネルの最奥にあるワームホールへ近づくほど明滅はだんだんと激しくなっていき、ホワイトアウトとともにワームホールを越えると、球体は海上に出現します。その後、球体はじわじわと歪んでいき、戦闘機へと形を変えます。変形中の不思議な球体の上には、私が尊敬するデモシーナーの名前を表示しました。これはグリーティングと呼ばれるデモシーンにおける慣習です。戦闘機はパーティクルを放ちながら海上を進み、パーティクルが一瞬だけTDFのロゴを形作ります。戦闘機は元の球体に変形し、突如現れたワームホールに吸い込まれるようにして冒頭のトンネルのシーンに戻っていきます。実装ならびに制作にはUnityを利用しました。2018.2の新機能も活用しています。レンダリング映像の大部分はレイマーチングで描画し、パーティクルやグリーティングのテキストなどのレイマーチングが苦手とする部分はラスタライザで描画するというハイブリッドなレンダリング方式を採用しました。今回は制作期間が短かったため、レイマーチングのシェーディングにはUnity標準のディファードレンダリングを利用することにしました。ディファードレンダリングにすることで、Gバッファの書き込みまでを実装すれば、それ以降のライティングの処理をUnityの標準のディファードレンダリングのシェーダーに任せることができます。簡単に言ってしまえば、Unityでサポートされる全種類のライトやGI機能に対応するライティング処理をあえて自分で実装しなくて済むという、工数削減のメリットがあります。@hecomiさんのuRaymarchingを利用させていただきました。uRaymarchingは距離関数とGバッファに値を書き込む部分を実装すれば、簡単にレイマーチングができる便利なシェーダーテンプレートです。他にも、鏡面反射による周囲の映り込みに、Unity標準のReflectionProbeを配置して実現しています。毎フレームCubemapを生成するくらいならレイトレで反射を計算したほうが速いと思っていたが、この例ならCubemapの解像度は16x16でも十分だし、Cubemapの方がポリゴンとの混在が容易なので、現実的な方法だと思う。Quadの実装方法について紹介します。スクリプトによる制御は最小限にしてEditorモードの挙動を安定させたかったので、別のアプローチをとってみました。Cullingを無効にしたQuadを静的生成しました。これによって時々レイマーチング部分が動かないトラブルを回避できました。時間によって切り替わる表現のためには、MeshRendererのenableの切り替えで制御できる単純な仕組みの方が好都合でした。Unityで画面全体にレイマーチングをさせる最高のソリューションができた!CommandBufferを使う方法だとEditMode等の考慮が大変。Cullingされて困る。そこで、BoudingBoxを拡張したQuadを事前生成して通常のMeshRendererで描画できるようにした。spongeという有名なフラクタル図形をベースにしています。回転のfoldのテクニックを利用して万華鏡のように見せたり、modをつかった図形の繰り返しのテクニックを適用しました。回転のfoldは次の記事で紹介しています。gam0022.net上の4種類の画像はいずれも同じ距離関数によるトンネルの様子です。パラメータを変化させることで形状や色などを演出に合わせて変更できるようにしました。海面のモデリング海面は平面として衝突判定を行い、ノーマルマップだけで波が立っているように見せています。gam0022.net』と同じアプローチの軽量化方法です。ところで、上記の記事の作品と異なり、本作品ではLODを一切行っておりません。マーチングループ中でテクスチャのフェッチをするとUnityのシェーダーのコンパイルが激重になる現象を回避するためです。海面の質感は、Gバッファに書き込むパラメータの調整だけで再現しました。ディファードレンダリングなので不透明オブジェクトとして当然ライティングされているのですが、どことなく海中を感じさせるような半透明の質感を擬似的に再現できたのではないかと思います。戦闘機のモデリング戦闘機は距離関数でモデリングしました。3つのBoxの大きさをcos/sin/abs等で調整しつつ、smoothminによるメタボールでBoxを融合することで、流線形のSFっぽい戦闘機をモデリングしました。Raymarchingを行いました。Quadを使わずに戦闘機と同じ大きさのSphereを配置し、Sphereのシェーダーでレイマーチングをしています。上記の画像を拡大するとSphereのワイヤーフレームを確認できます。演出の実装TextMeshProによるフォントのレンダリングフォントはプロシージャルではなくテクスチャを使用しています。fontのデータからSDFのフォントのアトラステクスチャを生成しました。生成したアトラステクスチャはTextMeshProのシェーダーでレンダリングしています。次のような簡単な文字の出現と消滅のエフェクトを、TextMeshProの標準シェーダーの一部を改造して実装しました。2018の19日目の記事で行いました。Trackと書きます)。Trackの実装はそれなりに工数がかかります。クリップのパラメータを1つでも増やすと複数箇所に変更が発生します。Trackでは実現できないのかを事前に確認することをおすすめします。Trackを利用する方針としました。パーティクルパーティクルはUnityのParticleSystemを利用しました。次の画像はポストエフェクトとSkyboxをOFFにした状態でパーティクルをワイヤーフレーム表示したものです。パーティクルの形状は5種類でしたが、パーティクル用のモデルは1種類しか用意しませんでした。四角形のQuadをフラグメントシェーダーでdiscardして形状を変化させました。すべてのパーティクルを1マテリアルで表現できるので、全パーティクルを1ドローコールで描画できました。Streamsを用いてランダム値をシェーダーに渡し、シェーダーで形状の切り替えを行いました。Raymarchingの仕組みを利用しました。Houdiniでワームホールの八角形のポリゴンメッシュを作成しました。Raymarchingを行えば、別の世界と繋がる演出ができます。ところが、カメラの原点からレイを進めると、別世界が3Dの立体映像のように飛び出してしまうという罠にハマってしまいました。この問題はレイを物体の表面から進めることで回避できました。UnityのディファードレンダリングではStencilの利用が制限されていました。レンダリングパスでレンダリングするオブジェクトのためのステンシル機能はいくらか制限されます。つのステージの間、シェーダーで定義されるステンシルステートは無視され、最終的なパスの間に考慮されるだけです。そこで、DepthテストとRenderQueueによる制御でStencilを代用しました。ReflectionProbeの映り込みによる演出2回目のワームホール出現時(2:05〜)に海面が黒く侵食されていく演出があります。これは、ワームホールの向こう側の景色がReflectionProbeに映り込み、Unityのライティング機能によって自動的に水面に反映された結果です。意図的に演出したものではなく偶然の産物でしたが、気に入ったのでこのまま採用しました。揺らぎ揺らぎは2箇所で利用しました。単純でコストもかからない工夫ですが、効果は大きいと感じました。カメラにfbmノイズを加えて手ブレ感を出すことで臨場感が生まれました。それから、戦闘機をcos波で振り子のように左右に揺らしています。戦闘機の動き自体はZ軸に直進するだけなのですが、機体の揺れとカメラワークによって旋回しているような雰囲気が出ているのではないでしょうか。音楽との同期方法ビート単位でのシェーダー制御シェーダーの入力をビートにし、演出を「ビート単位」で制御することで、映像と音楽を同期させました。時間単位(秒単位)で制御するよりも、BPM変更に柔軟に対応できるというメリットがあります。音楽に合わせてTimelineのクリップを手動で配置する必要がありました。こちらは音楽を120BPMで制作していただいたことで、かなり楽に解決できました。120BPMでは、1ビートが0.5秒となります。4分の4拍子であれば1小節の長さが2秒となるため、カメラのカット切り替えを2秒単位にすると音楽と映像が自然に同期します。同様に、4分の3拍子であればカット切り替えを1.5秒単位にすればよいわけです。パーティクルは、エミット間隔を0.5秒ごとに設定することで音楽とタイミングを合わせています。次はライティングに凝ってみたいです。非現実的なレンダリング(NPR)には対応できないので、ディファードレンダリングのライティングパスの独自実装などを調査したいです。Pipeline(HDRP)とレイマーチングを組み合わせる検証などもしてみたいです。おわりに『WORMHOLE』の映像を作るための取り組みや手法について技術的な視点で解説しました。上記の通り、『WORMHOLE』の制作にはUnityの機能やライブラリを多く利用しています。巨人の肩の上に立つことで表現の部分に注力でき、3週間弱という短い制作期間の中で完成度の高い作品に仕上げることができました。いえ、制作期間中は『WORMHOLE』を受け入れてもらえないのではと常に不安を感じていました。デモシーンの世界ではゲームエンジンの機能に頼らない高度な実装力こそ評価されると思っていたからです。そんな予想に反し、Unityで作成したデモ作品を高く評価していただけて大変光栄です。Unityには初心者~上級者まで様々なレベルの方を対象とした資料や教材があります。『WORMHOLE』では使用しませんでしたが、たくさんのアセットも用意されています。デモシーンに興味はあるもののハードルが高そうで踏みとどまっている方や、レンダリング技術の学習に挫折してしまった方に、Unityでもデモ作品を作成できることをお伝えしたいです。日頃の業務でUnityを利用している方に、自分でも作れそうな身近なものとしてデモシーンに興味を持ってもらえれば嬉しいです。『WORMHOLE』が新たなデモシーナーを生み出すきっかけとなれば幸いです。最後に、素晴らしいサウンドを生み出してくれたさだきちさんに感謝申し上げます。チームでTDFに参加するのは今回が初めてでしたが、非常に良い経験をさせてもらいました。『WORMHOLE』を高画質で見るには下記の実行ファイルか動画ファイルをダウンロードしていただくと、エンコード前の綺麗な画質でご覧いただけます。Windowsの実行ファイル(GTX1070以上のGPU推奨)動画ファイル(ブラウザ上だとエンコードされた状態で再生されるのでダウンロードしてください)『WORMHOLE』の感想をお待ちしております!pouet.netという世界中のデモ情報を集めたポータルサイトに作品を公開しました。pouet.net内の『WORMHOLE』のページ作品の感想をYouTubeやpouet.netでいただけると泣いて喜びます。『WORMHOLE』を高画質で見るには『WORMHOLE』の感想をお待ちしております!。