凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

結婚式のプロフィールムービーを Unity で作ってみた

はじめに

私事で恐縮ですが、先日、コロナ禍で 2 年半ほど延期していた結婚式をしました。そこでのプロフィールムービー制作を Unity でやってみましたので、本記事ではそのお話をしようと思います。

過去に友人の結婚式のムービー制作を任された時は After Effects か Premiere で作っていたのですが、それぞれ本 1 冊読んだ程度なので、自分の能力的にはスライドショー的に画像や文字を配置する程度が限界でした。自分たちのものはスプラトゥーン風のムービーにしたいなぁと思い、もう少し色々やれるかも & 勉強にもなるかもと思って Unity でやってみることにした次第です。プライバシーの関係でムービーの共有はできないのですが...、部分部分を簡単にご紹介したいと思います。

概要

基本方針は次のような感じです。

  • 全体は Timeline を使って作成
  • 出力は Unity Recorder を使って mp4 化
  • 各表示オブジェクトの表現はシェーダグラフを使って作成(URP)
  • 写真入れ替え・コメント入れ替えは直前まで出来るようにエディタ拡張から自動生成

オープニング部分

こんな感じのスプラトゥーン 2 風のオープニングを作ってみました。

ここからカクカクと自分らの写真が動いて挨拶するシーンが入るのですが、そこは割愛します。シマシマ模様はテクスチャなしでシェーダグラフで作ってみました。黒い縞々はワールド座標系で XY を基準にして作っています。ワールド座標系にしておくとこれを適用したオブジェクトは一体化したみたいな感じになるので、マスクっぽい使い方ができます(滴りのオブジェクト部分にも適用してます)。

UV の X * Y をして斜めのグラデーションを作り、Multiply して数値を大きくしたあと Fraction してあげると縞々になります。Multiply する大きさを制御することで縞々の量もコントロールでき、Add した値も足してあげるとスクロールします。

パキッとさせるために Step したあと、白黒部分それぞれに色を付ければ好きな色の縞々が出来る感じです。ワールド座標ではなくローカル座標や UV 座標を使ってあげれば回転させられる縞々も作れるので、上記 GIF のところではこれららを組み合わせている感じです。

名前紹介部分

こんな感じのにしてみました(実際はインクがあたったところからジワッと出るように調整しましたが、ブログ用に文字を HECOMI に変えた関係で場所が合わなくなってます…)

背景表現

背景の縞々は使いまわしです。その前面にジワーッと垂れてくる背景があります。

ここは全然シェーダグラフでやる必要はないのですが、頭の体操のためにテクスチャなしでシェーダだけで形を作ってみました。縦方向に長さの違う縞々を作成して、端っこ部分は Rounded Rectangle ノードで丸いカーブ部分を作り、足し合わせることによって滴るような形状を作っています。途中で色々パラメタで制御するようにして、これらをタイムラインでキーフレームを打って利用しています。

モヤモヤしているところは Voronoi を加工したものを互い違いにスクロールして足し合わせ、これを Step することでメタボールみたいにモニョモニョする何かができます。

名前

名前はインクに合わせてジワッと出てくるようにしてます。これには次のようなテクスチャを作っています。

RGB チャネルにそれぞれ、

  • G: 文字全体
  • B: 文字がじわっと出てくる順番を表すマスク(青が強いところから G が見えるようになる)
  • R: インクの垂れ表現、G に足し合わせる(赤が強いところから見えるようになる)

といった内容を入れておき、次のようなシェーダグラフを作ってこれらを参照してコントロールします。

B と R に与えるスレッショルドパラメタを作成し、これをパーティクルエフェクトや弾と組み合わせて Timeline 上でキーフレームアニメーションしています。

飛んでくる弾は基本的には4分割のタイルテクスチャをアニメーションさせている感じですが、ちょっと情報量を増やすためにその上で UV にノイズをかけてモニョモニョさせてみました。

その他

シェーダグラフでのアウトライン表現はこちらの記事にまとめています。

tips.hecomi.com

これに加えてアウトライン色も含む全体の色をコントロールできるようにして、屈んだ写真のときに色をジワッと変えてイカスワップしてます。イカはモデル作って普通にアニメーションで動かしてます。

スライドショー部分

作った表現

インク表現

まずインクがピチャピチャと付く表現からです。インク素材はシルエットデザインさんのものをお借りしました。

kage-design.com

これをタイルテクスチャとして読み込めるようにして、こんな感じのジワジワッと広がる表現をシェーダーグラフで作ってみました。

実装としては、円状にグラデーションがかったノイズを multiply して smoothstep をかけているだけですが、インクパターンごとに中心位置が違うので、円状のグラデーション中心もいじれるようにしておきました。

なお、文字も同じようにノイズテクスチャでジワッと出るようにしておきます(画像見づらくてすみません)。やっていることは同じで、ノイズを multiply して smoothstep しているだけです。

これらをタイムライン上で組み立てていきます。飛んでくるインクは単純なタイルテクスチャのアニメーションで表現し(これも連番 index で操作しやすいようにシェーダグラフで適当なシェーダを作っておきます)、飛んでくる感じの軌跡をキーフレームアニメーションで作成、着弾時のパーティクルエフェクトを追加したりすればピチャピチャ感が出ました。

