【UE5】モデルにアウトラインをつける方法
プログラマーの尾関です。今回はモデルにアウトラインをつける方法を調べたので情報をまとめてみました。
なお今回の記事を書くにあたって以下の動画を参考にさせていただきました。
アウトラインの実装方法は2つ
この動画で紹介されているアウトラインの実装方法は2つです。
方法 | メリット | デメリット |
背面法 | 1つのマテリアルのみで実装できる | 複数のメッシュで構成されているモデルの場合、内側にも線が出てしまう。これを解消するには、メッシュ1つ1つにアウトラインの太さを指定する必要がある(通常は現実的でない) |
ポストプロセス | 外側にだけアウトラインをつけられる | マテリアルが少し複雑で、ポストプロセスとカスタムステンシルが必要となる |
背面法での実装手順
マテリアルの作成
マテリアルを作成して名前を「M_OutlineHaimen」とします。

マテリアル > 詳細設定

パラメータ名 | 値 | 説明 |
Blend Mode | Masked | 可視性を制御可能にする |
Shading Model | Unlit | ライティングの影響を受けないようにする |
Two Sided | ON | 裏側も描画する |
背面描画と頂点の移動
ノードグラフで右クリックして「TwoSidedSign」ノードを追加します。

“Multiply” で “-1.0” を掛けて負の値にして「オパシティマスク」に接続します。
これは背面のみ描画する設定です。”1.0″ だと正面のみで、”0.0″ だと描画されません。

プレビューをわかりやすくするために “VertexNormalWS” ノードを作成し、”Multiply” で 3倍にして “ワールド位置オフセット” に接続します。

VertexNormalWS は、その名前の通り「頂点の法線」で WS とは “World Space” の略語で「ワールド空間」を意味します。つまりワールド空間における法線方向に3.0倍の値を設定しています。
するとプレビューで背面のみ描画されていることがわかりやすくなりました。

色の設定
色を設定するために Constant3Vector ノードを作成します。

色を赤色にして「エミッシブカラー」に接続します。

プレビューのメッシュが赤色になりました。

アウトラインの動作確認
動作確認用にレベルに球体を配置してみます。

球体は複製して2つ配置します。

どちらか1つのマテリアルに「M_OutlineHaimen」を設定します。

すると真っ赤になりました。

これを合体して重ねるとアウトラインになります。

OverlayMaterialを使ってアウトラインを実装する
この方法だと同じメッシュを重ねるのが手間ですが、OverlayMaterialを使うと1つのメッシュで同じことができます。
方法は簡単で「Overlay Material」にマテリアルを設定するだけです。

例えばキャラクターの Overlay Material にマテリアルを適用するとアウトラインが簡単に実装できます。

Overlay Material については以下のページに活用例が書かれています。
フレネルやノイズテクスチャのUVスクロールを組み合わせると以下の表現もできるようです。

Dynamic Material Instanceで動的にパラメータを変更する
“M_OutlineHaimen” に “LineWidth” というパラメータを追加して、アウトラインの太さを動的に設定できるようにします。

Third PersionのBPを開いて、”Construction Script” でダイナミックマテリアルを生成してパラメータを設定し、Overlay Material にマテリアルを設定します。

実行してアウトラインの太さを動的に変更できることを確認します。

これで、モデルの内側にあるメッシュには太さを変えて設定することで、内側の線を目立たなくすることもできます。
ポストプロセスによるアウトライン
ただ、背面法で内側にあるアウトラインを消すにはメッシュ1つ1つに設定が必要で、かなりの手間がかかります。
そこ、ポストプロセスで実装してみます。
マテリアルの作成
マテリアルを作成して名前を「M_OutlinePostProcess」とします。

マテリアルを開いて “Material Domain” を “Post Process” にします。

グラフに “SceneTexture” ノードを追加します。

詳細タブから “Uマテリアルエクスプレッションシーンテクスチャ” の Scene Texture Id を “PostProcessInput0” にします。

以下のようにしてエミッシブカラーに接続します。

それぞれのノードとパラメータの説明は以下のとおりです。
項目 | 説明 |
SceneTexture:PostProcessInput0 > InvSize | スクリーンのサイズの逆数。例えば画面サイズが “1920×1080” の場合 (x, y) = (1/1920, 1/1080) となります。これは UV座標が (0, 0) ~ (1, 1) の範囲となるため、画面比率を UV座標系で扱いやすいようにした単位とも言えます |
Multiplyの理由 | InvSizeに対して (x, y) = (1, 0) を乗算することで、1単位で右側にずらすことができます。そのためこの値を大きくすることで、より大きくずらすことができます。 |
Addの理由 | InvSize は固定値なので、実際のUVの値は TexCoord から取得したものに加算する必要があります |
シーン深度を使う
「ライティングあり > バッファを可視化 > シーン深度」を選ぶと、シーン深度の情報を可視化できます。

