9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Unreal Engine (UE)Advent Calendar 2023

Day 17

[UI] オーディオ信号の周波数グラフを作成しよう!オーディオBPからUIに映るまでの構造

Posted at

はじめに

こんにちは、初投稿です!
僕がUIのマテリアルを研究し続けていて丁度「オーディオ信号の周波数グラフ」を作成してみたかったところです。いい機会なので記事にまとめてUEアドベントカレンダーに載せようと思ったきっかけです。
こちらの記事ではラジアルとリニア形式、グラフの2パターンをご紹介していきます。
初心者も作れるように画像とステップを多く含めました。ベテランならばどんどん飛ばして確認したい項目のみでもご確認いただければと思います。

グラフはこちらのものです。
UnrealEditor_aRyAAjvD5D.gif UnrealEditor_MSmTsODLgq.gif

音に関する豆知識

本番に入る前に、作り方に当たって最低限こちらのオディオ知識が必要となります。よーく見かけるものに関わらず、意外とグラフの読み方知らない方が多いのではないかと思います。(恥ずかしながら僕はそうでした)
分かりやすく説明するためこちらのシンプル図を用意しました。
X方向には可聴周波数(Hz)幅でY方向には音圧(dB)です。横方向は左が低い音を示し、右が高い音です。縦方向は音の圧力、量のことですね。バーが高いとうるさいということです。
という訳で、このパラメーターがあればグラフが作れます。

Flowchart (2).jpg

作りこなせばできるようになること

最後まで作ってしまえばこちらの要素ができるようになります。

ー RenderTargetへ描画する方法
ー BPからマテリアルに値を渡す方法
ー Synesthesia NRTというサウンドプラグインの設定方法
ー BPインターフェスの使用方法

準備

環境と必要なものまとめです。

ー UE5
ー Audio Synesthesia (プラグイン)
ー サウンド(.wav)を用意 (最低限1x)

Audio Synesthesiaはサウンドファイルの情報を読み取りBPで扱うようにしてくれる、便利なプラグインです。

デフォルトにUE5にインストールされているはずですが、念のためご確認しておいてください。
Beta版になってます。プラグインメニューからチェックが入っていれば大丈夫です。
Screenshot_76.png

目次

ー フローのご紹介
ー ① NRT作成とSoundの設定
ー ② BPInterfaceの作成
ー ③ WidgetとRenderTargetの作成
ー ④ ActorBPの作成
ー ⑤ MaterialVisualの作成 (バーの作成)
ー ⑥ MaterialRenderの作成
ー テスト
ー NRTSetting説明

フローのご紹介

詳細に入る前に迷わずアセットがどのように繋いでいるかをご理解していただくためにこちらの大まかなフロー図を用意しました。

image.png

名称 解説
NRT サウンド情報を収穫してくれるアセット(プラグイン)
Sound サウンドファイル
Actor BP ウイジェットとサウンド間に値渡しするBP
Widget HUD 画面に映るWidget
BP Interface BP間に値渡しをシンプル化してくれるもの
Widget Render Target RenderTarget描画管理するウイジェット
Material Visual バー作成するマテリアル
RenderTarget Texture バーが描かれるテクスチャー
Material Render MaterialVisualの透明度をサポートしてくれるマテリアル

描画処理説明と最適化について

毎フレームにRenderTargetへバーを書き込み、バーの数により描画回数が決まります。つまり、バーが多ければ多いほど描画回数が増して処理が重たくなります。具体的の例を挙げるとバーを40描画するには1フレーム当たり40回バーのポジションと長さを計算しRenderTargetへ出力します。。ここのRenderTargetは保存テクスチャーとして使用され、バーが全部揃った時点でMaterialRenderを通してアルファを反対し、1フレーム当たりの描画結果をスクリーンに写します。

