【UE5】マテリアルピン(アウトラインマスクとカラー)を追加してみた - Unreal Engine 5.3

始まり

マテリアルピンを追加するエンジン改造をしていきます。

マテリアルピンとは?

Base ColorやMetallicなどの最終的な計算結果を接続する部分のことをマテリアルピンと呼びます。

実装を覗いてみるとマテリアルプロパティやインプットという名称も使われているので、またしても正式名称は知らんです。

相手に伝わるレベルの言葉の揺れは許してね。


パラメーターをシェーダーに渡したい場合は、マテリアルピンを追加する必要があります。

独自のコンスタントバッファを追加すればいいじゃんと思うかもしれませんが、Unreal Engineでそのやり方はまぁまぁな手間を要するので、一般的には実装までの導線が最低限確保されているマテリアルピンの追加が選ばれます。

エンジン改造とは?

ゲームエンジンのコードを書き換える行為をエンジン改造と呼びます。

尚エンジン改造という呼称が正式かは知らんです。

これ以上の真面目な説明はググればヒットするので割愛します。

以下、実際の描画まわりの改造事例です。

前髪を透かしたり

毛先まで綺麗に表現できるポストプロセスなアウトラインを描いたり


キャラと背景を別々のシャドウマップに書き込んでセルフシャドウを抑制したり

画像準備中

髪影を落としたり

頂点IDノードを追加して、それを元に鼻に線を引いたり

Substrate (旧: Strata) 非対応

Substrateはマテリアルピンの構成が異なり内部でピンの再接続が行われています。

その再接続部分を対応していないので、Substrateは非対応という感じです。

リポジトリ

最新バージョンのみ保守しています。
過去バージョンが動かないと言われても基本的には知らんがなスタイルです。

実装

アウトラインマスクとアウトラインカラーを格納するピンを追加していきます。

アウトラインマスクの型はfloat、アウトラインカラーの型はfloat3を想定します。

Engine/Source/Runtime/Engine/Public/SceneTypes.h

マテリアルプロパティの列挙体にアウトラインマスクとアウトラインカラーを追加します。

MaterialPropertyの頭文字を取ってMPですね。

githubで実装を見る(L196-L199)

Engine/Source/Runtime/Engine/Classes/Materials/Material.h

ピンの接続関係なを保持する変数です。

型によって使用するFMaterialInput構造体が異なります。

カラーはベクターとかでもたしか問題なかった気がしますが、精度がfloatとuintで面倒なことになるので、基本的にはカラーの方を使います。

githubで実装を見る(L404-L410)

Engine/Source/Runtime/Engine/Private/Materials/Material.cpp

static_assertの対応です。

要素の増減によってはシリアライズの互換性が無くなるため、static_assertで「対応忘れずにね♪」というスタイルだと思います。

githubで実装を見る(L2805-L2809)


マテリアルピンの接続を取得する関数です。

ツールチップ的な説明ではなく、構成要素の型とかの内部情報の説明ですね。

githubで実装を見る(L5751-L5752)


ピンに刺さっているノードのコンパイルまわりです。

接続されている場合はそれが展開されて、未接続の場合はFMaterialAttributeDefintion::CompileDefaultValueに飛ばされて任意の初期値が適用されます。

githubで実装を見る(L6362-L6363)


ピンの有効性です。

シェーディングモデルがToonLitの場合のみ有効、それ以外はグレーアウトするように指定しています。

githubで実装を見る(L6990-L6993)

Engine/Source/Runtime/Engine/Private/Materials/MaterialAttributeDefinitionMap.cpp

先ほど触れたピン未接続時の初期値を指定しています。

アウトラインマスクはマスクをしないが初期値なのでCompiler->Constant(1.0f)を指定、アウトラインカラーは黒色が初期値なのでCompiler->Constant3(0.0f, 0.0f, 0.0f)を指定しています。

Compiler引数からシェーディングモデルの情報が取得可能なため、条件に応じて初期値を変えることもできます。

githubで実装を見る(L74-L84)


