こんにちは、Unityエンジニアのオオバです。
Universal Render Pipeline(以下:URP)は
描画処理(パス)をカンタンに追加することができます。
やってみたいけど、、、
始め方が分からない。
そういう人結構いるんじゃないかなって思います。
今回オオバ的に最小コードで
URPの描画拡張を作ってみました。
URPの拡張をこれからやっていきたい人に向けて
わかりやすく紹介していきたいと思います。

解像度を徐々に下げていく、
モザイクのような表現を作っていこうと思います。
→11万文字で徹底解説した「DOTweenの教科書」Unityアニメーションの超効率化ツールはこちら
1.PassとFeatureを作成
まずURPを拡張する上で2つのクラスを紹介します。
ScriptableRenderPass
とScriptableRendererFeature
。
クラス名 | 説明 |
---|---|
ScriptableRenderPass | 実際の描画処理 |
ScriptableRendererFeature | URPへの追加機能単位 |
これらのクラスを継承したクラスを作ります。
DownSamplingRenderPass
DownSamplingRenderFeature
Passは描画処理
💻ソースコード : DownSamplingRenderPass.cs抜粋
public class DownSamplingRenderPass : ScriptableRenderPass
{
public override void Execute(ScriptableRenderContext context,
ref RenderingData renderingData)
{
// 描画処理を記述
}
/// <summary>Constructor</summary>
public DownSamplingRenderPass() =>
renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
}
Executeメソッド
内に描画の処理を記述します。
Passの処理タイミングは決まっている
先のソースコードでrenderPassEvent
が登場しました。
renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
Enum RenderPassEvent
にはさまざまな
描画タイミングが定義されています。
RenderPassEvent
をPassにセットすることで、
指定のタイミングで描画処理を走らせることができるのです。
今回はAfterRenderingTransparents
なので、
「透明オブジェクトを描画した後に実行」という意味になります。
FeatureはURP拡張の最小単位
💻ソースコード : DownSamplingRenderFeature.cs抜粋
public class DownSamplingRenderFeature : ScriptableRendererFeature
{
DownSamplingRenderPass _renderPass;
public override void Create() =>
// Passの作成
_renderPass = new DownSamplingRenderPass();
public override void AddRenderPasses(
ScriptableRenderer renderer, ref RenderingData renderingData)
{
// ScriptableRendererにPassを渡す
renderer.EnqueuePass(_renderPass);
}
}
Featureクラスの仕事は2つあります。
- Passの生成処理
- Passを
ScriptableRenderer
に渡す
つまりFeatureとPassの関係は以下です。

Featureは複数のパスを管理することができます。
2.Featureの適用
作成したFeatureを適用するため、
Rendererに登録していきます。

URPのForwardRendererに
Featureを追加していきます。

Add Renderer Feature をクリックして、
作成したDown Sampling Render Feature
を追加します。

するとFeatureはRendererに適用されます。
モザイク処理の解説
実際の描画処理はPassです。
前述のとおり、描画処理はPassのExecuteに記述します。
// CommandBuffer作成(描画コマンドです)
var commandBuffer = CommandBufferPool.Get(CommandBufferName);
var cameraData = renderingData.cameraData;
// 現在描画しているカメラの解像度を`_downSample`で除算
var w = cameraData.camera.scaledPixelWidth / _downSample;
var h = cameraData.camera.scaledPixelHeight / _downSample;
// RenderTextureを生成
commandBuffer.GetTemporaryRT(RenderTextureId,
w, h, 0, FilterMode.Point, RenderTextureFormat.Default);
// 現在のカメラ描画画像をRenderTextureにコピー
commandBuffer.Blit(_currentTarget, RenderTextureId);
// RenderTextureを現在のRenderTarget(カメラ)にコピーしてモニタに写す
commandBuffer.Blit(RenderTextureId, _currentTarget);

