カスタムポストプロセス
HD レンダーパイプライン (HDRP) では、Volume に自動統合する独自のポストプロセスを書くことができます。カスタムエフェクトには C# Custom Post Process (C# ファイル) および関連する FullScreen Shader (HLSL ファイル) の 2 つのファイルが必要です。それぞれのテンプレートの生成は、以下の手順で行えます。
C# Custom Post Process: アセットフォルダーで右クリックし、Create > Rendering > C# Post Process Volume を選択します。
FullScreen Shader: アセットフォルダーで右クリックし、Create > Shader > HDRP > Post Process を選択します。
デフォルトにより、Volume に追加するだけではカスタムエフェクトは作動しませんので、注意してください。エフェクトをプロジェクトがサポートするエフェクトのリストにも追加する必要があります (エフェクトの順序付けに使うのと同じリストです。後述のエフェクトの順序のセクションを参照してください)。
例
この例では、GrayScale エフェクトの作成方法を説明します。
C# Custom Post Process ファイル (アセットフォルダーで右クリック: Create > Rendering > C# Post Process Volume) を作成し、GrayScale と命名します。Unity のシリアル化の仕組みにより、ファイル名とクラス名が一致しないと、Unity が正しくシリアル化できませんのでご留意ください。
コード例を GrayScale C# スクリプトセクション から C# Post Process Volume にコピーします。
フルスクリーンポストプロセスシェーダー (Assets フォルダーを右クリック: Create > Shader > HDRP > Post Process) を作成し、GrayScale と命名します。
コード例を GrayScale シェーダーセクション からポストプロセスシェーダーにコピーします。
プロジェクトが実行するカスタムポストプロセスのリストに GrayScale エフェクトを追加します。これは、Edit > Project Settings > HDRP Default Settings に行き、After Post Process リストの一番下で、 + をクリックしてGrayScale を選択して行います。
これでシーンで GrayScale ポストプロセスオーバーライドを Volumes に追加できるようになります。エフェクト設定の変更は、折り畳み矢印のすぐ下にある、小さな
all
のテキストをクリックし、Intensity スライダーを調整します。オプションとして、ポストプロセスエフェクトにカスタムエディターを作成することができます。この方法に関する情報は、カスタムエディター を参照してください。
GrayScale C# スクリプト
これは、C# ポストプロセスファイルです。カスタムポストプロセスエフェクトは、設定データとロジックの両方を同じクラスに保管します。エフェクトに設定を作成するには、VolumeParameter
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using System;
[Serializable, VolumeComponentMenu("Post-processing/Custom/GrayScale")]
public sealed class GrayScale : CustomPostProcessVolumeComponent, IPostProcessComponent
{
[Tooltip("Controls the intensity of the effect.")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
Material m_Material;
public bool IsActive() => m_Material != null && intensity.value > 0f;
public override CustomPostProcessInjectionPoint injectionPoint => CustomPostProcessInjectionPoint.AfterPostProcess;
public override void Setup()
{
if (Shader.Find("Hidden/Shader/GrayScale") != null)
m_Material = new Material(Shader.Find("Hidden/Shader/GrayScale"));
}
public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
{
if (m_Material == null)
return;
m_Material.SetFloat("_Intensity", intensity.value);
m_Material.SetTexture("_InputTexture", source);
HDUtils.DrawFullScreen(cmd, m_Material, destination);
}
public override void Cleanup() => CoreUtils.Destroy(m_Material);
}
まずコード例では、馴染みがないかもしれませんが、ClampedFloatParameter を使います。このタイプは、範囲に固定できる浮動小数点数です。コンストラクターでは:
最初のパラメーターは、プロパティーのデフォルト値です。
2 番目のパラメーターは、プロパティーを固定する最小値を表します。
3 番目のパラメーターは、プロパティーを固定する最小値を表します。
次に、IsActive() 関数があります。HDRP は Render 関数がエフェクトのプロセスが可能であるかを確認する前に、この関数を呼び出します。これに false
が返されると、HDRP はエフェクトをプロセスしません。エフェクトが破損する、または何も起こらない場合には、各プロパティー設定を確認すると良いでしょう。この例では、IsActive() が GrayScale.shader を見つけることができ、強度が0を超過するようにします。
injectionPoint オーバーライドでは、パイプライン HDRP がエフェクトを実行する場所を特定できます。現在ある挿入ポイントは3つです。
AfterOpaqueAndSky
BeforeTAA
BeforePostProcess
AfterPostProcess
HDRP がどこにカスタムポストプロセスを挿入するかに関する詳細は、次の図表を参照してください。
次に、SetUp、Render、Cleanup 関数があります。これらは順に、エフェクトが必要なリソースの割り当て、使用、およびリリースを行います。例が使用する唯一のリソースは、単独のマテリアルのみです。例では Setupでマテリアルを作成し、Cleanup では CoreUtils.Destroy() を使ってマテリアルをリリースします。Render 関数では、CommandBuffer にアクセスでき、HDRP が実行するタスクをキューに加えるために使えます。ここでは HDUtils.DrawFullScreen を使い、フルスクリーンクアッドをレンダリングできます。パスする CommandBuffer およびマテリアルを使い、結果を目的地の RTHandle へ転送します。
GrayScale シェーダー
HDRP では、ユーザーに頂点およびフラグメントシェーダーの全面的な制御権が与えられるため、ニーズに応じ両方を編集することができます。ちなみに、Common.hlsl および Color.hlsl には、シェーダーがデフォルトで含める数多くのユーティリティ関数があります。つまり、エフェクトでこれらのユーティリティ関数にアクセスすることができるということです。例えば、グレースケールシェーダーは Luminance() 関数を使って、リニア RGB 値をルミナンスの同等値に変換します。
Shader "Hidden/Shader/GrayScale"
{
HLSLINCLUDE
#pragma target 4.5
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"
struct Attributes
{
uint vertexID : SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vert(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
return output;
}
// ポストプロセスエフェクトを制御するプロパティーリスト
float _Intensity;
TEXTURE2D_X(_InputTexture);
float4 CustomPostProcess(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
uint2 positionSS = input.texcoord * _ScreenSize.xy;
float3 outColor = LOAD_TEXTURE2D_X(_InputTexture, positionSS).xyz;
// ブレンディングはハードウェアブレンドに頼らず、手動で行う
// これはカラーバッファに以前のポストプロセスエフェクトからの廃物が含まれているため、必要である。
return float4(lerp(outColor, Luminance(outColor).xxx, _Intensity), 1);
}
ENDHLSL
SubShader
{
Pass
{
Name "GrayScale"
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
#pragma fragment CustomPostProcess
#pragma vertex Vert
ENDHLSL
}
}
Fallback Off
}
シーンにシェーダーを参照するものがない場合、Unity はシェーダーを構築せず、アプリケーションをエディター外で実行する際にエフェクトは作用しません。この解決策は、シェーダーを リソースフォルダー に追加するか、または Edit > Project Settings > Graphics へ行き、シェーダーを Always Included Shaders リストに追加します。
⚠️ HDRP はポストプロセスエフェクトを実行する際に、レンダーターゲットプーリングシステムを使います。つまり、現在のカラーバッファに何が含まれているかが不明であることを意味し、従ってこのカラーバッファを表示することが可能なインストラクションを利用してはいけないということです。エフェクトが破損につながるため、シェーダーに透明度、ブレンドモード、または clip() インストラクションを使わないようにしてください。
シェーダー入力
デフォルトにより、シェーダーテンプレートには次の入力が含まれています。
入力 | 説明 |
---|---|
positionCS | ピクセルのクリップスペース位置です。この値の範囲は、0から現在のスクリーンサイズです。 |
texcoord | フルスクリーン UV 座標です。この値の範囲は0から1です。 |
_InputTexture | ソーステクスチャです。グレースケール C# スクリプトはこれをシェーダーに渡します。 |
_Intensity | エフェクトの強度です。グレースケール C# スクリプトはこれをシェーダーに渡します。 |
エフェクトの順序
HDRP では、各挿入ポイントでカスタムポストプロセスエフェクトの順序をカスタマイズできます。エフェクトの順序はいかのとおりです。
Edit > Project Settings に移動し、HDRP Default Settings タブを選択します。
Custom Post Process Orders のセクションまで下にスクロールします。このセクションには各挿入ポイントに 1つずつ、合わせて 3 つのリストが含まれています。
HDRP がレンダリングできるように、これらのリストにカスタムエフェクトを追加します。
HDRP はリストの上から下へ、順番にエフェクトをプロセスします。各リストの実行順序は以下の通りです。
Before Transparent.
Before TAA
Before Post Process
After Post Process
カスタムエディター
デフォルトにより、Unityはクラスに対してエディターを作成しますが、特定のプロパティーの表示様式をより制御したい場合は、カスタムエディターを作成できます。カスタムエディタースクリプトを作成する場合は、Editor と名付けられたフォルダーに必ず入れてください。
以下は、GrayScale エフェクト用のカスタムエディターの例です。
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEditor;
[VolumeComponentEditor(typeof(GrayScale))]
sealed class GrayScaleEditor : VolumeComponentEditor
{
SerializedDataParameter m_Intensity;
public override bool hasAdvancedMode => false;
public override void OnEnable()
{
base.OnEnable();
var o = new PropertyFetcher<GrayScale>(serializedObject);
m_Intensity = Unpack(o.Find(x => x.intensity));
}
public override void OnInspectorGUI()
{
PropertyField(m_Intensity);
}
}
このカスタムエディターは、Unity が作るエディターと同様の結果を生みますので、それほど役には立ちません。なお Custom Volume コンポーネントエディターも 追加のオプションボタン をサポートします。追加するには、hasAdvancedMode オーバライドを true に設定してください。その後、OnInspectorGUI 内で isInAdvancedMode ブーリアンを使い、追加プロパティーを表示します。
トラブルシューティング
エフェクトが正しく表示されない場合
プロジェクト設定で、ポストプロセス順序リストの1つにエフェクトが記載されていることを確認します (エフェクトの順序) を参照にしてください。
エフェクトのシェーダーが編集するか、およびポストプロセスボリュームのマテリアルへのリファレンスが null になっていないか確認します。
ポストプロセスを含むボリュームで、十分に高い優先順位になっているか、そしてカメラが境界内にあることを確認します。
シェーダーに clip() インストラクションが含まれていないこと、ブレンドモードがオフに設定されており、出力アルファが常に1であることを確認します。
既知の問題と制限事項
- カスタムポストプロセスのクラス名を改名すると、HDRP プロジェクト設定でファイルが削除され、エフェクトがレンダリングされなくなります。