アトリビュートマップに追加したマテリアルプロパティを登録しています。

左からGUIDが個体識別、表示名等、紐付けするマテリアルプロパティ、型の種類、初期値、それを使用するシェーダーステージって感じです。

他にもデフォルト引数で隠れている要素もあるので、覗いてみると面白いかもです。

そしてシェーダーステージを指定している通り、頂点シェーダーで扱うピンを追加する場合はまた違う種類を指定しないとなのですよね。

地味に面倒ですが、マテリアルエディタという面倒なシステムに対応する都合上、これくらい明示的な方がいいんでしょうね。

githubで実装を見る(L290-L291)


これもアトリビュート関連ですね。

LOCTEXTはたしか文字列のキャッシュなので頻繁に使う場合メモリに載せておいて確保と解放の手間を省くとかだった気がします。

間違えてたらすまん。

githubで実装を見る(L464-L467)

Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionMakeMaterialAttributes.h

ピンの接続関係などを保持する変数のMaterialExpressionMakeMaterialAttributes版です。

ちなみに使ったことないです。

githubで実装を見る(L78-L84)

Engine/Source/Runtime/Engine/Private/Materials/MaterialCachedData.cpp

MaterialExpressionMakeMaterialAttributesに接続されているピンの更新まわりです。

githubで実装を見る(L521-L522)


上記同様です。

githubで実装を見る(L716-L717)

Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressionHLSL.cpp

MaterialExpressionMakeMaterialAttributesの関連です。

使わないから語りたいことがない件について。

githubで実装を見る(L1818-L1819)

Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressions.cpp

マテリアルプロパティに対応した入力情報が詰まった変数を返している部分です。

githubで実装を見る(L6706-L6707)


static_assertは同様に要素数を変更したら対応してね♪の静的な通知機能です。

githubで実装を見る(L6736-L6740)


シェーダーコンパイル部分ですね。

githubで実装を見る(L6771-L6772)


static_assertは同様に要素数を変更したら対応してね♪の静的な通知機能です。

ちなみに以降はMaterialExpressionMakeMaterialAttributesではなく、それをばらすMaterialExpressionBreakMaterialAttributesノードです。

githubで実装を見る(L6833-L6837)


MaterialExpressionBreakMaterialAttributesノードの各ピンが出力するチャンネル数を指定しています。

githubで実装を見る(L6871-L6872)


Displacementのマスクがなかったので勝手に追加していますが、どちらが正解なのか分かりません。

先日githubの方にもリリースされた5.4.4でも特に修正入ってなかったから無いのが正解なんですかね。

でも他を見れば分かる通りDisplacementは入出力対応ピンなんですよね。

誰かPR出して確認取ってくれないかなーと数年間思い続けています。自分でやるのは怠い、英語分からねぇし。

githubで実装を見る(L6920-L6922)


原始的な紐づけ方法で草ですわ。

githubで実装を見る(L6963-L6964)

Engine/Source/Runtime/Engine/Private/Materials/MaterialHLSLEmitter.cpp

アウトラインマスクとアウトラインカラーのシェーダーコードを常時展開として指定しています。

理想はCustomDataと同様に使用する場合のみ展開なのですが、ぶっちゃけ実装が面倒だし、大してシェーダーランタイム負荷にもならんので、保守性を優先して簡単な常時展開を採用しています。

ちなみにココを見ると分かりやすいと思います。

判定が偽の場合は、以降に進まないのでシェーダーコードが展開されないって感じです。

githubで実装を見る(L814-L815)

Engine/Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.cpp

MaterialHLSLEmitterと同様です。

どちらが新コンパイラで旧コンパイラかは忘却しました。

両方把握していれば別にどうということはないという脳筋スタイルです。

githubで実装を見る(L416-L417)


Chunkも上記と似たようなものです。

新旧で設計が多少違うのでしょう。

githubで実装を見る(L1071-L1072)

Engine/Source/Editor/MaterialEditor/Private/MaterialEditor.cpp