- 小さいサイズのRenderTextureを生成
- カメラが写している画像をRenderTextureにコピー
- 小さいサイズのRenderTextureを元のカメラのサイズにコピー
一度解像度を小さくしているため、
元のサイズに戻すとモザイク状態になるという仕組みです。
CommandBufferでさまざまな処理をさせる
CommandBufferは描画コマンドの単位で、
描画処理を作っていく上で必要な存在です。
CommandBufferに処理を詰め込み、
GPUにわたすことで描画処理が実行されます。
GetTemporaryRTメソッド
: 一時利用のRenderTextureの生成Blitメソッド
: RenderTextureの内容を転送(コピー)
他にもたくさんの処理が定義されています。
↑今回はこの2つを使っています。
PassのExecute前にパラメータを渡す
PassにSetParamメソッド
を定義して
描画前にFeatureからパラメータを渡しています。
💻ソースコード : DownSamplingRenderPass.csの抜粋
public override void AddRenderPasses(
ScriptableRenderer renderer, ref RenderingData renderingData)
{
// 描画処理前にパラメータをPassに渡す
_renderPass.SetParam(renderer.cameraColorTarget, downSample);
renderer.EnqueuePass(_renderPass);
}
- カメラ情報
- ダウンサンプル値
この2つをPassの描画処理前に渡します。
カメラ情報とはカメラが写している画像情報 です。
ダウンサンプル値は
モザイク表現するための値です。
この値を毎フレーム変化させることで
モザイクアニメーションを表現しています。
描画前のPassに対してFeatureからパラメータを渡す。
この手順は今後も出てくると思うので、
覚えておきましょう。
3.モザイクの大きさをアニメーションさせる
FeatureはScriptableObject
です。

再生中に調整したいパラメータを定義しておき、
スクリプトから変更することが可能です

パラメータを更新することで
アニメーション表現を作れます。
public class DownSampleAnimation : MonoBehaviour
{
// Featureの参照を保持
[SerializeField] private DownSamplingRenderFeature _feature;
void Update()
{
var tmp = (Mathf.Sin(Time.frameCount * Mathf.PI / 180f) + 1f) / 2f;
// ダウンサンプリング最小1/120のサイズまで適用
var value = tmp * 120f;
// Featureのパラメータを更新
_feature.downSample = (int)value;
}
}
するとこのようなこのようなアニメーションが作成できます。

ゲームの状態によるパラメータ調整ってよくありますよね。
ダメージを受けたら画面を赤くするとか。
そういう処理もURPの拡張を使えば
わかりやすく実装できそうです。
FrameDebuggerで描画タイミングを確認
最後に描画処理のデバッグ、確認方法の紹介です。
Window > Analysis > Frame Debugger
で
Frame Debuggerを使うと描画タイミングを確認できます。

FrameDebuggerの Enableボタン をクリック。

すると
DownSamplingRenderPass
がFrame Debuggerに表示されます。
DrawTransparentObjects
(透明オブジェクトの描画)の後に
実行されていることが分かります。
意図通りですね。
まとめ
URPの拡張を最小コードで紹介してきました。
- Feature、Passの作成
- Featureの中でPassを生成
- 描画前にFeatureからPassにパラメータを渡す
- PassのExecuteに描画処理を書く
- FeatureをRendererに登録
5ステップで大まかな描画の流れは実装できます。
Frame Debugger
を使うことで
意図したタイミングで処理が走っているか
確認可能です。
次回はシェーダーを使ってURPを
拡張していこうと思います。
全ソースコードはこちら
最後にサンプル全ソースを公開しておきます。
サンプルも内包されて分かりづらいですが、
Assets/DownSamplingフォルダ
に
今回のサンプルは入っています。
何か参考になれば幸いです。
GitHub - baobao/URP-DownSamplingSample

この記事が気に入ったらフォローしよう
「Unity初心者大学」というUnity初心者向けのYouTube始めました!!
ぜひチャンネル登録をお願いします!
最後まで読んでいただきありがとうございました!
すばらしいURP拡張ライフをお過ごしください。
- Unity2021.16.f1
- URP v11.0.0