Quartz を使用したプロシージャルな音楽の生成

Adam Block、Paul Oakley、Marcel Swanepoel
通常、プレイヤーがシーズンの合間にフォートナイトにログインすると、新しいシーズンが始まるまでのプレースホルダーとして機能する静止画面が表示されます。チャプター 3 シーズン 3 を開始するにあたり、フォートナイト チームでは何か違うことをしたいと考えました。

そこでチームは、Unreal Engine の主要機能をいくつか活用し、新しいシーズンのビジュアル要素があふれる豊かで没入感のあるシーンを作成しました。

そのとき、サンプル アキュレートなオーディオ再生を可能にするエンジン内のネイティブ サブシステム、Quartz と同期させたのです。プロシージャルに生成された音楽パートは、視覚効果と連動してどちらも Quartz クロックに「サブスクライブ」され、見事な発光生物の森が音楽と完全に同期して脈打ちました。

フォートナイトのシーズン開始イベントで、このような試みが行われたのは初めてです。この記事では、プロジェクトに携わった Epic のデザイナーやアーティストから、この成果を達成した方法について話を聞きました。
 

ダウンタイム画面のビデオ ゲーム オーディオ

こんにちは!Adam Block です。Epic Games で技術サウンド デザイナーをしています。この技術ブログでは、チームや私が Quartz という Unreal Engine のサブシステムを使用してフォートナイトに適用した最近の実装について、いくつかのアイディアを共有したり、説明したりします。これを読んだ後は、Quartz とは何か、またその機能についてより理解し、プロジェクトに Quartz を取り込むきっかけとなることを願っています。この非常にすばらしい機能について学習する時間を割いていただき、ありがとうございます。

Quartz とは

Quartz は Unreal Engine 内にあるサブシステムです。これにより、オーディオ バッファ間であっても正確な (サンプル アキュレートな) 瞬間にイベントが発生するようにスケジューリングされます。音楽コンテキストで Quartz を使用する場合は、オーケストラの前に立つ指揮者の役割を担っていると考えることができます。指揮者の右手は指揮棒を一定の形で揺らしてすべてのプレイヤーが守るべきテンポを維持しながら、さまざまなセクションのミュージシャンが自分たちのパートを演奏できるように、ところどころで左手を適格な瞬間に伸ばして合図を送ります。

Quartz では、サンプル アキュレートなオーディオ再生が可能になり、オーディオ エンジンでは、イベントが PFX やその他のゲームプレイ イベントのゲーム スレッドに戻るために必要な時間を十分に取ることができます。なかなかクールですよね?「Play Quantized」イベントを行う Quartz では、.wav、サウンド キュー、MetaSound、またはオーディオ コンポーネントを含む、いかなる uSoundbase オブジェクトも使用することができます。

Quantized Playback イベントが発生するその瞬間に、パーティクル エフェクトのバースト、ライトの点灯などをトリガーできます。Quartz サブシステム内で、曲のテンポと拍子に関連する特定の「量子化境界線」をいくつでも定義することができます (たとえば、4 小節ごとにこれを行ったり、8 小節ごとの 2 拍目でこれを行います)。

Quartz は音楽関係のアイディアにとってすばらしい選択である一方、音楽以外のコンテキストにも適しています。実際に、フォートナイトのいくつかの武器には、非常に高速で正確な武器の発砲音をトリガーするために Quartz が使用されています。Quartz クロックを使用してサブマシンガンの発砲音を、武器の発砲が毎分 110 拍のクロックの 32 音符ごとに実行されるようにスケジューリングする場面を想像してください。おそらくパーティクル エフェクトはその Quartz クロックをサブスクライブし、発砲されるたびに正確にパーティクル エフェクトをスポーンすることができるでしょう。Quartz がないと、ビデオ フレーム レートにバインドされるため、高速な発砲に一貫性がなくなり、「ギャロップ」のように一瞬無音になる可能性があります。

プロシージャルな音楽