シーン深度は「近くのものを黒 (0)」「遠くのものを白 (1)」にすることが確認できます。

まずは SceneTexture:PostProcessInput0 から “Color” のピンを伸ばして “ComponentMask” ノードを作成します。

欲しいのは “R” 成分だけなので、詳細タブから “R” のみにします。

“InvSize” から合成した Color にも Component Mask (R) を適用し、Subtract ノードで減算します。

この状態だとプレビューが真っ暗なので、それぞれの SceneTexture を “PostProcessInput0” から “SceneDepth” に変更します。

プレビュー表示が以下のように「デプスに差があるところが白く」なります。

ただ左側にしかないので、これを「上下左右」に適用されるようにします。
マテリアル関数で「上下左右」に適用されるようにする
左側の処理をコピー&ペーストで作ることもできますが、無駄が多いので「マテリアル関数」にして処理を使い回せるようにします。
コンテンツドロワーで右クリックして「マテリアル > マテリアル関数」を選びます。

名前は「MF_OutlineFunction」にしておきます。

「M_OutlinePostProcess」のノードグラフをコピーして、「MF_OutlineFunction」に貼り付け、”Output Result” にピンを接続します。

値を受け取れるように「FunctionInput」ノードを作成します。

入力の型は「Vector 2」にします。

(x, y) = (1, 0) のノードを削除して、Multiplyにピンを接続します。

マテリアル関数を呼び出す
「M_OutlinePostProcess」に戻ってノードをすべて削除し、コンテンツドロワーから「MF_OutlineFunction」をドラッグ&ドロップします。

引数に Constant2Vector の (1, 0) を渡すことで、アウトラインが左側に表示されました。

後はこれをコピー&ペースとして上下左右に作るようにして、Addノードで加算すればアウトラインになります。

マテリアルを適用する
レベルを開いて「PostProcessVolume」の「ポストプロセスマテリアル」に「M_OutlinePostProcess」を適用します。

するとシーン全体にアウトラインが適用されます。

SceneTextureと合成する
画面が白黒になってしまったので、「M_OutlinePostProcess」を開いて、SceneTextureと合成する処理を追加します。

アウトラインとなる部分をアウトラインの色(ここでは赤)とLerpで線形補間で合成します。
線を目立たせたい(太くしたい)場合は、「MF_OutlineFunction」の “Input In” に乗算して太くします。

これで今まで通りの表示となり、アウトラインが表示されるようになりました。

カスタムステンシルでアウトラインを外側だけにする
ただこのままだと、結局モデルの内側にもアウトラインが表示されたままです。
その問題を解消するために「カスタムステンシル」を使います。
カスタムステンシルを使うにはプロジェクト設定から「エンジン > レンダリング」の「カスタム深度ステンシルパス」を「Enabled with Stencil」にします。
(※検索欄に「custom depth」と入力するとすぐに見つかります)

設定を確認するために、ライティング設定から「バッファを可視化 > カスタムステンシル」を選びます。

しかし何も表示されなくなります。

アウトラインを適用したい対象(ここでは Third Persion キャラクターの メッシュなので「BP_ThirdPersonCharacter」) を開いて、詳細タブから以下の設定をします。

パラメータ名 | 値 |
Render CustomDepth Pass | チェックを入れる |
CustomDepth Stencil Value | 1 |
コンパイルして BP_ThirdPersonCharacter をレベルに配置すると、CustomDepth Stencil Valueに設定した「001」という番号で表示されるようになります。

「MT_OutlineFunction」を開いて、”SceneDepth” を “CustomStencil” に変更します。

するとアウトラインがモデルの外側だけに表示されるようになります。

ただ2体が重なったときに、アウトラインが結合してしまう問題があります。

この問題を解消するには、重なる可能性があるオブジェクトは異なる “CustomDepth Stencil Value” にします。

「バッファを可視化 > カスタムステンシル」で可視化すると別の番号が振られていることがわかります。

番号を分けたことで、アウトラインが共有されずに、各モデルのアウトラインとして表示されるようになりました。

カスタムデプスの有効・無効の切替方法
“Set Render Custom Depth” ノードでカスタムステンシルを ON/OFF できます。

参考
この記事を書くにあたって、以下の動画を参考にさせていただきました。