C# を使った独自のカスタムパスのスクリプティング
Custom Pass API で CustomPass クラスを拡張し、1 つ以上のバッファを持つカスタムパスや、 コンピュートシェーダー を使ったカスタムパスなど、複雑なエフェクトを作成することができます。
Custom Pass C# テンプレート の説明に従って独自の C# カスタムパスを作成すると、それは、Custom Pass Volume コンポーネント内の利用可能なカスタムパスのリストに自動的に表示されます。
Custom Pass C# テンプレート
新しいカスタムパスを作成するには、Assets > Create > Rendering > C# Custom Pass へ移動します。これで、Custom Pass C# テンプレートを含む新たなスクリプトを作成できます。
class #SCRIPTNAME# : CustomPass
{
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) {}
protected override void Execute(CustomPassContext ctx) {}
protected override void Cleanup() {}
}
C# Custom Pass テンプレートには、独自のカスタムパスをコードする、次のエントリーポイントが含まれます:
エントリーポイント | 説明 |
---|---|
Setup |
これはテクスチャ、マテリアルのレンダリングやバッファの演算など、パスをレンダリングするのに必要なすべてのリソースを割り当てするために使います。 |
Execute |
これは HDRP がカスタムパス中に何をレンダリングするかを説明するために使います。 |
Cleanup |
これは設定方法で割り当てたリソースをクリアするために使います。メモリーリークを防ぐために、すべての割り当てられたリソースを含むようにしてください。 |
Setup
および Execute
法を使うと、 ScriptableRenderContext
並びに CommandBuffer
へのアクセスが可能になります。CommandBuffers
と ScriptableRenderContext
の併用に関する情報は、スクリプタブルレンダーパイプラインのレンダリングコマンドのスケジューリングと実行 を参照してください。
C# でフルスクリーンカスタムパスを作成
次のコードはアウトラインエフェクトをシーンのオブジェクトに適用するフルスクリーンカスタムパスの作成方法を紹介します。
このエフェクトは、透明なフルスクリーンパスに、スクリプトを割り当てるゲームオブジェクト周辺のピクセルを置き換えるブレンドモードを使っています。
このシェーダーコードは、以下のステップを踏みます。
- アウトラインレイヤーのオブジェクトを
outlineBuffer
と呼ばれるバッファにレンダリングします。 outlineBuffer
でカラーをサンプリングします。カラーがしきい値以下の場合は、ピクセルがアウトラインにある可能性を意味します。- 隣接するピクセルを検索し、確認します。
- Unity がしきい値以上のピクセルを見つけた場合は、アウトラインエフェクトに適用します。
CustomPass スクリプトの作成
CustomPass スクリプトを作成するには、以下を行います。
- Assets > Create > C# Script を使って新しい C# スクリプトを作成します。
- スクリプトに名前を付けます。この例では、新しいスクリプトは “Outline” と名付けられています。
- 次のコードを入力します。
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
class Outline : CustomPass
{
public LayerMask outlineLayer = 0;
[ColorUsage(false, true)]
public Color outlineColor = Color.black;
public float threshold = 1;
// シェーダーが参照するビルドにあることを確認するために、シェーダーへの参照を維持する
[SerializeField, HideInInspector]
Shader outlineShader;
Material fullscreenOutline;
RTHandle outlineBuffer;
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{
outlineShader = Shader.Find("Hidden/Outline");
fullscreenOutline = CoreUtils.CreateEngineMaterial(outlineShader);
// アウトラインバッファを定義する
outlineBuffer = RTHandles.Alloc(
Vector2.one, TextureXR.slices, dimension: TextureXR.dimension,
colorFormat: GraphicsFormat.B10G11R11_UFloatPack32,
// このエフェクトにアルファは必要ない
useDynamicScale: true, name: "Outline Buffer"
);
}
protected override void Execute(CustomPassContext ctx)
{
// アウトラインバッファでアウトラインエフェクトを適用したいメッシュをレンダリングする
CoreUtils.SetRenderTarget(ctx.cmd, outlineBuffer, ClearFlag.Color);
CustomPassUtils.DrawRenderers(ctx, outlineLayer);
// アウトラインエフェクトのプロパティーを設定する
ctx.propertyBlock.SetColor("_OutlineColor", outlineColor);
ctx.propertyBlock.SetTexture("_OutlineBuffer", outlineBuffer);
ctx.propertyBlock.SetFloat("_Threshold", threshold);
// アウトラインバッファフルスクリーンをレンダリングする
CoreUtils.SetRenderTarget(ctx.cmd, ctx.cameraColorBuffer, ClearFlag.None);
CoreUtils.DrawFullScreen(ctx.cmd, fullscreenOutline, ctx.propertyBlock, shaderPassId: 0);
}
protected override void Cleanup()
{
CoreUtils.Destroy(fullscreenOutline);
outlineBuffer.Release();
}
}
Unity シェーダーの作成
新しいシェーダーを作成するには、以下を行います。
- Assets> Create> Shader を使って、新しい Unity シェーダーを作成します。
- 新しいシェーダーソースファイルを “Outline” と名付けます。
- 次のコードを入力します。
Shader "Hidden/Outline"
{
HLSLINCLUDE
#pragma vertex Vert
#pragma target 4.5
#pragma only_renderers d3d11 playstation xboxone vulkan metal switch
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassCommon.hlsl"
TEXTURE2D_X(_OutlineBuffer);
float4 _OutlineColor;
float _Threshold;
#define v2 1.41421
#define c45 0.707107
#define c225 0.9238795
#define s225 0.3826834
#define MAXSAMPLES 8
// 隣接ピクセル位置
static float2 samplingPositions[MAXSAMPLES] =
{
float2( 1, 1),
float2( 0, 1),
float2(-1, 1),
float2(-1, 0),
float2(-1, -1),
float2( 0, -1),
float2( 1, -1),
float2( 1, 0),
};
float4 FullScreenPass(Varyings varyings) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(varyings);
float depth = LoadCameraDepth(varyings.positionCS.xy);
PositionInputs posInput = GetPositionInput(varyings.positionCS.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V);
float4 color = float4(0.0, 0.0, 0.0, 0.0);
float luminanceThreshold = max(0.000001, _Threshold * 0.01);
// レンダリング射出ポイントの前で実行しない場合は、カメラカラーバッファをミップ0で読み込む
if (_CustomPassInjectionPoint != CUSTOMPASSINJECTIONPOINT_BEFORE_RENDERING)
color = float4(CustomPassSampleCameraColor(posInput.positionNDC.xy, 0), 1);
// RTHandle テクスチャを散布するときには、常に _RTHandleScale.xy を使って UV をまずスケールする。
float2 uv = posInput.positionNDC.xy * _RTHandleScale.xy;
float4 outline = SAMPLE_TEXTURE2D_X_LOD(_OutlineBuffer, s_linear_clamp_sampler, uv, 0);
outline.a = 0;
// このサンプルがしきい値以下の場合
if (Luminance(outline.rgb) < luminanceThreshold)
{
// 隣接を検索する
for (int i = 0; i < MAXSAMPLES; i++)
{
float2 uvN = uv + _ScreenSize.zw * _RTHandleScale.xy * samplingPositions[i];
float4 neighbour = SAMPLE_TEXTURE2D_X_LOD(_OutlineBuffer, s_linear_clamp_sampler, uvN, 0);
if (Luminance(neighbour) > luminanceThreshold)
{
outline.rgb = _OutlineColor.rgb;
outline.a = 1;
break;
}
}
}
return outline;
}
ENDHLSL
SubShader
{
Pass
{
Name "Custom Pass 0"
ZWrite Off
ZTest Always
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
HLSLPROGRAM
#pragma fragment FullScreenPass
ENDHLSL
}
}
Fallback Off
}
C# Custom Pass 効果の使用
シェーダーで作成した効果を有効にするには、Full-screeen Custom Pas コンポーネントの FullScreen Material プロパティーに割り当てます。
コードを使った Custom Pass Volume コンポーネントの制御
CustomPassVolume
はスクリプトで GetComponent を使って取得でき、ほとんどのものには、isGlobal
、fadeRadius
並びに injectionPoint
のような UI からアクセスできます。
さらに実行されたカスタムパスのリストは、customPasses
リストを修正することで、動的に変更できます。
Custom Pass Volume コンポーネントのプロパティ―をスクリプティング
Inspector ウィンドウでカスタムパスのプロパティーをカスタマイズするには、 CustomPropertyDrawer の MonoBehaviour Editor と同じようなパターンを使うことができますが、属性は異なります。
次の例は、フルスクリーン Custom Pass ドロワーの一部です。
[CustomPassDrawerAttribute(typeof(FullScreenCustomPass))]
public class FullScreenCustomPassDrawer : CustomPassDrawer
{
protected override void Initialize(SerializedProperty customPass)
{
// パスで使うローカル SerializedProperty を開始する。
}
protected override void DoPassGUI(SerializedProperty customPass, Rect rect)
{
// `EditorGUI` 呼び出しを使ってカスタム GUI を描画する。Layout メソッドはここでは使えないので注意する。
}
protected override float GetPassHeight(SerializedProperty customPass)
{
// 上記 DoPassGUI メソッドで使った垂直ハイトをピクセルで返す。
// 動的になる場合がある。
return (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * X;
}
}
Custom Pass ドロワーを作成する際、Unity は Custom Pass プロパティーのデフォルトリストを提供します。Unity は DoPassGUI
が空であっても同様に行います。これらのプロパティーは、Unity が CustomPass Volume コンポーネントの Draw Renderers でデフォルトで提供するプロパティーと同じです。
これらの設定すべてが必要でなければ、commonPassUIFlags
プロパティーをオーバーライドし、いくつかを除去することができます。次の例は、名前およびターゲットバッファ enum のみを残しています。
protected override PassUIFlag commonPassUIFlags => PassUIFlag.Name | PassUIFlag.TargetColorBuffer;