フォートナイトでは、新シーズンが始まる前におおよそ 10 時間の「ダウンタイム」期間がありますが、それに対してカスタマイズされた音楽のリクエストがありました。これが、Quartz を使用して印象的な音楽パターンや繰り返しのループが認識されない、プロシージャルに生成された (ループしない) リスニング エクスペリエンスを作成するよい機会となったのです。通常、同じコンテンツを何度も繰り返して聞いていると飽きたり疲れたりしやすいものですが、このアプローチでは、音楽フレーズの小さな「チャンク」を集めてシャッフルし、実行時に再生するバリエーションをランダムに選択しました。

このロジックを処理する音楽コントローラーは、ブループリント で構築しました。簡単に言うと、曲のプレイリストをシャッフルし、ランダムに曲を選択します。曲が選択されると、すべての音楽的な「枝」(ベース、ドラム、メロディー、パーカッション、和音など) が「現在の曲」として参照され、ブループリント ロジックは (Quartz サブシステムを使用して) 何をいつ再生するかを指示するだけです。

Quartz の大きなメリットの 1 つを挙げるとすると、これは Unreal Engine のサブシステムであるため、開発チームの誰もが私の Quartz クロック (たとえば、「Song 1」、「Song 2」など) をサブスクライブして、現在再生しているトラックの小節と拍をすべて取得できることです。小節や拍を取得したメンバーは、音楽と完璧にマッチするものであれば何でも自由に制作することができます。

今回の場合は、他のチームでもわかるように非常にシンプルにして、小節、拍、その他の分割要素のデリゲートを Quartz クロックから呼び出しただけです。これらのデリゲートには、FX チームがビジュアル変更を行うために使用するイベントがバインドされていました。それらをご紹介します。

プライマリ データ アセット — 曲固有の情報

それぞれの曲が独自のプライマリ データ アセットでした。これらのデータ アセットには、トラックに関するありとあらゆる情報が含まれています。トラック名 (この変数を「クロック名」と読んでいました)、テンポ、小節単位での曲の長さ (このトラックが終了してプレイリストがシャッフルされるまで、どれくらいプロシージャルに再生するか)、各レイヤーの小節と拍 (たとえば、ベース ラインは 8 小節のフレーズで最後は 4 拍、メロディは 4 小節のフレーズで最後は 4 拍)、それぞれの音楽的な枝 (レイヤー) のすべての uSoundBase アセットが、トラックのデータ アセットに含まれています。

概念的には、DJ デッキのような「A」と「B」があるアプローチにしました。すべてのパートが「A」デッキで再生を開始し (つまり、メロディ A)、そのパートが終了すると、別のパートがランダムに選択されて「B」デッキで再生されます。この動作を考えながらオーディオ コンポーネントを使用したわけではありませんが、フレーズを入れ替えてコール アンド レスポンスのシステムを目指すアイディアは当時、状況に合っているように見えました。

「A」というメロディ、和音パート、ドラム フレーズ、ベース ライン、パーカッション パートの配列があり、「B」という対応するアセットの配列にすべて切り替わって選択が行われます。このシステムは、基本的にプロシージャルに生成されるコール アンド レスポンスのアプローチです。データ アセットはこれらのアセット、および各レイヤーの持続時間を定義するパラメータと設定を保持しているだけで、Quartz クロックを保持する音楽コントローラーが、いつ再生する新しいレイヤーを探してシャッフルし、キューするのかを把握しています。

BeginPlay

このプロセスが機能する方法について、きちんと説明しましょう。最初にサウンド ミックスをプッシュし、残りのメニュー音楽がある場合や特別な問題が発生する可能性がある場合、他の音楽の音を下げたり、聞こえなくしたりしています。また、ビジュアルがクールでローファイな湿地帯を表現しているため、じめじめとした雰囲気でループする環境音は大きくしています。15 秒間再生すると、その雰囲気のサウンドは 30 秒間フェードアウトします。レコードをかけるように針を落とすサウンド エフェクトを再生すると (当然、テーマは「ローファイ」ですから)、また音楽の設定と再生を開始します。

Shuffle data assets

この関数では、DataAsset 配列を取得してシャッフルし、1 つを CurrentDataAsset として設定します。その DataAsset から BPM を取得して Next BPM 変数に設定し、IntroComplete ブールを「false」に設定します。これは、新しい曲を初めて再生するからです。

