こんにちは、Unityエンジニアのオオバです。

前回超基本編として Universal Render Pipeline(以下:URP) の拡張方法を紹介しました。

とても簡単にわかりやすく 紹介していますので、URP拡張に興味ある方はぜひ見てください。
導入としてちょうど良いと思います。

本記事と前回の違いは シェーダーを使っていること です。

【今回作るもの】不透明オブジェクトにシェーダーを適用するURP拡張

不透明オブジェクトにシェーダーを適用

不透明のオブジェクトだけにカラー乗算するというURPの描画拡張を作っていきます。

今回の本質はシェーダーを使ったURPの拡張のため、シェーダーの内容は超簡素です。

基本をおさえた上で難しいシェーダーを書いていきましょう。

👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

FeatureとPassの用意

URPを拡張する上ではおなじみの手順です。

それぞれScriptableRendererFeatureScriptableRenderPassを継承して作成します。

URP ForwardRendererのRenderer Featuresに追加します。

URP ForwardRendererに追加した状態

【超基本編】URPの拡張にシェーダーを使う方法_0

このあたり前回記事で丁寧に紹介していますので、そちらをご確認ください。

シェーダーの用意

💻ソースコード : HelloWorldShader.shaderの抜粋
fixed4 frag (v2f_img i) : SV_Target  
{
    return tex2D(_MainTex, i.uv) * _Color;  
}

各ピクセルを_Colorプロパティを乗算するシンプルなシェーダーです。

シェーダーの全ソースはコチラです。

※シェーダー全文は記事末尾に公開しています

このシェーダーファイルをFeatureにセットします。

💻ソースコード : HelloWorldShaderRendererFeature.cs
[SerializeField] private Shader _shader;  

Materialを生成してPassに渡す

FeatureとPassの関係を思い出しましょう。

FeatureとPassの関係図

【超基本編】URPの拡張にシェーダーを使う方法_1

FeatureはあくまでPassの生成器。
Passは描画処理担当です。

FeatureはPassにShaderをセットしたMaterialを渡します。

💻ソースコード : HelloWorldShaderRendererFeature.cs
public override void Create()  
{
    // ShaderからMaterialを生成  
    var material = CoreUtils.CreateEngineMaterial(_shader);  
    // PassにMaterialを渡す  
    _pass = new HelloWorldShaderPass(material);  
}

シェーダーからMaterialを作る時は、CoreUtils.CreateEngineMaterialメソッドが便利。再生終了時に自動でMaterialの破棄をしてくれます。

※動的に生成したMaterialは破棄しないとリークします

レンダーターゲットにシェーダーを適用

今回の肝、シェーダーの適用です。

描画のフローの流れ
  1. RenderTexture生成
  2. カメラ画像をRenderTextureにコピー
  3. RenderTextureをカメラ画像にコピー

2. カメラ画像をRenderTextureにコピーのタイミングでシェーダーを適用します。

💻ソースコード : HelloWorldShaderPass.cs Executeメソッド内
// カメラ画像をRenderTextureにコピー  
commandBuffer.Blit(_currentRenderTarget, RenderTargetTexId, _material);  

CommandBuffer Blitメソッドの第3引数にMaterialを渡すことでシェーダーは適用されます。

Blitメソッドの解説

【超基本編】URPの拡張にシェーダーを使う方法_2

CommandBuffer.Blitメソッドの各引数
※第1,2引数にはRenderTextureを直接セットしません。紐づくIDを指定する仕様です。

もっとわかりやすくした図はコチラ。

【超基本編】URPの拡張にシェーダーを使う方法_3

Blitメソッドをまとめると、元画像をコピーしてシェーダーを適用。シェーダーを適用したデータを書き出し画像に書き込みます。

↑これだけ覚えておきましょう。

_MainTexで元画像をシェーダーから参照

Blitメソッドの第1引数のカメラ画像はシェーダーからどのように参照すればよいでしょうか。

答え : シェーダー内で定義した、_MainTexという変数に格納されます。

このあたりはUnityの仕様です。

@ref:https://docs.unity3d.com/ja/2021.1/ScriptReference/Rendering.CommandBuffer.Blit.html

今回実装した画像処理を振り返ります。該当するシェーダー処理はコチラ。

💻ソースコード : HelloWorldShader.shaderの抜粋
fixed4 frag (v2f_img i) : SV_Target  
{
    return tex2D(_MainTex, i.uv) * _Color;  
}

_MainTex(カメラ画像)の各ピクセルを_Colorで乗算しています。

カメラに映し出された画像に指定の色で塗られる処理になります。

処理した画像をカメラに戻す

RenderTextureをいくら加工してもカメラ画像に戻さなければ見た目は変わりません。

シェーダー適用したRenderTextureをカメラに映し出す処理
// RenderTextureにシェーダーを適用  
commandBuffer.Blit(_currentRenderTarget, RenderTargetTexId, _material);  

// シェーダー適用したRenderTextureをカメラ画像にコピー  
commandBuffer.Blit(RenderTargetTexId, _currentRenderTarget);  

再度Blitメソッドが登場します。処理済み画像をカメラ画像にコピーしてモニタ上の見た目を更新します。

【超基本編】URPの拡張にシェーダーを使う方法_4

このように、シェーダーを適用したURP拡張ができました!

もう少し続けます。

シェーダーのパラメータを動的に更新する方法

URP拡張にシェーダーを適用できました。
このシェーダーのパラメータを動的に変えてみようと思います。

調整したいFeatureにColorパラメータをpublic変数として公開します。

public Color color;  

するとインスペクタからカラーを変更できるようになります。

HelloWorldShaderRenderFeatureのインスペクタ

【超基本編】URPの拡張にシェーダーを使う方法_5

図にするとこんなイメージです。

【超基本編】URPの拡張にシェーダーを使う方法_6

このcolorを毎フレーム更新することでリアルタイムに変更できます。

【超基本編】URPの拡張にシェーダーを使う方法_7

まとめ

シェーダーを使ったURPの拡張方法を紹介しました。

前回、今回記事を通して基本的なURPの拡張方法を理解できたかと思います。

おつかれさまでした。

次回から、より複雑な題材をテーマにURPの拡張をしていきたいと思います。

お楽しみに!

ソースコード全文はこちら

最後にサンプル全ソースを公開しておきます。
サンプルも内包されて分かりづらいですが、Assets/HelloWorldRendererFeatureSampleフォルダに今回のサンプルは入っています。

何か参考になれば幸いです。
GitHub - baobao/URP-HelloWorldRendererFeature

「Unity初心者大学」というUnity初心者向けのYouTube始めました!!
ぜひチャンネル登録をお願いします!

最後まで読んでいただきありがとうございました!
すばらしいURP拡張ライフをお過ごしください。

オススメ記事
検証環境
参考サイト