関連ブログ
- [UE4][UE5]開発環境の容量を少しでも減らす 2024.08.14UE
- [UE5] PushModel型のReplicationを使い、ネットワーク最適化を図る 2024.05.29UE
- [UE5]マテリアルでメッシュをスケールする方法 2024.01.17UE
CATEGORY
2019.07.31UE4UE/ Editor拡張
執筆バージョン: Unreal Engine 4.22 |
こんにちは、エンジニアの小倉です。
前回に引き続き、エディタ拡張などで使える、描画内容をカスタムしたViewportの作り方を前後編にわけて紹介します。
上記画像は、前回と今回の記事で紹介する方法で得られる最終結果となります。
① ViewportClientとCanvas
② ShaderとRHI <= イマココ!
Rendererとは
Renderer用モジュールを作成する
Shaderを作成する
頂点データを作成する
Rendererを作成する
Rendererを使用する
参考記事
ソースコード
ここでは、描画を行うための一連の処理をまとめたものをRendererと呼ぶこととします。
Rendererの大まかな処理の流れは次のようになります。
この手順に沿って描画を行うためには、Shaderや頂点バッファなどを事前に作成する必要があります。
順に紹介していきます。
RenderTestプラグインにSimpleRenderという新しいモジュールを追加します。
SimpleRenderer.Build.csは基本的なモジュールに加えて、”RenderCore“、”Projects“、”RHI“を追加します。
StartupModule関数に、Shaderファイルへのパスを設定する記述を追加します。
以下のようにAddShaderSourceDirectoryMapping関数を用いると、プラグイン直下のShadersフォルダに配置した.usfファイルを参照することができるようになります。
最後に、RenderTest.upluginにSimpleRendererモジュールを追加します。
Shaderを扱うため、LoadingPhaseはPostConfigInitにします。
Shaderを開発する前に、Engine/Config/ConsoleVariables.ini のr.ShaderDevelopmentMode=1のコメントアウトを外します。
これによりShader開発における問題(例えば文法エラーなど)があるときに原因を特定しやすくなります。
参考:https://www.unrealengine.com/ja/tech-blog/debugging-the-shader-compiling-process
次に、Shadersフォルダ内にShaderを追加します。ここではファイル名をSimpleShader.usfとしました。
MainVSがVertex Shaderのエントリポイント、MainPSがPixel Shaderのエントリポイントです。
Vertex Shaderでは、頂点データからAttribute0セマンティクスによってスクリーン座標を受け取り、Attribute1セマンティクスによって頂点カラーを受け取ります。それをSV_POSITIONとCOLOR0セマンティクスの出力にそのまま渡し、Pixel Shaderではラスタライザで処理された頂点カラーを出力します。
参考:https://api.unrealengine.com/JPN/Programming/Rendering/ShaderInPlugin/Overview/index.html
次に、FGlobalShaderを継承してSahderクラスを作成します。
まず、Vertex ShaderとPixel Shader共通のFGlobalShader継承クラスであるFSimpleShaderを作成します(6行目)。
ShaderクラスはShouldCompiledPermutation関数を定義する必要があります。これはプラットフォームごとにShaderをキャッシュするかどうかを決定するために使われます(14行目)。
次に、Vertex ShaderのShaderクラスとしてFSimpleShaderVSを作成します(20行目)。
同様に、Pixel ShaderのShaderクラスとしてFSimpleShaderPSを作成します(32行目)。
最後に、IMPLEMENT_SHADER_TYPEマクロを使って、ShaderクラスとSimpleShader.usfへのパス、Shaderのエントリポイントと
Shader Stage(ここではVertex ShaderかPixel Shaderか)を設定します。
ここではVertex Buffer、Vertex Declaration、Index Bufferの3つを作成します。
まず、Vertex Bufferを作成します。
Vertex Shaderは頂点データからスクリーン座標と頂点カラーを受け取るため、座標(FVector2D)と色(FVector4)を持つ単一の頂点データとしてFColorVertexを作成します(5~8行目)。
次に、FVertexBufferを継承したFSimpleVertexBufferを作成します(10行目)。ここでは、InitRHIでVertex Bufferが持つ頂点データ本体を作成します。ここでは単純な三角形を描くので、三角形の端点のスクリーン座標と色を頂点データとして与えます(13行目~29行目)。
最後に、TGlobalResourceテンプレートでFSimpleVertextBufferを静的なリソースとして宣言します(32行目)。静的なリソースとして宣言されたGSimpleVertexBufferは、このSimpleShader.cppファイル内で参照することができます。
次に、Vertex Declarationを作成します。
Vertex Declarationは、Vertex Shaderに与える頂点データの形式を設定します。例えば12行目は、STRUCT_OFFSETマクロによって取得したFColorVertexのColorメンバのバイトオフセットから、Float2だけAttribute1に割り当てるといったようになります。
最後に、Index Bufferを作成します。
Index Bufferは頂点データにインデックスを付与し、そのインデックスを用いてプリミティブを構築することで、頂点を再利用するために用います。ここでは三角形を描くだけなので、頂点の再利用を考慮する必要はありません。Indicesは0、1、2だけになります(8行目)。
Rendererに必要なものが準備できたので、FSimpleRendererというRendererを作成します。
Render関数は、Render Targetを引数に受け取り、そのRender Targetに対して三角形の描画を行います。
ENQUEUE_RENDER_COMMANDマクロは、ドローコマンドを発行するためのタスクを追加(Enqueue)します。ここで追加されたタスクは、Game Threadから1または2フレーム遅延してRender Thread上で実行されます(16行目)。
このタスクのラムダ式にはRHICmdListがパラメータとして与えられており、これを介してドローコマンドを発行します。
DrawTestShaderRenderTarget_RenderThread関数は次のように実装しました。
FRHIRenderPassInfoによって、描画対象とするRender Targetを指定します(13行目)。
GlobalShaderMap関数によってFSimpleShaderVSとFSimpleShaderPSを取得します(17~19行目)。
Graphics Pipline Stateを設定します(22~31行目)。ここでは、デプス・ステンシルテストや、ブレンドなどの設定をします。
BoundShaderStateには、Vertext DeclarationやVertex Shader・Pixel Shaderを設定します(28~30行目)。
SetViewport関数によってビューポートを設定します(34~36行目)。
SetStreamSource関数によって頂点データをデータストリームに設定します(39行目)。
DrawIndexedPrimitive関数によってドローコマンドを発行します。ここでIndex Bufferを与えます(41~48行目)。
これでRendererに必要な処理は一通り実装できました。
Rendererを使用するために、RenderTestモジュール側からSimpleRendererモジュールを使えるようにする必要があります。
まず、RenderTest.Build.csにSimpleRendererモジュールを追加します。
次に、RenderTestViewportClientのDraw関数にSimpleRendererによる描画処理を追加します。
これを実行すると、次のようになります。
SimpleRendererによって描画された三角形をビューポートに表示することができました。
https://api.unrealengine.com/JPN/Programming/Rendering/ShaderInPlugin/index.html
https://zhuanlan.zhihu.com/p/66514192