Set song duration

ここから先は、すべてのロジックは「Current Data Asset」変数からプルされます。たとえば、この次の関数では、曲の長さ (小節数) を取得して「Current Song Duration」という名前の変数に設定します。このようにして、音楽コントローラーでは曲のプレイリストを再シャッフルして別の曲を選択するタイミングを認識します (Quartz が小節の数を数えています)。

Does clock exist

ツールで初めてロジックを実行するときに、すでにクロックが存在しているかどうかを確認します (たとえば、「Track02」というトラック名で行います)。この場合は存在しないため、クロックに Quartz の量子化境界をいくつか設定する必要があります。また、新しいクロックも作成し、現在の曲の名前などの好きな名前を付けます。

Create and cache Quantization Boundaries

この関数では、必要になる Quartz の量子化境界をそれぞれ作成してキャッシュします。たとえば、再生をスケジュールする場合に「every four bars (4 小節ごと)」、「next bar (次の小節)」、「Immediate (即時)」などは役に立つシナリオです。これらを変数として作成してキャッシュすることで、ブループリント グラフが整理され、量子化して再生するとき、各境界に簡単にアクセスすることができます。

Reset Bools

この関数では、前のサイクルで設定した可能性のあるブーリアンをすべてリセットします。

曲形式のサイクルを確認する

このセクションでは、曲を循環するのが初めてかどうかを確認します。初めての場合は、まず現在アクティブなクロックがあるかどうかを確認します。クロックが実行されていない場合は、曲のステレオ 4 小節のイントロを選択してオーディオ コンポーネントに設定し、「Immediate」の量子化境界を使用して Play Quantized を実行します。

この「Immediate」量子化境界はクロックを開始し、トランスポートもリセットします (これらは、Quartz Quantization Boundary のオプションです)。基本的にこの時点では、曲を再生するのが初めてだと認識しているため、曲のイントロをキューに入れて、再生トランスポートを「00:00:00」に設定しています。
次に、Play Quantized を実行し、量子化されたさまざまな拍をサブスクライブします。これにより、デリゲートを数えたり送信したりするために使用されるイベントとして個々の分割が実行され、基礎となるクロック パルス イベントとして機能します。

メインの再生ロジック

小節と拍が再生され始めると、(小節と拍にそれぞれ) 変数を設定しているため、小節の合計時間と再生中の拍数が数えられます。これらの変数を後で使用して、曲のプレイリストをシャッフルし、新しい曲を選択する正確な時間を把握します。
拍ごとに、曲を変える必要があるかどうかを確認しています。
この「Calculate Song Duration」関数内では、現在のデータ アセットの「小節単位の合計時間」を参照し、拍ごとに「もう変更するべきか?」を計算しています。これは「Bar Counter」変数を参照し、モジュロを使用して最終的に Current Song Duration に達し、その小節の 4 拍目になったことを通知してくれます。それが true の場合は、曲のプレイリストをシャッフルしてこのロジックを継続するタイミングだということがわかります。
トラックを変更するタイミングで「DJ Spin」のサウンド エフェクトにキューを出し、1 曲目を終えて次の曲のイントロを始めるためのトランジション サウンドを発生させます。
最後に、「InitiateNewTrackPlayback」イベントに到達するとブループリント ロジックの先頭に戻り、また繰り返して同じロジックを実行します。しかし今回は、最初の「針を落とす音」とループする環境音は省きます。

プロシージャルな音楽生成