アウトラインマスクの型であるfloatは、UMaterialExpressionScalarParameterに区分されます。

githubで実装を見る(L4690)


アウトラインカラーの型であるfloat3は、UMaterialExpressionVectorParameterに区分されます。
float2やfloat4も同様にベクターパラメータに区分されます。

githubで実装を見る(L4702)

Engine/Source/Editor/UnrealEd/Private/MaterialGraph.cpp

ピンにカーソルを重ねた際に表示されるツールチップ部分です。

githubで実装を見る(L269-L270)

Engine/Shaders/Private/MaterialTemplate.ush

ピクセルシェーダーでアウトラインマスクとアウトラインカラーを取得する関数部分です。

関数名の末尾にRawがある場合はノードの結果をそのまま取得、Rawがない場合はGBuffer等に格納するのを想定してクランプ済み、または正規化済みな値を取得する、といった感じで使い分けます。

マテリアルノード側でsaturateする必要が無いように整備してあげるイメージです。

githubで実装を見る(L2953-L2971)

簡単な動作確認

追加したOutline MaskやOutline Colorを目に見える形で動作確認するためにはGBufferに格納しないといけないのですが、そこまでやるのは面倒なので簡単に確認できる方法を軽く紹介します。

型に応じたCustomノードを接続
Window > Shader Code > HLSL Codeをクリック
下の方にスクロールするとCustomノードの展開結果とそれがピンに格納されていることが見れる

おわり!!!

スカラーパラメータであるアウトラインマスク、ベクターパラメータであるアウトラインカラーをピクセルシェーダーに渡すためのマテリアルピンの追加でした。


改めて見返すとMaterialExpressionMake/BreakMaterialAttributesノードがコード行数を稼いでいますね。

筆者は使ったことないノードだから正直鬱陶しいんですよね。

ブレンドできたりとか汎用化するには便利なんでしょうけど。

雑談

ここから先は年齢制限のかかっている作品を取り扱うページとなります。


表示する

目次


  • オトメきのリアイベが盛り沢山 - 2024/08/25 (日)
  • Blenderプラグイン説 - 2024/08/25 (日)
  • 共通ルート編 - 2024/08/27 (火)
  • 共通ルート編 - 2024/08/28 (水)
  • 共通ルート編 - 2024/08/29 (木)


オトメきのリアイベが盛り沢山 - 2024/08/25 (日)


セレオブにも予約引換?ありましたね。

お弁当も同様に。

ま、出不精の筆者には無縁のイベントなのです。


Blenderプラグイン説 - 2024/08/25 (日)


CSでライン引いたり、普通にVS/PSでテクスチャ空間で描画したり、準備は整ったんだけど、UEで完結する作業フローが怠すぎることに気づいてしまった。

Blenderみたいに曲線ブラシもカーブで代用しないとだし。

Blenderプラグイン作った方が早い説?

最近は保守でしかPythonちゃんとイチャイチャ出来てないし、久々に新規開発でもやろかな。

描画に関連するツール開発は、Unityに比べるとやっぱり踏まないといけない手順が多くて怠いですね。

こういう楽しそうなことをパパッと出来たらもっと楽しいんですけど、足踏みフェーズが存在するあたり、まだまだなんだなと落ち込む筆者さんでした。


共通ルート編 - 2024/08/27 (火)



シークレットラブ(仮)のネタバレを含みます。

「めちゃくちゃ好きです」

わたしも!

足りないか?はノンデリ過ぎるだろ。優しいのにデリカシーはないのかコイツ。

あー、ノンデリだった。

ボッチに面と向かってぼっちか?と質問するのゴミ過ぎる。


Q. 好きじゃないんですか?
A. バカか?

返答辛辣過ぎて草

お嬢様キャラなら適当に人間使って買いに行かせればいいのに。


ぶ ち 壊 す

お淑やかな言葉遣いを頼むわ、お嬢様。


わかりますか!

いやわからないでしょう!

自己完結する流れ好き。わたしもよくやる。


