【UE5】シェーディングモデルを追加してみた – Unreal Engine 5.5

Unreal Engine
目次
  1. 水ノ茉の宣伝
  2. 始まり
  3. シェーディングモデルとは?
  4. エンジン改造とは?
    1. 前髪を透かしたり
    2. 毛先まで綺麗に表現できるポストプロセスなアウトラインを描いたり
    3. キャラと背景を別々のシャドウマップに書き込んでセルフシャドウを抑制したり
    4. 髪影を落としたり
    5. 頂点IDノードを追加して、それを元に鼻に線を引いたり
    6. 独自のトゥーンパス群ですべて描いたり
  5. Substrate (旧: Strata) 非対応
  6. レイトレース、パストレースなどは非対応
  7. リポジトリ
  8. 実装
    1. Engine/Shaders/Private/DeferredLightPixelShaders.usf
    2. Engine/Shaders/Private/Definitions.usf
    3. Engine/Shaders/Private/PostProcessGBufferHints.usf
    4. Engine/Shaders/Private/ReflectionEnvironmentPixelShader.usf
    5. Engine/Shaders/Private/ShadingCommon.ush
    6. Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp
    7. Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.cpp
    8. Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.h
    9. Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h
    10. Engine/Source/Runtime/Engine/Classes/Materials/MaterialExpressionShadingModel.h
    11. Engine/Source/Runtime/Engine/Private/Materials/HLSLMaterialTranslator.cpp
    12. Engine/Source/Runtime/Engine/Private/Materials/MaterialHLSLEmitter.cpp
    13. Engine/Source/Runtime/Engine/Private/Materials/MaterialIRToHLSLTranslator.cpp
    14. Engine/Source/Runtime/Engine/Private/Materials/MaterialShader.cpp
    15. Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderGenerationUtil.cpp
    16. Engine/Source/Runtime/RenderCore/Private/ShaderCore.cpp
    17. Engine/Source/Runtime/RenderCore/Public/ShaderCore.h
    18. Engine/Source/Runtime/RenderCore/Public/ShaderMaterial.h
  9. おわり!!!
  10. 関連するエンジン改造
  11. Ci-enを始めたのよさ
  12. えっちなソフボの公開計画を企む

水ノ茉の宣伝

準備中...
ゲームを作る予定なの
水ノ茉こおり

始まり

シェーディングモデルを追加するエンジン改造をしていきます。

シェーディングモデルとは?

シェーダーです。

シェーディングモデルとライティング関数が紐付けされているので、独自のライティングをしたい場合は、シェーディングモデルを追加する必要があります。

エンジン改造とは?

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

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

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

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

前髪を透かしたり

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

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

髪影を落としたり

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

独自のトゥーンパス群ですべて描いたり

Substrate (旧: Strata) 非対応

セル・トゥーンのルック開発で超現実的なライティング計算をサポートしたSubstrateを併用するケースが無さ過ぎるので、当然の如く非対応です。少なくとも筆者はこれまで一度も遭遇したことないです。尚5.7からは対応する予定です。

レイトレース、パストレースなどは非対応

セル・トゥーンのルック開発でレイトレやパストレースを使うこともハード性能次第では稀にありますが、あまりにも商用的な内容のため非対応(非公開)です。

リポジトリ

実装

ToonLitというシェーディングモデルを追加していきます。

基本的にはUnlitと同じ振る舞いで、差分としてGBufferを書き込みます。

Engine/Shaders/Private/DeferredLightPixelShaders.usf

Unlitと同じ扱いなのでディファードライティングできないようにします。

githubで実装を見る(L343)

Engine/Shaders/Private/Definitions.usf

HLSLMaterialTranslator/Emitter.cppでToonLitを使用している場合は定義が立てられますが、それ以外は未定義状態です。

使用箇所の全てで#if definedをするのも面倒なので、未定義の場合は#define MATERIAL_SHADINGMODEL_TOON_LIT 0となるようにしています。

githubで実装を見る(L113-L115)

Engine/Shaders/Private/PostProcessGBufferHints.usf

マウスカーソルの位置のGバッファを可視化するデバッグ機能のToonLitの対応です。

デバッグ機能はr.PostProcessing.GBufferPicking 1で有効化されます。

githubで実装を見る(L149)

Engine/Shaders/Private/ReflectionEnvironmentPixelShader.usf

Unlitと同様に環境光(反射とか)の適用を無効にしています。

githubで実装を見る(L525-L529)

Engine/Shaders/Private/ShadingCommon.ush

ToonLitの定義です。ナンバリングはEngineTypes.hと同じにしてください。

今回から#if 0で隠さずに#undefで打ち消す形に変更しました。この方がWinMergeする時に差分が分かりやすいんですよね。

githubで実装を見る(L35-L37)

ToonLitのシェーディングモデルカラーを設定しています。

主にデバッグで使用する際に呼ばれる関数です。

