Unity2022 URP14 呟き独歩 その1

2023/12/16に公開

この記事の趣旨

Unity2022 LTSが約半年前に利用可能になった。描画パイプラインが大きく変化し、URP14は既存の描画処理から大きな変更が加わっているという。自分はURPの知見がURP10で止まっているため、そろそろ重い腰を上げて学ばないとな…と思う。

更新内容

2024/01/20 RTHandleの説明画像と一部説明を修正しました。

想定する対象読者

  • URPを気分で使用してきた人
  • 2,3年ほど昔のURPを触ってきた人

開発環境

  • Unity 2022.3.15(現時点 2023/12/15のUnity2022最新バージョン)
  • Universal RP 14.0.9

その1

風のうわさ程度の話では、RTHandleと呼ばれるハンドラーを用いてリソースを操作するらしい。今まではGetTemporaryRTSetRenderTargetなどのリソース割り当てやターゲット指定処理を羅列し、CommandBuffer.BlitでテクスチャコピーやShaderによる描画処理をスケジューリングしていたと思うが、どう変化しているのか。

RTHandle

The RTHandle system | Core RP Library | 14.0.9

RThandleはRenderTargetをハンドリングするもの、つまりRenderingのTargetや対象となるTextureを管理するもののようだ。確かに、メモリ管理は煩雑になりがちだし、書き込み先のミスによって描画されないといったことで時間を要したことも多々あった。

特にUnityが問題視しているのは、複数のカメラが存在しているときのようだ。

例えば、下図の場合、

RenderTextureはカメラごとに生成されるため、カメラ分だけメモリを圧迫してしまう。
また、下図のように、同一カメラのRenderPipeline内で解像度の異なる一時テクスチャを使用している場合、そのテクスチャはメモリ割り当ての対象となる。

これを解決するために、RTHandleが存在している。RTHandleがRenderTextureを管理することで、無駄のないメモリ管理をおこなってくれる。

RTHandleはRenderTexture APIを抽象化したもの

RTHandleの正体は、RenderTextureを管理する抽象レイヤーである。先程述べた、異なる解像度間の問題もRTHandleが解決してくれる。以下にRTHandleシステムの基礎を載せる。

RTHandleは、全画面を覆う解像度をもつRenderTexture1枚分のみをメモリに割り当て、そのRenderTextureを全てのカメラにおいて使いまわす

今までサイズ指定したRenderTextureをCommandBuffer.Blit呼び出し時にセットしていたが、そんなことはしなくてよくなった。すべてRTHandleが管理してくれる(嬉しい)。RenderTextureも複数カメラが存在していても全画面解像度1枚だけなので、メモリに優しい。

但し、特定解像度に対してレンダリングする場合は、「Reference Size」というものを設定する必要がある

まだよくわからないので一旦パス。なんとなくだが、全画面解像度1枚に色々書き込みをしていくので、解像度が変わったらその分書き込む位置がずれるよ、ということなのだと思う。

確保したRenderTextureよりも大きいサイズのテクスチャ確保が必要になった場合、全てのRenderTextureを内部的に再割り当てし、最大サイズに置き換える

確かにその必要があるとは思うが、この処理がどのくらいスパイクに繋がるかは気になる。

Reference Size

「Reference Size」というのがよくわからなかった。

Reference Sizeとは、現在確保している最大解像度を基準とした、確保したいRenderTextureの解像度である。これによって、割り当てのサイズを決定している。上記で述べた通り、現在の解像度よりも大きい場合(1920x1080 → 3840x2160の場合scale=2)は全てのテクスチャの再割り当てが実行される。

但し、RTHandleSystemを使用すると、固定サイズのテクスチャを割り当てることもできる。この場合、テクスチャの再割り当てをしないので、既存と同様の処理となる。

Unityのアップデートを考慮すると、RTHandleが管理するReference Sizeを用いたテクスチャ割り当てか、今まで同様固定サイズ指定割り当てか、どちらに対応するかが迫られる。恐らく素直にReference Sizeを用いたテクスチャ割り当てに作り直した方がよいのだろう。

今回はここまで。次回は実際にRTHandleの使用方法を見ていこうと思う。

おまけ: RenderGraph

2023/10/2にURPのRenderGraph対応が発表された。これに対応するとScriptable RenderPassのパフォーマンスを自動的に最適化してくれるようだ。Unity 2023.3.0a18以降のバージョンであれば動作が確認できる。

まずはマニュアル。RenderGraphの基礎について。

Render graph fundamentals | Core RP Library | 14.0.9

なんとなくだが、RenderGraphを使用することでリソースの扱いが効率的になり、メモリに優しくなるとのこと。

RenderGraphの実行は、

  • Setup(設定)
  • Compilation(編集)
  • Execution(実行)

から成り、

  • RenderPassと、そのパスが使用するリソースを宣言し
  • RenderGraphをコンパイルし
  • RenderGraphが宣言順にRenderPassを実行する

という流れになる。CompilationとExecutionでは、それぞれ実行しないロジックやパスをRenderGraphから排除する+パスごとにもう使用しないリソースは解放するなど、よしなに最適化をしてくれる。

RenderGraphは概念

RenderGraphはUnity独自の概念かと思っていたら、どうやらそうではないらしい。

2017年のGDCでYuriy O'Donnell氏が発表した ”FrameGraph: Extensible Rendering Architecture in Frostbite” が、RenderGraphの概念の先駆けとのこと。

今ではゲームエンジンのレンダリングシステムの主流になっているらしい(UEもRenderGraphの概念をもとにレンダリングシステムを構築しているっぽい)。
要するにRenderGraphは、描画命令処理やリソース管理を統括して扱うためのものである。
聞く限りRendererFeature, RenderPassもRenderGraphの概念の1つのようにも思ったが、そもそも記述の仕方が通常のSRPとは異なるため、これらの拡張法とは異なるのだろう。
ただ、RenderGraph APIはRTHandlesやComputeBuffers等リソース管理用ハンドルも操作するAPIであり、本当に統括して管理をするようだ。

ドキュメントにRenderPipelineの作成という欄があるが、これに触れると長くなりそうなので、URP14の全体の概要を掴むためにも一旦飛ばす。RTHandleとは何者なのかだけを先に知りたいのだ…

その2はこちら

https://zenn.dev/inpro/articles/1f23b92536a112

Discussion