トラックが開始されると、再生される音楽要素がランダムに選択されてキューに入りますが、その際にいくつかのことが発生します。それを確認しましょう。拍ごとに、これらの「Calculate Part Timing」関数を介して「新しいものを再生するのに適したタイミングだろうか?」と確認しています。
例として、ベース パートでは Current Data Asset を参照し、バリエーションを選択する前に正しい小節と拍かどうかを確認します。正しい条件が満たされている場合、実行パスを継続して次のロジックに進みます。
こちらでは、次に再生するのに適したベース パートのセットを選択しています。先ほど説明したように、音楽レイヤーにはそれぞれ、「A」と「B」のグループ、または「デッキ」と呼んでいる 2 つの「セット」があります。これは、DJ の A デッキと B デッキのようなものです。現在「A」で再生している場合は、次に「B」からランダムに選択されます。現在「B」で再生している場合、次は「A」グループからランダムに選択されます。
その選択が完了すると、次に変数「Deck A Is Playing」を使用し、それとは反対の値に設定します。そして次にロジックが実行されると、もう一方が選択されます。これにより、基本的にブーリアン変数が毎回入れ替わることになります。A が再生されている場合は B を選択して B をアクティブに設定します。B がアクティブな場合は A を選択して A をアクティブに設定します。

サウンド変数を Play 関数に渡す

各パートがランダムに選択されると、その uSoundBase 参照 (音楽クリップ) が出力として渡され、「Queue Next Deck」関数にフィードされます。
その「Queue Next Deck」関数では、次のチェックが行われます。これは 4 小節のフレーズだろうか?これはトランジション要素 (2 小節) だろうか?これは 8 小節のフレーズだろうか?結果に応じて、適切な量子化境界を使用してそれ自体を Play Quantized に割り当てます。
このような感じです!おわかりかと思いますが、Quartz は非常に強力なサブシステムで、正確な瞬間にサンプル アキュレートなタイミングで再生をスケジューリングすることができます。この設定で行ったことは、音楽のレイヤーを分割し、それを 4 小節や 8 小節のフレーズに分けて、さまざまな量子化境界を使用して適切なタイミングで再生されるようにスケジューリングしただけです。

Quartz が数を数えて各曲の最大小節数に達すると、データ アセットのプールをシャッフルし、別の曲を選択して BPM を設定し、特定のブーリアン、ゲート、DoOnce などを消去して、同じロジックを実行します。

これを解決するための今回の特別なアプローチは、「これしかない」方法でもなく、「Epicの」方法でもなく、ただの「1 つの」方法です。このコントローラーを磨き上げ、最適化を進めることにより、強化、冗長性の削減、およびセットアップへの MetaSound の組み込みを行う機会が何度も出てくるでしょう。ゲーム音楽、特にプロシージャルな音楽生成に興味のある方は Quartz に挑戦し、自分が納得できるアプローチを使用して独自のシステムを構築することをお勧めします。ただし、Quartz サブシステムは音楽専用のツールではないということを覚えておいてください。音楽アプリケーションとしての機能以外にも、Quartz を使用できる場面はたくさんあります。武器、イベント、プロジェクト全体の規模で同期するものがある場合はどれも、Quartz クロックを作成して望むことをやってみるすばらしい機会です。

Unreal Engine の Quartz サブシステムについての理解が深まり、プロジェクトでの活用方法を考え始めていただけることを願っています。どうもありがとうございました!

ビジュアルを作成する

こんにちは!Epic Games でマーケティング アート ディレクターをしている Paul Oakley です。これから、フォートナイト チャプター 3 シーズン 3 のスタート時に画面に表示されたビジュアルの作成方法に関する情報をお教えします。
おおまかに説明すると、プレイヤーを魅了することができるローファイの環境画面を作成することでした。それは、次に始まるシーズンの雰囲気と自然の概念にとてもよく合っています。私たちは、これが発光生物の森というアイディアに完璧にマッチすると思いました。

私たちはレンズ効果と被写界深度 (DOF) を使用して環境を開発し、それを非常に抽象的にしました。フォアグラウンドは詳細に描かれていますが、遠くになればなるほど抽象的になっていきます。
私たちがこのローファイ サウンドトラックについて話していたとき、「発光生物の森が生きているというアイディアとサウンドトラックのアイディアを結び付けて、発光生物のさまざまなパーツをビートのさまざまな部分とペアにしたらどうなるだろうか?」と尋ねてみたのです。ここでオーディオ チームが本領を発揮しました。

CG チームに静的な美しい レンダリングを作成してもらい、次にすべての発光する木々など、そのイメージのさまざまなチャンネルをすべて異なるマップで実行しました。また、UI/UX チームが UV カードを作成し、そのイメージをカードにマッピングしました。

