はじめに
この記事では、手書きアニメでよく見られる画面に一瞬激しい効果がかかる演出風の演出をUnityで実装するための方法を解説します。
実際に動かしてみた動画 ↓
環境
- Unity 2022.3.12f1
- Universal Render Pipeline 14.0.9
- ShaderGraph 14.0.9
方針
Universal Render Pipeline(以降URP)でのポストエフェクトの実装方法は様々ありますが、今回はおそらく現状最もカジュアルに実装可能である FullscreenPassRendererFeature を利用します。
この機能は、Shader Graphでフルスクリーンに対して効果をかけるShaderを作成し、それを使ったMaterialをRendererFeatureに刺すことでポストエフェクトが作成できる機能です。
こちらの機能に関しては以下の動画でUnity公式が解説していますので、詳細はそちらをご確認ください。
実装
さて、ここからは実際の実装について解説します。
ShaderGraphの作成
まずはShaderGraphを作成し、Material Typeを Fullscreen に設定します。
URPのRendererAssetにFullscreenPassRendererFeatureを追加し、作成したシェーダを使ったマテリアルをアタッチします。これにより作成したシェーダを画面に対して適用することができます。
今回目指す演出はアートスタイル等によって様々な作り方があると思いますが、今回の実装は Lambertのポスタライズ と 円形のディストーション を用いて行います。
Lambertのポスタライズ
この項では、画面全体の色を大胆に調整して画面全体が激しく明滅しているような印象を与えるための実装を行っています。
まずは、ShaderGraphで取得できる画面のNormalバッファを利用してLambert (LdotN) の計算を行います。
この時点では以下のような画面が出力されます。
続いて、この結果をstep関数で2値化し、その結果をもとにlerpでカラーを乗せポスタライズを行います。
最終的に以下のような絵が得られました。指定するカラーを変更することで見た目の雰囲気をガラリと変えることができます。
円形のディストーション
この項では、画面全体を大きく歪ませることで画面に躍動感を与えることを目指した実装を行っています。
まず、特定座標を中心として画面を歪めるため、指定座標からの方向ベクトルに応じてUVオフセットをかける処理を実装します。
この時点での画面は以下のようになります。 (画面中心を基準としてUVを歪ませています)
さらに、集中線のような効果を得るため、Polar Coordinates ノードを用いた円形のUVとノイズ、またUVと特定座標との距離を用いて特定座標を中心にギザギザが広がるようなシェーダを実装します。
最終的には以下のような見た目になりました。
ここまでで一枚絵としての実装(シェーダの実装)は完了となります。
プロパティのアニメーション制御
ここまでの実装で画面に対して作成したポストエフェクトを適用することができましたが、今回実装する演出は画面に一瞬かけたい効果なので、アニメーション等でパラメータを操作する必要があります。
今回は以下のようなTimelineを作成し、AnimationTrackでシェーダのプロパティを操作できるようにします。
シェーダプロパティのGlobal化
まずはShaderGraphで定義しているプロパティを外部から変更可能にするため、Globalなプロパティとして制御できるようにします。
(シェーダを使ったマテリアルのプロパティを制御する方法も考えられますが、今回はポストエフェクトであるのと実装の単純化のためGlobalなプロパティを用います)
ShaderGraphではプロパティの設定の Override Property Declaration にチェックを入れ、Shader Declaration をGlobalにすることでプロパティをGlobalなものとして定義することができます。
Globalなプロパティの変更
次に、Globalなシェーダプロパティをアニメーション制御可能にするため、Inspectorから各種パラメータを操作することができるスクリプトを実装します。
[ExecuteAlways]
public class FlashPostProcessParameter : MonoBehaviour
{
public static class ShaderProperty
{
public static readonly int DistortionCenter = Shader.PropertyToID("_DistortionCenter");
public static readonly int DistortionStrength = Shader.PropertyToID("_DistortionStrength");
public static readonly int PosterizationThreshold = Shader.PropertyToID("_PosterizationThreshold");
public static readonly int PosterizationLightColor = Shader.PropertyToID("_PosterizationLightColor");
public static readonly int PosterizationDarkColor = Shader.PropertyToID("_PosterizationDarkColor");
public static readonly int FlashAlpha = Shader.PropertyToID("_FlashAlpha");
}
[SerializeField] private Vector2 _distortionCenter = new Vector2(0.5f, 0.5f);
[SerializeField] private float _distortionStrength = 0.1f;
[SerializeField] private float _posterizationThreshold = 0.1f;
[SerializeField, ColorUsage(false, true)] private Color _posterizationLightColor = Color.white;
[SerializeField, ColorUsage(false, true)] private Color _posterizationDarkColor = Color.black;
[SerializeField] private float _flashAlpha = 0.0f;
private void LateUpdate()
{
Shader.SetGlobalVector(ShaderProperty.DistortionCenter, _distortionCenter);
Shader.SetGlobalFloat(ShaderProperty.DistortionStrength, _distortionStrength);
Shader.SetGlobalFloat(ShaderProperty.PosterizationThreshold, _posterizationThreshold);
Shader.SetGlobalColor(ShaderProperty.PosterizationLightColor, _posterizationLightColor);
Shader.SetGlobalColor(ShaderProperty.PosterizationDarkColor, _posterizationDarkColor);
Shader.SetGlobalFloat(ShaderProperty.FlashAlpha, _flashAlpha);
}
}
そして最後にこのスクリプトをアタッチしたオブジェクトにAnimatorコンポーネントをアタッチし、各種プロパティを制御するAnimation Clipを作成、それらをTimelineに並べることでアニメーション制御が可能になります。
結果
これらの実装により、時間軸に合わせて激しい画面効果をかける演出を実現することができました。
(最終的な絵作りにはBloomなどの別の効果を併用しています)
さいごに
今回の記事ではFullscreen ShaderGraphの簡単な使い方と、それを用いてアニメ風のポストエフェクトを実現するためのアプローチを解説しました。
ポストエフェクトシェーダは画面の印象を操作することができる面白いものなので、ShaderGraphで気軽に実装できるようになった今、ぜひチャレンジしてみてください!