適当に黄色っぽくしています。

他のシェーディングモデルと被らなければ好きな色に変えて大丈夫です。

githubで実装を見る(L71)

githubで実装を見る(L91)

Engine/Source/Editor/PixelInspector/Private/PixelInspectorDetailsCustomization.cpp

PixelInspectorの対応です。

githubで実装を見る(L168)

Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.cpp

PixelInspectorの対応です。

githubで実装を見る(L271-L272)

githubで実装を見る(L321)

Engine/Source/Editor/PixelInspector/Private/PixelInspectorResult.h

PixelInspectorの対応です。

githubで実装を見る(L29)

Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h

シェーディングモデルの列挙体に追加しています。

DisplayNameがリストボックスの表示名に、/** ~~~ */がカーソルを合わせた際の説明表記・ツールチップに該当します。

githubで実装を見る(L668-L669)

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

5.3 ~ 5.4までは形骸的に対応していましたが、今回からは非対応とします。

ToonLitは単独で動作させる前提なのでMakeMaterialAttributesなどを使う機会がなさ過ぎました。

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

シェーディングモデルにToonLitが含まれるマテリアルは、シェーダー側に#define MATERIAL_SHADINGMODEL_TOON_LIT 1が定義されるようにしている箇所です。要はバリエーションです。

githubで実装を見る(L2826-L2829)

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

HLSLMaterialTranslatorと同様です。

HLSLMaterialTranslatorの前身がMaterialHLSLEmitterという感じです。

ちなみに5.6でMaterialHLSLEmitter.cppは削除され、HLSLMaterialTranslator.cppに一本化されます。

githubで実装を見る(L612-L616)

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

5.5から追加されたファイルです。

シェーディングモデルに紐づくバリエーション名を返す関数です。

githubで実装を見る(L193)

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

シェーディングモデルを文字列で返す関数です。

githubで実装を見る(L139)

stat ShaderCompilingで表示できる統計情報にToonLitを追加しています。

有効利用できた試しがないので次期の5.6では対応しないかもです。

githubで実装を見る(L564-L567)

Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderGenerationUtil.cpp

FShaderCompilerEnvironmentMATERIAL_SHADINGMODEL_TOON_LITが含まれる場合は、その結果をFShaderMaterialPropertyDefinesに伝播しています。

githubで実装を見る(L136)

SetSlotsForShadingModelType関数は呼び出し箇所が存在しないので形骸的な対応です。

githubで実装を見る(L1752-L1754)

ToonLitが書き込み先として使用するGバッファのスロットを指定している箇所です。

この実装を見ると分かりますが、UnlitはGバッファに書き込む値がゼロ値なだけで、書き込み自体は発生しているんですよね。

githubで実装を見る(L1907-L1910)

こんな感じに少し書き換えるだけで、UnlitでもGバッファに値を格納できるんですよね。

Engine/Source/Runtime/RenderCore/Private/ShaderCore.cpp

stat ShaderCompilingの対応です。

githubで実装を見る(L162)

Engine/Source/Runtime/RenderCore/Public/ShaderCore.h

stat ShaderCompilingの対応です。

githubで実装を見る(L119)

Engine/Source/Runtime/RenderCore/Public/ShaderMaterial.h

変数定義です。

githubで実装を見る(L111)

おわり!!!

描画まわりのエンジン改造の基礎、入門と言っても過言ではないシェーディングモデルの追加でした。

実はシェーダーの対応をサボっちゃえば大したことない変更量なんですよね。

関連するエンジン改造

Ci-enを始めたのよさ

主に体験版の配布先として利用予定で始めました。

かふえすプロフィール - Ci-en(シエン)
かふえすのプロフィールです。水ノ茉(こおり)のなかのひと。|最新の記事は「ソフトボディシミュの開発が楽しすぎてえっちなゲームを作りたい気分になったの」です。 - Ci-en(シエン)

来年のどこかで公開予定です。

いまは絶賛モックの作成中なのです。

それにしてもインゲーム開発の面白みはイマイチ分かりませんね。

ライブラリ開発は楽しいんだけど。

相性の問題でしょう。

えっちなソフボの公開計画を企む

すぐにでも公開という名の自慢をしたいのですが、GPGPUという性質上、実装を隠蔽するのがかなり難しいんですよね。

ランタイム実装を隠すことは簡単なのですが、シェーダーは各種デバッグオプションを有効化した状態でGPUキャプチャされると、一瞬でリバースエンジニアリングが出来ちゃいます。倫理観的にするなよとは思いつつも、他者に倫理を求めたところで期待は出来ません。対策するしか手はないのです。

普通に隠蔽せずに公開すれば済む話ではあるんですが、商業転用できそうな技術を完全なオープンは微妙に抵抗があるんですよね。

自己顕示欲と独占欲に揺れる日々です。

そんなしょうもないことで悩んでいる私を横目に、今日も今日とて、ソフボはえっちなのです。