そして、それらのチャンネルを使用して強度とカラーのバリエーションを操作し、Quartz クロックに組み込みました。これにより、強度乗算の値が操作され、それぞれのビートの振幅によってトリガーされます。

基本的に、これはカードにマッピングされた CG イメージで、そのイメージ内にあるさまざまなマスク要素を示すチャンネルが不足します。
その後、Perlin ノイズやプロシージャルなノイズをカード全体の数学関数として使用して、カラーを変更する方法、強度を変更する方法、あるいは波動や動きを変更する方法を定義しました。

開発者にとって魅力的なこととは?

このプロジェクトには、開発者にとって興味深いクールなことがたくさんあります。まず最初に、従来の映画制作をリアルタイム ワークフローにブレンドしたものがその一例です。

これは、たとえば AOV (または二次出力) がエミッシブ マスクかテクスチャ マスクか、あるいはフォグ ボリューム パスか、いずれであってもレンダリングするという昔ながらの映画制作の原理を使用していました。
これらの追加パスと一緒に美しいプレートがあります。通常、それらを持ち出してコンポジットし、オフラインでレンダリングすると、再び 1 つの静止画像になります。基本的には画像を挟んで再圧縮してから、実際に画像を表示します。

今回はそのようにしませんでした。取得したすべての出力をリアルタイム コンテキストでカードにフィード バックしていますが、これは基本的にはカメラでリアルタイムにキャプチャされます。そのカードでは、すべての二次出力を再コンポジットし、計算によってそれらのマスクを使用して変更を行います。

Quartz クロックもまた、それらのマスクに接続し、変更し、波動するところがリアルタイムにカメラでキャプチャされます。それが、スクリーン空間で視聴者である皆さんに表示されます。これは本当に既成概念に捉われない考え方です。以前からあるものをたくさん取り込んでいますが、それに加えてとても斬新です。

UI およびシェーダー

こんにちは、Marcel Swanepoel です。Epic でフォートナイトのシニア UI アーティストをしています。これからフォートナイト チャプター 3 シーズン 3 のシーズン開始画面を使用して、UI や UI マテリアルのセットアップについていくつかご紹介します。

この機能の開発サイクルは、まず必要となる UI の技術要件を調査することから開始しました。その際の目標は、動的なオーディオ入力を取得して、最終的なビジュアル出力の制御に使用することができる機能を備えた完結型のシステムを生成することでした。同時に、ロード画面としても使用できるように、システムへの負荷を軽くする必要がありました。

システムは最終的に、オーディオの範囲をブループリントからマテリアル パラメータ コレクション (MPC) に出力することにしました。これは、UI マテリアルにそのデータを取り込むために必要となる動的入力として機能し、最終的なビジュアルを構築するために使用されるさまざまなレンダリング パスおよび 2D FX を制御するために使用します。この UI マテリアルは、Unreal Motion Graphics (UMG) を使用してテキストやタイマーなど、他の UI 要素を追加するロード画面のウィジェット ブループリントで参照されます。

UI マテリアルの設定は、さまざまなレンダリング パスを再コンポジットする必要があるため (これはレンダリング チームの担当です)、複雑な側面もあります。さまざまなパスの詳細は、カラー パスから始めましょう。カラー パスとは完全にレンダリングされている画像で、光る葉、川、およびボケがすべて解除されています。さらに、これらの要素からの反射や反射光もすべて無効になっています。これは、音楽が始まる前のロード画面が表示される一番最初の静止ショットになります。

全範囲の RGB 値を使用する必要があるため、さまざまなテクスチャ パスでフォリッジの発光を導入しています。これにより、さまざまな時間間隔でオーディオからトリガーされるフォリッジ グループを生成することも可能になり、すべての発光するフォリッジに、より多くのバリエーションを導入することができるのです。
画像全体で広く使用しているもう 1 つの重要なパスは Z 深度です。これは、シーン深度でフォリッジの発光の強度を制御および抑制するために使用されます。シーン内でフォリッジの位置が遠くにあるほど、強度は弱くなります。ここで、「フォリッジ パス自体でシーン深度と強度をレンダリングしたらよいのではないか?」という疑問が出てくることでしょう。それについては、すべてのフォリッジの発光で 0 から 1 の範囲全体を使用したいため、こうしているというのが答えです。それにより、必要に応じてエフェクトをしっかり調整することができ、さらにすべてのパスを再コンポジットすると、シーン全体のバランスをより効果的に調整することもできます。簡単に言うと、最終的な出力とバランスをより細かく制御することが可能になります。