スプラッシュボムもモデルを作成してこちらは普通に爆発アニメーションを作ってそれをタイムライン上で流し爆発する瞬間にインクと差し替えればそれっぽく見えました。

写真の入れ替え

上記のようにいくつかのパターンを Timeline を包含した Prefab として作成しておき、これを親側の Timeline 上に並べるところを自動化してみました。とはいっても、ボタンを押すと 0 から生成するというようなものではなく、少し手抜きして、事前にセットアップされた Timeline に並べられたアイテムをセットアップボタンを押したときにエディタ上で登録された情報をもとに GameObject の差し替え(左右どちら方向に弾を撃つのかボムを爆発させるのかの演出など)、写真・コメント・インクの色の変更を行う形にしています。

Preafab はこんな感じで Timeline を含んでいます。

そしてスライドショーの Timeline はこんな感じで並べておきます。

Prefab のルート要素は Timeline を持っていませんが、Control Track に配置した Control Playable Asset の Control Children をチェックしておくと、子要素に配置した Timeline を制御してくれるようになります。ここに置く GameObject をエディタ拡張のボタンをポチッと押したら置き換えるような仕組みを作ります。

まずはこんな感じでどのようなスライドショーのパターンが有るかの Prefab を登録し...

どのパターンの Prefab を使って、どのテクスチャ・どんなコメントを載せたいかを入力していきます。

最後に Rebuild Timeline を押すと、次のような処理が走ります。

  • まずは Timeline に配置されたクリップを収集してリストを作成
  • リストの中身を時系列に並び替え
  • 次に入力されたデータを見ていって選択した Prefab の GameObject を生成
  • 生成したオブジェクトのテクスチャとコメントを書き換え
  • 対応するクリップの Source Game Object をこれと差し替えていく
void SetupTimeline()
{
    ...
    // playableAsset.outputs を見てクリップを収集していく
    var director = gameObject.GetComponent<PlayableDirector>();
    var asset = director.playableAsset;
    var clips = new List<TimelineClip>();
    foreach (var output in asset.outputs)
    {
        // Picture と名前のついたクリップだけ見る
        if (!output.streamName.Contains("Picture")) continue;

        var track = output.sourceObject as ControlTrack;
        foreach (var clip in track.GetClips())
        {
            clips.Add(clip);
        }
    }
    // 時系列に並び替え
    clips = clips.OrderBy(x => x.start).ToList();

    // 入力された情報を取得
    var generator = target as PicturesGenerator;
    var pictures = generator.pictures;

    // クリップの情報を置き換えていく
    int nc = clips.Count;
    int np = pictures.Count;
    for (int i = 0; i < nc; ++i)
    {
        // ControlPlayableAsset を取得
        var clip = clips[i];
        var playableAsset = clip.asset as ControlPlayableAsset;
        if (playableAsset == null) continue;
        ...
        // 指定された Prefab を選択
        var prefab = generator.prefabs.FirstOrDefault(
            x => x.type == data.type).prefab;
        ...
        // GameObject を生成
        var go = Instantiate(prefab, transform);
        go.SetActive(false);
        // 入力された情報をもとにテクスチャやコメントを書き換え
        var setup = go.GetComponent<PictureTimelineSetup>();
        if (setup)
        {
            setup.Setup(data);
        }

        // ControlPlayableAsset の GameObject を入れ替え
        director.SetReferenceValue(
            playableAsset.sourceGameObject.exposedName, 
            go);
    }
}

このあたりのコード全文はイカになります。

こういったタイムライン要素の書き換えについてはテラシュールブログさんに詳しく書かれています。

tsubakit1.hateblo.jp

映像出力

公式の Unity Recorder を使うと簡単に mp4 が生成できます。

docs.unity3d.com

Timeline 連携も用意されていて、Recorder トラック と Recorder クリップを使って指定した区間を録画・録音することも出来ますが、私は通常のゲーム画面キャプチャで行いました。

おわりに

基本的にはオブジェクトをおいてキーフレームアニメーションをして...の Timeline の操作は他の映像編集ソフトと変わらないので、意外とすんなり動きの部分は作れた気がします。Prefab は Nested Prefab が出来てから簡単に編集が出来るようになりましたし、Timeline はネストしても簡単に編集できるのが良いですね。また、色々こだわりたいところは Unity の知識を活用してアレコレ出来るので、映像制作専門ではない Unity 使いの人は、なにかムービー作成機会があったときの1つの選択肢として結構良いのではないかと思いました。デメリットとしてはちょっとしたプリセットのエフェクト(例えば画像間のトランジションや良い感じの効果など)は当たり前ですが全然ないので、全部自前で作る必要があり、簡単なスライドショーであったら圧倒的に動画編集ソフトのほうが楽かなと思います。ただ、限られたスケジュールの中で切羽詰まってやることで、強制的にシェーダグラフや Timeline 周りのノウハウが溜まるので心に余裕があったらオススメです。