処理が多いため、こちらの制作フローが最適化されておりません。本来はマテリアル内で解決したかったのですが、BPからの配列変数をマテリアルに渡せない代わりにRenderTargetテクスチャーをしました。
プロファイリングはまだしておりませんが、興味深いです。いつかの課題として残しておきます (笑

こちらの図は上記に解説したRenderTargetの使い方です。マテリアルを何回も通してRenderTargetに描画して、処理が終わると描画結果を出します。それを毎フレームに行います(!!)
byougamaisuu.png

① NRT作成とSoundの設定

さて、本編に入りましょう。
まず.wavのファイルをUEに入れます。このようなアセットが出てきます。

image.png
僕は無料BGM、Musmusというサイトからサウンドをダウンロードしました。
.wavがなければオンラインで簡単にどんな拡張子からでも.wavに変換できるコンバーターが存在します。

次に、オーディオ情報管理ができるNRTファイルの作成です。サイドメニュー(右クリック)からAudio>Analysis>SynesthesiaNRTを選択します。
image.png

ウインドウが現れます。ConstantQNRTLoudnessNRT一つずつ作成します。
image.png

ConstantQNRTは周波数情報に該当するものです。ConstantQNRTだけでグラフが成り立てます。値は配列形式で出力されます。バーの位置は配列のIndexで定められ各Indexにある値が音圧に該当します。

LoudnessNRTは音圧に該当するものです。こちらの音圧は全周波数合計に該当し、ラジアルマテリアル中心の円がリズムについてくるようにLoundnessNRTを使用します。

次に、Audio>Analysis>Synesthesia NRT Settingを作成します。
周波数を調整したいだけなので作成するのはConstantQNRTSettingだけで十分です。
image.png

合わせてアセット3つになります。
image.png
各アセットの設定をしましょう。

ConstantQNRT

先ほど作成したConstantQNRTSettingとサウンドをこのように設定します。
image.png

LoudnessNRT

今回はLoudnessNRTSettingsを作成していないのでDefaultLoudnessNRTSettingsのままで大丈夫です。サウンドは上記と同様です。
image.png

ConstantQNRTSetting

ここはグラフのパラメーターを調整できる場所です。とりあえずこのように設定しておけばよいでしょう。
image.png

重そうと思えばFFTSizeをLargeもしくはXLargeにするとよいです。

SartingFrequencyは最小数の周波数を示すものです。値が高いとバーが減りますので、常に最小値(20)にしておきます。

NumBandsはバーの数になります。バーが多いと描画の回数が増え処理が重いのでご注意を。

Noise(dB)は最終的にバー合計の高さを調整できるのでその段階で弄りません。
それ以外はほぼ触っていないです。パラメーターに関してご興味があればこちらの公式ページをご確認ください。

これでサウンド編が完了です。

② BPInterfaceの作成

こちらのアセットの役名はクラスの親子を気にしないで変数をWidgetとBP間に簡単に渡せる、非常に便利なものです。BPとBPのつなぎ込み方法は色々あるのですが、今回はBPInterfaceがどのものなのかを含めて見たかったので使用しました。
サイドメニューのBlueprint>BlueprintInterfaceを選択します。
image.png

開いてから空なのでファンクション1つ追加します。「Add」ボタンを押し「OnSetSynthetiseur」という名をつけます。
image.png

InputセクションにはこのようにFloat変数4つ作成します。

image.png

名称 解説
Db 一定時の音圧(バー1本当たりの高さ)
FreqNb 可聴周波数の幅 (バーの数)
FreqHz 一定時の周波数(バー1本当たりの位置)
Loudness 音圧合計(円型マテリアルの中心に使用)

保存し、閉じましょう。BPInterfaceを完成しました。

③ WidgetとRenderTargetの作成

ウイジェットはWBP_HUDとWBP_RenderTarget、2つ作成します。

サイドメニューからUserInterface>WidgetBlueprintから作成できます。

image.png

両方UserWidgetクラスにします。
image.png

WBP_RenderTarget

こちらはImage一枚が十分です。
image.png

変数とBPInterfaceの設定

BPInterfaceがWidgetから見えるため、ClassSettingsよりBPInterfaceを繋げておきます。Addボタンを押して作成したBPInterfaceをリストから選択します。
image.png
image.png

次に必要な変数を作ります。
image.png
TextureRenderTargetを設定するにはRenderTargetというテクスチャーが要るのでまず作りましょう。

RenderTargetテクスチャーの作成方法

サイドメニューからTexture>RenderTargetを選択します。
image.png

テクスチャーセッティングはこのようにしておきました。2Kが大きいですが、研究プロジェクトなのでとりあえずよいクオリティで出しておきましょう。
image.png

できたテクスチャーをWBP_RenderTarget内のTextureRenderTarget変数に設定します。
image.png

RenderMaterial内にはステップ⑤番に作る予定のマテリアルを入れますが、一旦変数だけ作っておいて後に戻って繋げましょう。
DynamicMaterial変数はBPで定義します。(次のステップ)

Graph

CustomEventはこのように作ります。
image.png

OnSetSynthetiseurは先ほど接続したBPInterfaceから呼び出せます。右クリックしOnSetSynthetiseurを検索すれば出てくるはずです。
このようにノードを繋げます。MaterialParameterの名称に気をつけましょう。
image.png

WBP_HUD

ウイジェット内は黒背景とContainerを作成しています。Containerはなんでもいいです。Canvas,OverlayもしくはGridPanel。ウイジェットGraphからWBP_RenderTargetを生成してContainerの子供として加えますので、UMGのヒエラルキーに直に置きません。
image.png

ウイジェットのGraph(BP)側ではOnInitRenderTargetのCustomEventを作成し、WBP_RenderTargetを生成した後に変数化しContainerに追加します。ReturnValue上に右クリックして「Promote to Variable」で変数化してくれます。Createノードは「Create Widget」の検索から生成できます。Class中には先ほど作ったWBP_RenderTargetウイジェットを設定します。

image.png

そのOnInitRenderTargetはのちほどActorBPから呼びます。次のステップ(ActorBP)に移りましょう。

④ ActorBPの作成

Actorブループリントを作成します。サイドメニューからBlueprint>BlueprintClassを選択します。

image.png

クラスはActorです。
image.png

そのブループリント中にはオディオコンポネントを追加し、変数はLoudnessNRT、ConstantNRT、CQ(Float配列)とWBPHUD(HUDのウイジェットクラス)を作成します。
Screenshot_85.png

コンポネントオーディオを選択しながらDetailsタブ内にサウンドアセットを設定します。
image.png

Graph

BeginPlayノードからサウンド設定、CreateWidgetからWBP_HUDを生成し、Viewportに出します。ゲーム開始時にサウンドが再生するようにPlayノードも入れておいてCQ変数の初定義をします。(CQ変数は毎フレームに更新する必要があるのでBeginPlayに必要ないかもです、念のため定義しておきました)
Screenshot_74.png

OnSynthetiseur(Call Message)ノードを出してTargetにはHUDの子供であるWBP_RenderTargetを接続します。それでUEがWBP_RenderTargetウイジェットへオーディオ情報を送り、RenderTargetのテクスチャーに描画するようにできました。
ループに入る前に、CQ変数を更新し、各パラメーターに情報を渡します。
image.png

次はいよいよマテリアル編に入ります。

⑤ MaterialVisualの作成 (バーの作成)

マテリアルはサイドメニューから直接にマテリアルを選択すると作成されます。
image.png

マテリアルをUserInterfaceとTranslucentにします。マテリアル内のDetailsパネルから変更できます。
image.png

さてと、下記のグラフに移ります。
分かりやすくするため、マテリアルファンクションを作成しました。(MF_SynthBar)
下記スクショに詳しくノードを載せています。

オーディオ用のパラメーターは先ほど設定したActorBPでの値はオーディオアセットからの情報をウイジェットに送り出されてマテリアル内の値は上書きされますので、ここでは仮な状態でよいです。

IsCircularノードは「Switch Parameter」です。On/Offにより縦型、ラジアル型で姿を入れ替えられます。

Screenshot_79.png

GradientScale,GradientOffsetXとGradientOffsetYはラジアル型限定のパラメーターです。
バーの長さによりColor2が見えなかったりするのでグラデーションの見るどころを調整するためのパラメーターです。

MF_SyntBarの詳細

マテリアルファンクションの詳細に入ります。グラフが少し大きいので部分を取り分けてスクショを載せます。
バーの姿2つあるのでOutputノードを2つ用意してます。
Screenshot_80.png

まず、マテリアルファンクションの作成方法。
サイドメニューからMaterial>MaterialFunctionを選択します。
image.png
できたファンクションアセットをマテリアルにドラッグ・アンド・ドロップすればノードとして出現します。

ファンクションの中身ですが、名称付けられるRerouteを使用し、ぐちゃぐちゃならないようINPUTをこのようにまとめます。
Screenshot_81.png

Linear

バーの縦型、リニア編です。
Screenshot_82.png

Radial

RadialUVは別の名称付のRerouteを作成しこのようにUVを極座標系に変換します。
Screenshot_83.png

Screenshot_84.png

色々ノードを繋げていますが、一つ一つ説明していくとより長くなってしまうので今回は省略してスクショを参考にして再現していただければと思います。

マテリアルインスタンスを作成

マテリアルができると、インスタンスを作成します。マテリアルを右クリックし、Create Material Instanceを選択します。
image.png

そこからパラメーターをいじって確認できます。楽しい!
UnrealEditor_yK9ifeEkIq.gif

isCircularにチェックを入れるとラジアル形式で、はずすと縦バーの形式に代わることが確認できます。
UnrealEditor_sKu4KnmLwF.gif

バーは一本しか見えないのは正しいです。全バーが表示されるのはRenderTargetだけなのでBP処理が入らないと見えないです。

ラジアル型とリニア型一つずつのインスタンスを作ってしまうといいかもしれません。BPでインスタンスを差し替えればよいし、インスタンス内のIsCircularを調整すれば同じ結果にできます。ただし、SwitchParameterはランタイムで制御できないので注意しましょう。

忘れずにWBP_RenderTargetにマテリアルを設定しましょう

WBP_RenderTarget再び開き、RenderMaterialに作ったマテリアルインスタンスを設定します。
image.png

⑥ MaterialRenderの作成

先ほど作ったマテリアルをそのままRenderTargetに描画してもよいのですが、透明度に問題があるため、透明度が美しく映るように別マテリアルを作成してます。どういう問題なのかは気になる方はこちらご確認ください。

新たなマテリアルを作成し、ドメインをUserInterface、ブレンドモードをAlphaCompositeにします。
image.png

ノードはシンプルです、作ったRenderTargetのテクスチャーをSamplerに設定し、変数化します。そしてSamplerのアルファをリバースするだけです。
Screenshot_78.png

WidgetにMaterialRenderを設定

最後に作ったWBP_RenderTargetがマテリアルを映すためにImageにマテリアルを割り当てます。
image.png

これですべての設定が完了しました。

テスト

テストはActorBPを好きなシーンにおいて再生するだけです。WBP_HUD黒背景なしでも3Dシーン上に表示できますよ。
image.png

懸念点
背景が黒くないとバーのエッジに白いピックセルが少し写ってしまいます。原因はまだ調べ中です。
また、ラジアル型では最初と最後のバーがどうしてもくっついているのですが、マテリアルを少し調整すればきれいに並べられる気がします。

NRTSettingについて

最初に作ったNRTSettingを再び開き、バーの数、周波数の幅を調整できます。

バグかもしれませんが、NRTSettingを保存するだけでパラメーターが更新されないようなのでご注意ください。煩わしいですが、ConstantQRTアセットに変更がないとセッティングが渡り移らないようです。僕は毎度ConstantQRTのサウンドを変えて戻してあげて保存するようにしてやっとNRTSettingの最新パラメーターが適用されます。

最後に

思ったより長い記事になりまた。お疲れ様です!
コメントや開発アドバイス、記事の書き方アドバイス、ご質問などがありましたらいつでもTwitter(X)上でご連絡ください。
https://twitter.com/ko_yuki_lo

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?