自炊しないと湊くんにぶちぎれられますよ...

最近は冷凍食品美味しいですよね。

湊くんに食べてもらいたいくらいです。

たぶん少しは見直すことでしょう。

技術の進歩はすんごいです。


よしっ。輪郭線改修のビルド待ちだからゲーム画面みーよぉっと。


ガチのお嬢様なら白鈴学園に行ってどうぞ。


気持ちは分かるが「うそでしょ」は面と向かって言われたら凹むぞ。


鼻がめっちゃ法線とライトベクトルの内積感。


パンツ見えなくても太もも見えてるし別に満足だろ。


クレカ破産か、なのは破産しかけたアホなら身近にいたぞ。


見えそうで見えない!

ドンッ

ピンク!

流れ草


タイツのあの微妙にエッチな感じ、シェーディングで表現したいんだけど、なかなか難しい。

仕事は全年齢だから、そういうところを求めてないから得る機会が無いのよね。


それ横領

せやな


呑気な主人公さんですな。

指名されるのどうせお前やぞ。


アスパラベーコン、美味しそう。


めっちゃ話戻るけど奏命様に触発されて苺大福を作りたくなったんだけど、苺の時期が過ぎてた。

レシピだけ調べて終えた悲しき筆者さんでした。


料理とかレシピ通りに作れば失敗もクソもねぇのですけどね。

お菓子作りするためにいいオーブンレンジ買ったけど、結局コード書くのが忙しくて作ってないですね。

クッキーを作ると粉のせいで筋肉痛になるから地味に嫌。

筋力が無さ過ぎるのも問題あるなと度々思う筆者さん。


楓さん、いいですね。

楓さんの見た目だけで購入しましたが大正解でした。

やっぱりフィーリングって大事よ。


アウトラインを改修して口元を分かるようにしてみた。

なんかアウトラインカラーの計算が周りと違うな。

見直し中。

計算ミスってた。

これで大体同じになったかな。

鼻も分かりやすくしたいなぁ。

1か月ぐらい前に技術検証で学マスの鼻ポリゴン作ったから、それ入れてみようかな。

流行りの学マスですが、アイマスとの違いが分かりません。

そもそもアイマスすら分からん。

なんでこの程度の知識でゲームプログラマやれてるんだろう・・・

まーじでR&D業務が多くて助かってますわ。

ガチガチのインゲームプログラマだったら「最近流行りの~~みたいな表現」とか言われたら即死待ったなしですわ。

人間には向き不向きがありますからね。

僕はインゲーム向いてない。

個人制作は別腹だけどね。


わかるー。カリッとしたベーコン旨いよね。


ふーむ。

やっぱり衣類のしわってあった方がエッチだよなぁ。

どうやろうかなぁ。

テクスチャを書き換えるコストは払えないから技術的に頑張るしかないんだよね。

あとで調べよ。

そして今日は寝よう。


共通ルート編 - 2024/08/28 (水)



シークレットラブ(仮)のネタバレを含みます。

服のしわってエッチだよね。から興味が湧きました。

Cloth wrinkleと検索するとヒットしました。

GPUシミュ、法線あたりなのかな。


ミリ可愛い、ミクロ可愛い、言葉の響きがいいですね。


わかる。

クーデレ、いいよね。

だからパフェクイーンを攻略したい。

だけど9-nine-やるならもう1回最初から遊びたいのよねぇ。


鼻の部分、いい感じ。

昔のアニメ調なセルルックってベタ塗りが正義だから、こういう形状を認識できるためのワンポイントって重要なのよね。


気が付いたらルート選択だ。


このヘアハイライトの表現いいな。

角度によっては浮き出て、角度によってはベースカラーに溶け込むと...

参考になる。


スカートの陰いいなー。

2値陰とシンプルなNoLな陰、この混ぜ具合はやっぱり人力で成せる業よな。

数学的な判定で出来ないモノかなぁ。

まぁ筆者はバカだから数学とか分からんけど。

内積を理解したのが関の山。