Z 深度を使用することにより、レンダリング パスをフォアグラウンドとバックグラウンドのグループに分割し、フォリッジの発光範囲をさらに拡張することができます。基本的に、1 つのエミッシブ パスに 1 つのレンダリングされたテクスチャを使用し、自然だと感じられる画面上の位置に Z 深度をクランプします。そのクランプした Z 深度をマスクとして使用すると、2 つのエミッシブ出力ができます。

次に、フォアグラウンドとバックグラウンドの両方を異なるオーディオ出力にマッピングすると、バックグラウンドのサイクルをフォアグラウンドより速くしたり遅くしたりできるようになります。この代わりにエミッシブ パス全体を 1 つのオーディオ出力にマッピングすると、サイクルは画面全体を通して均一になってしまいます。バリエーションを増やしたいことを考えると、この方法は理想的ではありません。Z 深度を使用して発光を分割することにより、1 つのフォリッジのエミッシブ パスから得るバリエーションの数を倍増することができ、望んだ状態に到達することができます。
曲がりくねった川を流れるストリークのエフェクトを作成した方法を見ると、ここでもまた Z 深度パスに多くを頼っていることがわかります。ストリークはカスタム UV の V チャンネルを横切ってパンする、チャンネルパック化されたディスタンス フィールドです。

シーン内をストリークが移動する場合、Z 深度を使用してディスタンス フィールドをクランプし、バックグラウンドの焦点が合っていないものからフォアグラウンドの焦点が合うものへと移動しているような錯覚を与えます。さらに、Z 深度を使用してシーン全体でストリークの強度を制御しています。カスタム UV は川の輪郭に沿って生成されているため、それを 0 から 1 の範囲にマッピングし、ストリークもそれに適切に従うようにすることができます。オーディオ入力を使用すると、強度と表示されるストリークの数の両方を制御することができます。
シーンを仕上げるために、ボケと光線を使用して少し雰囲気を追加しました。これらはどちらも、やはり Z 深度を駆使してシーンにブレンドし、適切にエリアをマスクしています。ボケのエフェクトは、ランダムなノイズ関数を使用して円形の Signed Distance Field (符号付き距離フィールド、SDF) の動き、サイズ、オパシティを駆動するように生成されました。光線マスクはレンダリング チームから提供されたもう 1 つのパスで、Z 深度とカスタム UV マスクと一緒にチャンネルスタックしました。チャンネルパック化は、最大 3 つのグレースケール テクスチャを 1 つの RGB テクスチャ アセットに統合する理想的な方法です。カラー チャンネルごとに個別のグレースケール テクスチャ値を保持し、マテリアルですぐに個別のチャンネルを抽出することができます。これは最適化のメリットとして、とても優れています。

レンダリング チームと緊密に協力して、最終的な調整やバランスの修正をマテリアルとテクスチャに対して行い、値が範囲内にあることや、彼らがまとめた最初のシーンに忠実であることを確認しました。

結論として、私たちの成功基準を満たすことのできる完結型システムの構築という目標は、UI マテリアルを活用しなければ実際には不可能だったでしょう。最初からそれは明らかで、唯一の問題は、オーディオ入力を有意義で動的なビジュアル エクスペリエンスに変換する方法でした。

私にとって UI マテリアル パイプラインが UMG にもたらす柔軟性は、見逃すことのできないものです。これは信じられないほど強力かつ万能で、この 5 年間ほぼずっと、UI 開発において幅広く使用してきました。

    今すぐ Unreal Engine を入手しましょう!

    Unreal Engine は、世界で最もオープンで高度な制作ツールです。
    あらゆる機能とソース コード アクセスを完備している Unreal Engine を使用すれば、すぐに制作を開始できます。