<追記 2019-10-05>
HDRPがカスタムポストエフェクト対応したそうです。この記事の3日後にマージされとる……😂
https://github.com/Unity-Technologies/ScriptableRenderPipeline/pull/4484
追記ここまで>
HDRPでポストエフェクトできた、ワーイ pic.twitter.com/PM01n6y4g3
— amagi (@amagitakayosi) September 3, 2019
UnityのHDRPを使うと高品質なレンダリングが可能になりますが、まだユーザーがポストエフェクトを作成できません。
Unity公式フォーラムでは「2019.3で対応するつもりだよ~」とアナウンスされていますが、今のところ具体的なスケジュールはまだ未定のようです。
https://forum.unity.com/threads/custom-post-processing-effects-with-new-hdrp-workflow.689317/
昨日↑のスレを見返した所、Another Angle Gamesのnehvaleem氏がHDRPをforkしてポストエフェクトを自作するチュートリアルを投稿してくれていました!
https://medium.com/another-angle/custom-post-processing-using-hdrp-in-unity-2019-x-60302a2fa1e0
この記事では、↑のチュートリアルに沿って解説します。
↑のチュートリアルではシェーダー周りはノータッチだったり色々ハマりどころもあったので、その辺もカバーしていきます。
前提
- Unityのバージョン: 2019.2
- HDRPのバージョン: 6.9.1
手順
- HDRPをfork
- HDRPプロジェクトを新規作成
- forkしたHDRPをプロジェクトに突っ込む
- 自作PostProcessComponentを作る
- 自作PostProcessComponentをロードする
- PostProcessingSystemをいじる
HDRPをfork
HDRPはScriptableRenderPipelineの中にあるので、まずはこちらをcloneします。
けっこう時間かかるんで気長に待ちましょう。
https://github.com/Unity-Technologies/ScriptableRenderPipeline
git clone https://github.com/Unity-Technologies/ScriptableRenderPipeline
cd ScriptableRenderPipeline
HDRPは、Unityのバージョンに合わせて異なるバージョンを使う必要があります。
バージョン毎にタグが切られてるのでcheckoutしましょう。
2019.2の場合は6.9.1です。
git checkout 6.9.1
HDRPプロジェクトを新規作成
次に、Unityで新規プロジェクトを作成します。
プロジェクト作成ダイアログで HDRP
を選択してください。
HDRPのサンプルシーンが作成されます。きれいですね~
従来のUnityではPost Processing Stackをインポートしてポストエフェクトをかけていましたが、HDRPではPost Processing Stackが最初から組み込まれています。
Hierarchyビューで Scene Post-process
を選択してインスペクターを見ると、既にいくつかポストエフェクトが設定されていることがわかります。
forkしたHDRPをプロジェクトに突っ込む
まず、標準で入っているHDRPを削除します。
Window
> Package Manager
からHigh Definition RP
を選択し、Remove
をクリック。
次に、先程cloneしたHDRPをインストールします。
Package Managerの+
ボタンからAdd package from disk...
をクリック。
先程cloneしたレポジトリから、 ScriptableRenderPipeline/com.unity.render-pipelines.high-definition/package.json
を選択し、開く
をクリックすると、HDRPのインストールが始まります。
自作PostProcessComponentを作る
それでは、ついにポストエフェクトを作っていきます。
HDRPのポストエフェクトは、IPostProcessComponentを実装したクラスとシェーダーの2ファイルで構成されています。
- IPostProcessComponent: エフェクトのパラメータ等を管理
- シェーダー: エフェクト処理
まずIPostProcessComponentのクラスを作りましょう。
HDRPレポジトリの Runtime/PostProcessing/Components
に Glitch.cs
を作成します。
using System;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
[Serializable, VolumeComponentMenu("Post-processing/Glitch")]
public sealed class Glitch : VolumeComponent, IPostProcessComponent
{
// BoolParameterを使うと、Inspector上ではチェックボックスが表示される
public BoolParameter isEnabled = new BoolParameter(false);
// ColorParameterを使うと、Inspector上ではカラーピッカーが表示される
[Tooltip("Overlay color for glitch")]
public ColorParameter overlayColor = new ColorParameter(new Color(0,0,0,0), false, true, true);
// ClampedFloatParameterを使うと、Inspector上ではスライダーが表示される
[Tooltip("Intensity of glitch")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0.03f, 0f, 0.2f);
// 実装必須
public bool IsActive()
{
return isEnabled.value;
}
}
}
次に、HDRPレポジトリの Runtime/PostProcessing/Shaders
に Glitch.shader
を作成します。
Shader "Hidden/Glitch"
{
SubShader
{
Tags{ "RenderPipeline" = "HDRenderPipeline" }
Pass
{
ZWrite On ZTest Always Blend Off Cull Off
HLSLPROGRAM
#pragma target 4.5
#pragma only_renderers d3d11 ps4 xboxone vulkan metal switch
#pragma vertex Vert
#pragma fragment Frag
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
TEXTURE2D_X(_InputTexture);
float4 _OverlayColor;
float _Intensity;
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;
}
float4 Frag(Varyings input) : SV_Target0
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = input.texcoord.xy;
float time = _Time.y;
// ここにエフェクトを書く。
// 今回は適当にグリッチしてる
float4 outColor = LOAD_TEXTURE2D_X(_InputTexture, uv * _ScreenSize.xy);
float n = sin(floor(uv.y * 23. + time * 3.)) * sin(floor(uv.y * 17. + time * 39.));
if (frac(n * 170.) < 0.1) {
uv.x = frac(uv.x + n * _Intensity);
outColor = LOAD_TEXTURE2D_X(_InputTexture, uv * _ScreenSize.xy);
outColor += _OverlayColor * _OverlayColor.a;
}
return outColor;
}
ENDHLSL
}
}
Fallback Off
}
自作PostProcessComponentをロードする
Runtime/RenderPipeline/RenderPipelineResources.cs
を開きます。
GetAllComputeShaders
の上あたりに、以下のコードを追加します。
[Reload("Runtime/PostProcessing/Shaders/Glitch.shader")]
public Shader GlitchPS;
PostProcessingSystemをいじる
最後にPostProcessingSystemを編集し、レンダリングの終段でポストエフェクトがちゃんと実行されるようにします。
Runtime/PostProcessing/PostProcessingSystem.cs
を開き、以下のプロパティを追加してください。
Material m_GlitchMaterial;
Glitch m_Glitch;
次に、コンストラクタにmaterialの初期化処理を追加します。
// さっき作ったシェーダーからマテリアルを作成
m_GlitchMaterial = CoreUtils.CreateEngineMaterial(m_Resources.shaders.GlitchPS);
ついでに Cleanup()
内でちゃんと後処理してあげましょう。
CoreUtils.Destroy(m_GlitchMaterial);
m_GlitchMaterial = null;
m_Glitchの初期化はBeginFrame()
で行います。
public void BeginFrame(CommandBuffer cmd, HDCamera camera)
{
// 中略
var stack = VolumeManager.instance.stack;
// 中略
m_Glitch = stack.GetComponent<Glitch>(); // この行を追加
}
いよいよRender()
を編集します。
460行目あたりに // TODO: User effects go here
というコメントがあるので、その下に以下のコードをコピペしてください。
if (m_PostProcessEnabled)
{
if (m_Glitch.IsActive())
{
var destination = m_Pool.Get(Vector2.one, k_ColorFormat);
DoGlitchPass(cmd, camera, source, destination);
PoolSource(ref source, destination);
}
}
DoGlitchPassの実装を追加します。
DoFinalPassの上あたりに以下のコードをコピペしてください。
#region Glitch Pass
void DoGlitchPass(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
{
// マテリアルにパラメーターを渡す
m_GlitchMaterial.SetTexture(HDShaderIDs._InputTexture, source);
m_GlitchMaterial.SetVector(Shader.PropertyToID("_OverlayColor"), m_Glitch.overlayColor.value);
m_GlitchMaterial.SetFloat(Shader.PropertyToID("_Intensity"), m_Glitch.intensity.value);
// destinationに描画
HDUtils.DrawFullScreen(cmd, m_GlitchMaterial, destination);
}
#endregion
これでコードの編集は終了です~
使ってみよう
Scene Post-process
のインスペクターで Add overrideをクリックし、Post-processing > Glitchを選択します。
パラメーターをポチポチすると動くはず!
Unity custom post fx in HDRP pic.twitter.com/d7P5jU9Gqu
— amagi (@amagitakayosi) September 3, 2019
ワーイ