音声合成虚数が出てきた時は死を覚悟したよ。

好きなことで関連するなら仕方がないから覚えるけど。


ロングスカートのメイドさんね。

布物理を完璧に設定できればエロ可愛いんだろうけど。

SDFテクスチャ作成ツールは若干諦めムード漂わせてるし、布物理に移行しようかな。


眉と瞳を透かす処理、ポストなアウトラインだと2パス処理しないとダメか。

そこだけ背面法で描くべきかなぁ。

エンジン弄ればOverlayマテリアルを普通のマテリアルみたいに、スロット毎に指定できるし。安上がりな方法だと頂点カラーをオパシティマスクに接続してdiscardで切ればいいんだけど、描画フローを全掌握してる個人環境は好きなことしたいからね。回り道もまた一興なのですよ。

あとは髪影落とさないとな。


やばい、鼻のラインが完璧過ぎる。

流石、私です。

ま、元ネタは学マス、実装方法はツイッターに上がってたので、現実はそれをエンジン改造という脳筋実装しただけの有象無象。

もっと強く成りてぇですわー。


共通ルート編 - 2024/08/29 (木)



シークレットラブ(仮)のネタバレを含みます。

そろそろ5.4移行しようかな。

5.3で実用的な実装は網羅した気がするし、これ以上得られるモノが無さそう。

網羅したが故に改造箇所がバカ広いから移行が怠い。


幼馴染は大体むっつりでしょう。

なにをいまさらと思いましたが、その世界線しか知らん主人公さんは知らんのか。


わーお、クラッシャーだ。


紫だったのか。ピンクと見間違えた。

うちのモニター色味バカだし、ありえそう。


あーこりゃ確かに空中分解するわ。


普通に貴様を待っていたと言えばいいものを...

もどかしい!


この場合お前が遅れたから不機嫌という方が自然だろう、ボケが。

おっぱいが大きいお三方が朝から修羅場ですか。

胃もたれしそう。

おいこらミサミサって呼称やめろや。

お嬢様の登場まだ?!?!はやくきて!もっと修羅場しろ!

あー、やっぱ学年違うと無理か。

悲しい。


髪影落として、連翹さんの青色の目のテクスチャを拝借してと...

ふふん。どうよ。

えっち!

瞳はいつかプロシージャルな仕組みを作りたいですね。

D.C.アニメ版のような色塗りコストが安そうな見た目も好きではありますが、一番愛があるのは湊くんの瞳ですからね。

あの瞳だけは永遠と好きすぎる。


連翹さんの目、結構好きだなーと思ったら、色味が立夏さんと似ているんですね。

あとはリムライトと透かしにアウトラインを引く部分かな。

ルックデヴは息抜きに丁度いいですね。

技術的にも楽しいことやろうと思えば出来ますし、見た目として反映されるので、結果が分かりやすい。

描画エンジニアの楽しいところって結果が見て分かる部分もあると思うのです。

最適化フェーズにぶち当たると永遠とGPU時間の差分を睨めっこするのであれなんですけど。


寝間着姿の姫乃さんを眺めていたら髪陰の良い方法を思い付きました。

我ながら天才と思いつつ、実装コスト怠いなぁというジレンマ。

楽しいことで悩めるのは良い悩みです。


てかやっぱり、リムないよなぁ。アニメ版は。

それよかベースカラーでぼかしフィルタ&軽いブルームでキャラマスクしてシーンカラーに乗っける方が雰囲気出そう。

リム程度ならオブジェクトでもポストでも簡単に実装できるから後回しでいっか。

ちなみにブルームで代用できないかって思うでしょー。

のんのん。あやつはシーン全体に影響を及ぼすから、キャラからほわーって広がる感じが表現しにくいのですよ。

そのうち雑談編で画像載せますわー。たぶん。


さてと、そろそろおまけの技術ブログ書くか・・・

基本的なエンジン改造ってわざわざプライベートなリポジトリでもブランチ別けずに本体にぶち込んでるから地味に書き起こすの怠いんですよね。