🛠️

Universal Render Pipeline(URP)乗り換えハマりポイントまとめ

2021/02/19に公開

概要

Built-in Render PipelineからUniversal Render Pipeline(以下URP)への乗り換えでわかりにくかったところなどをまとめてみます

環境は、Unity2020.1.15f1 > Unity2020.2.3f1 + URP10.2.2です

インストール

とりあえずこちらのドキュメントに沿っていけばオッケーです
Installing the Universal Render Pipeline into an existing Project

ざっくり次のような感じです

  1. PostProcessing Stack v2を使ってたら削除
    URPにほぼ同様の機能が内包されているので事前に消しておく
  2. PacakgeManagerでURPをインストール
  3. 設定ファイルを作成
  4. Graphicsセッテイングで3.のファイルを指定

乗り換え

Unity組み込みシェーダーの置換

Upgrading your Shaders
かわりのシェーダーとマテリアルの変換コマンドが用意されています

OnRenderObject()内でCamera.current==nullになる

仕様のようです
RenderPipelineManager.beginCameraRenderingイベントでカメラを覚えておく方法で対応できます

Camera currentCamera;

void OnEnable()
{
    RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
}

void OnDisable()
{
    RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
}

void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera)
{
    currentCamera = camera;
}

void OnRenderObject()
{
    if ((currentCamera == null) || (currentCamera.cullingMask & (1 << gameObject.layer)) == 0)
    {
        return;
    }

    ~処理~
}

https://forum.unity.com/threads/camera-current-returns-null-when-calling-it-in-onwillrenderobject-with-universalrp.929880/

OnPreCull(),OnPreRender(),OnPostRender()非サポート

カメラにアタッチされているコンポーネント用のイベントが呼ばれなくなりました
シビアなケースでなければ上記OnRenderObject()のケース同様、RenderPipelineManagerのイベントで代用出来そうです

OnRenderImage()非サポート

カメラアタッチイベントなのでOnRenderImage()もサポートされなくなったのですが簡単な代用方法がなさそうです

Render Featureという自作のレンダリングパスを追加する機能があるので、これを利用するのがよさそうです

https://forum.unity.com/threads/replacing-onrenderimage-graphics-blit-in-urp.857278/

カメラを重ねる方法が変更

カメラの絵を重ねて描画する方法が変わっています
Built-in Render PipelineではカメラのCleaflags=Depth Only/Don't ClearにしてDepthの数値で処理順を調整して重ねていましたが、これらのパラメータがインスペクタ上に表示されなくなり設定出来なくなっています

URPではかわりにCamera Stacking機能を使います

上になるカメラのRenderTypeOverlayにして

下になるカメラ(RenderTypeBase)のStackに追加します

これで重ねて描画されます
Stackには複数登録でき、このリストの上から順に処理されます
いままでのDepth管理だと重なり順がわかりづらかったのでこれはいいですね

DepthバッファのクリアはOverlayにしたカメラのRendering > ClearDepthで指定できます

Shader乗り換え

UnityCG.cginc > Core.hlsl

UnityCG.cgincの代わりにCore.hlslをincludeします
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

CGPROGRAM > HLSLPROGRAM

CGPROGRAM / ENDCGではなくHLSLPROGRAM / ENDHLSLを使うのが推奨されています

そもそもこの違いは、HLSLSupport.cgincUnityShaderVariables.cgincが自動的にincludeされるかどうかだけのようです(前者だとされる)

これらのファイルで定義されている関数がURPの定義と衝突することがあるのでHLSLPROGRAM推奨とのことです

NOTE: HLSL language is the preferred language for URP shaders.
NOTE: URP supports the CG language. If you add the CGPROGRAM/ENDCGPROGRAM block in a shader, Unity includes shaders from the Built-in Render Pipeline library automatically. If you include shaders from the SRP shader library, some SRP shader macros and functions might conflict with the Built-in Render Pipeline shader functions. Shaders with the CGPROGRAM block are not SRP Batcher compatible.

https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@10.3/manual/writing-shaders-urp-basic-unlit-structure.html

ビルドイン関数名変更

Core.hlslでは、ビルトイン関数がなくなったり名前が変わっていたりします

UnityObjectToClipPos()がないのがよくひっかかるところかと思います

URPの座標系変換関数は次のファイルで定義されています(Core.hlsl経由でincludeされます)
Packages/com.unity.render-pipelines.universal/ShaderLibrary/SpaceTransforms.hlsl

float3 TransformObjectToWorld(float3 positionOS)
float3 TransformWorldToObject(float3 positionWS)
float3 TransformWorldToView(float3 positionWS)
float4 TransformObjectToHClip(float3 positionOS)

など

UnityObjectToClipPos()のかわりはTransformObjectToHClip()になります

とは言いつつ結構そのまま動く

手元の環境では特になにも書き換えなくてもそのまま動くシェーダーも結構多くありました
(ライティングまわりを全然触っていなかったからかな、という気もします)
乗り換え作業としては、エラーが出たところだけHLSLPROGRAM,Core.hlsl形式に書き換えていくというのも全然ありだと思います

GrabPass

*2023/04/03追記

GrabPassについての記事を書きました
https://zenn.dev/fuqunaga/articles/005cb0380d495e

複数Pass

*2023/04/07追記

SubShader内に複数のPassブロックを定義しておくと、特に明示してない場合は順番に実行されましたがURPでは1つしか動作しなくなっています

LightMode

Tags内でLightModeを使用することで複数パスに対応できます

Pass
{
    Tags{ "LightMode" = "SRPDefaultUnlit" } // デフォルトがSRPDefaultUnlitなので省略可
    
~略~

Pass
{
    Tags{ "LightMode" = "UniversalForward" }

LightModeで指定できる文字列はドキュメント参照

こちらは定義順ではなく現状SRPDefaultUnlitが先に実行されるようです
*以前は違ったみたいです

いっぽうで3つ以上のPassについてはサポートされず、正攻法としては次のようになるようです

  • シェーダーを分けてMeshRendererなどのコンポートネントで複数のマテリアルを指定する
  • RenderFeatureを自作する

https://stackoverflow.com/questions/72533739/unity-change-color-in-mesh-overlap-using-urp/72535318

https://forum.unity.com/threads/multipass-shaders-in-urp.864187/

Texture2DArray

*2024/01/11追記

次のようにシェーダーのマクロが変更されています

UNITY_DECLARE_TEX2DARRAY(_TexArray);
UNITY_SAMPLE_TEX2DARRAY(_TexArray, i.uv);

TEXTURE2D_ARRAY(_TexArray);
SAMPLER(sampler_TexArray);

SAMPLE_TEXTURE2D_ARRAY(_TexArray, sampler_TexArray, IN.uv.xy, _TexArrayIndex);

https://light11.hatenadiary.com/entry/2021/09/28/200848

機能比較表

公式にBuilt-in Render Pipelineとの比較表が公開されています
上記以外にもいろいろあるので乗り換えの際には一度目を通してみるのをおすすめします

https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@10.3/manual/universalrp-builtin-feature-comparison.html
https://docs.unity3d.com/ja/current/Manual/render-pipelines-feature-comparison.html
*2023/04/07 リンク先更新

個人的にはProjector非対応なのが痛いです
そのうち自前実装しなくちゃいけなくなりそうです

参考

http://tips.hecomi.com/entry/2019/10/27/152520
https://redhologerbera.hatenablog.com/entry/2022/01/27/193219

Discussion