[UE5] ポストプロセスでUser Scene Textureの使い方
はじめに
User Scene TextureはUE5.5で導入された比較的に新しい機能です。ポストプロセスマテリアルの一環で、User Scene Textureを用いて、複数のマテリアルを使ったマルチパスのエフェクトをより簡単に作成できるようになりました。
この機能についてEpic Gamesの公式ドキュメントがありますが、一部の設定の効果と使用方法の説明が少し曖昧な感じで、結局使用時は迷ってしまいました。
そのため、今回の記事は、いろいろな試みやソースコードのレビューを通してまとめた使用方法と簡単な使用例を紹介したいと思います。
実行環境
Unreal Engine 5.6.1
Windows 11 25H2
User Scene Textureの設定とHLSLでの使用
User Scene Textureは、ポストプロセスマテリアル内で作成・使用できる中間テクスチャというものです。まずは、User Scene Textureを使用する基本的な流れを説明したいと思います。
基本ワークフロー
デフォルト状態では、ポストプロセスマテリアルは入力データに対して何らかの計算を実行し、その結果はScene Textureを上書きして出力する仕組みとなります。User Scene Textureを使用することによって、ポストプロセスマテリアルはScene Textureに直接出力ではなく、別のテクスチャを作成して、Scene Textureと並行してレンダリングパイプラインを通します。
ポストプロセスマテリアルをUser Scene Textureに出力設定するには、マテリアルのDetailsタブ→Post Process Materialセクション→User Scene Texture でテクスチャ名を設定するだけで、マテリアルはUser Scene Texture出力に自動的に切り替え、設定した変数名でUser Scene Textureを保存します。
次に、User Scene Textureを使用したい時に、UserSceneTexture
ノードを作成して、Details→User Scene Textureで同じテクスチャ名を設定すると、保存したテクスチャは従来のSceneTexture
ノードと同様に使用できるようになります。
もちろん、テクスチャを使用するマテリアル(入力マテリアル)はレンダリングパイプラインでの位置はテクスチャを生成するマテリアル(出力マテリアル)より後にある必要があります。そのため入力マテリアルのBlendable Locationは出力マテリアルより後に配置するか、もしくは同じBlendable Locationの場合はBlendable Priorityで低い順位をつけるかを確認します。
テクスチャ出力に関する設定
User Scene Textureの解像度は入力テクスチャの解像度の分数(ダウンサンプル)または倍数(アップサンプル)に設定できます。マテリアルDetailsでUser Scene Textureすぐ下にあるUser Texture Divisor
とResolution Relative To Input
によって調整できます。
Resolution Relative To Inputは、User Scene Texture機能において一番誤解されやすい設定だと思います。名前からすると、解像度のスケーリング係数とかを入力すべきと考えそうが、ソースコードを確認すると、なんとここはFNameタイプのパラメータです。つまり、この欄では、ダウンサンプル・アップサンプル時の解像度の計算に基づいた、「ベース」になるテクスチャ名を指定するだけです。設定されていない(もしくはSceneColorに設定)の場合は、画面解像度(Screen Resolution)に基づくとなります。
実際のスケーリング倍数はUser Texture Divisorで設定されます。ここは正数でダウンサンプリング、負数でアップサンプリングとなります(整数値しか取れません)。例えば、指定された入力テクスチャの解像度は 2000 * 1000、User Texture Divisorは (2, 2)の場合、最終出力したUser Scene Textureの解像度は 1000 * 500となります。逆に (-2, -2) に設定すると、出力は 4000 * 2000です(但し、アップサンプル後の解像度は画面解像度に超えられません)。0, 1, -1いずれを設定なら入力テクスチャと同じ解像度で出力されます。
出力と入力テクスチャ解像度の関係
マテリアルインスタンスに関する
マテリアルインスタンスを作成して使用する場合、User Scene Textureの出力テクスチャ名を変更できます(元々Noneのままでも)。しかし、User Texture DivisorとResolution Relative To Inputは変更できません。
テクスチャ入力に関する設定
User Scene Textureを入力テクスチャとしてサンプリングする際にもFiltered
とClamped
の二つ設定があります。
Filteredを有効にすると、テクスチャの読み取り方法はpoint sampling(単点サンプリング)からbilinear sampling(双線形補間)に変わります。処理速度は少し遅くなりますが、ダウンサンプル・アップサンプルする際にピクセル化や、エイリアシングを軽減するのに役立ちます。
一方、特定のエフェクトを得るために、あえてFilteredをオフにする場合もあります。例えば、Scene Textureをダウンサンプルして、そのまま単点サンプルでフル解像度出力すると、ドット絵スタイルを簡単に実現できます。
Clampedは、[Filtered ON + ダウンサンプル]の場合に使用するべき、サンプリングのUVがテクスチャの実際範囲内に制限する設定です。推測に過ぎませんが、多分Unreal Engineはダウンサンプルする前に、エイリアシングを軽減するためにテクスチャをぼかし処理します。そのため、ぼかし計算中にテクスチャ外側にあるランダムなピクセルが計算に入れないよう、UV値をclampすることが必要となるかもしれません。
マテリアルインスタンスに関する
マテリアルインスタンス内で、入力テクスチャを別のテクスチャ名に指定できますが、サンプリング設定は変更できません。
HLSL(Custom ノード)での使い方
User Scene Texture機能の導入とともに、UE5.5はHLSLコードにおけるScene Textureサンプリングの効率化ための新関数:SceneTextureFetch()
を追加しました。ソースコードを見ると、この関数の基本は既存のGetDefaultSceneTextureUV()
と SceneTextureLookup()
両関数のラッパー関数であることがわかります。
SceneTextureFetch()
二つ目のパラメータはUVではなく、ピクセル単位のオフセット値です。オフセットを指定すると、ラッパー内で対応するUVを自動計算します。前に必要であった流れ、GetDefaultSceneTextureUV()
で現在ピクセルのUV値を取得 ->(オフセットがある場合)Texel Sizeに基づいてオフセットUVを計算 -> SceneTextureLookup()
でサンプリング と比べるとだいぶ短縮されます。
// Sample without offset
float4 Sample = SceneTextureFetch(UserTexName.ID, float2(0.0f, 0.0f));
// Sample with offset
float4 Sample = SceneTextureFetch(UserTexName.ID, + float2(1.0f, 1.0f));
float4 Sample = SceneTextureFetch(UserTexName.ID, - float2(0.5f, 0.0f));
ただし、この便利な新関数も制限があります。従来のSceneTextureLookup()
では、最後のboolパラメータでサンプリング方法(false
-> point sampling; true
-> bilinear sampling)を切り替えられますが、このラッパーではtrueに固定されて、設定不可となります。つまり、SceneTextureFetch()
を通したテクスチャサンプリングは全部bilinear方法のものです。大体の場合は問題ありませんが、前に述べたように、ドット絵スタイルなど意図的にbilinear filterを使用したい際に、従来の方法を使用する必要があります。
float2 UV = GetDefaultSceneTextureUV(Parameters, UserTexName.ID);
float2 Offset = float2(1.0f, 1.0f);
float2 OffsetUV = UV + Offset * InvSize; // InvSize: texel size
OffsetUV = saturate(OffsetUV); // Clamp
// Filtered = false is not available through SceneTextureFetch()
float4 Sample = SceneTextureLookup(OffsetUV, UserTexName.ID, false);
活用方法
次はUser Scene Textureの活用方法を簡単に紹介したいと思います。
Demo用レベル:Medieval Banquet Asset Pack - Quixel
ダウンサンプリング
フル解像度のScene Textureの代わりに、ダウンサンプルされたUser Scene Textureを使用することで、演算回数を大幅に削減し、一部のポストプロセスエフェクトのパフォーマンスを向上させることができます。特に、ローパスフィルタ(ガウスぼかしなど)はダウンサンプルによる低解像度の影響を受けにくいため、この方法にもっとも適しています。
実証として、意図的に効率の悪いアルゴリズムでガウスぼかしエフェクトを実装して、フル解像度、2x、4xダウンサンプル時の結果を確認しました。ご覧のように、ぼかし効果は保ちつつ、fpsは著しく改善したことがわかります。
フル解像度
2x ダウンサンプル
4x ダウンサンプル
複数テクスチャの合成
従来は、前のマテリアルがScene Textureに出力して、次のマテリアルがScene Textureを読み取る形でマテリアルを繋がって、マルチパスのポストプロセスエフェクトを作成してきます。しかし、これでマテリアルは一回一つしか処理できません。User Scene Textureを使用すると、線形のフローに制限されず、一つマテリアルで保存した複数のテクスチャを同時にサンプリングできるようになります。
複数のUser Scene Textureをlerpして最終の画面を合成する
おわりに
今回はUnreal EngineのUser Scene Textureについて紹介しました。この機能によって複雑なビジュアル表現がより簡単で作成できて、マルチパスエフェクトの管理も容易になると思いますので、ぜひUser Scene Textureを使ってみてください。
Discussion