56
44

【Unity】アニメ風の演出効果をShader Graphで実現する

Posted at

はじめに

この記事では、手書きアニメでよく見られる画面に一瞬激しい効果がかかる演出の演出を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 に設定します。

スクリーンショット 2024-02-21 午後11.17.19.png

URPのRendererAssetにFullscreenPassRendererFeatureを追加し、作成したシェーダを使ったマテリアルをアタッチします。これにより作成したシェーダを画面に対して適用することができます。

スクリーンショット 2024-02-21 午後11.58.56.png

今回目指す演出はアートスタイル等によって様々な作り方があると思いますが、今回の実装は Lambertのポスタライズ円形のディストーション を用いて行います。

Lambertのポスタライズ

この項では、画面全体の色を大胆に調整して画面全体が激しく明滅しているような印象を与えるための実装を行っています。
まずは、ShaderGraphで取得できる画面のNormalバッファを利用してLambert (LdotN) の計算を行います。

スクリーンショット 2024-02-21 午後11.24.55.png

この時点では以下のような画面が出力されます。

スクリーンショット 2024-02-21 午後11.25.38.png

続いて、この結果をstep関数で2値化し、その結果をもとにlerpでカラーを乗せポスタライズを行います。

スクリーンショット 2024-02-21 午後11.26.17.png

最終的に以下のような絵が得られました。指定するカラーを変更することで見た目の雰囲気をガラリと変えることができます。

スクリーンショット 2024-02-21 午後11.29.08.png

スクリーンショット 2024-02-21 午後11.29.24.png

円形のディストーション

この項では、画面全体を大きく歪ませることで画面に躍動感を与えることを目指した実装を行っています。

まず、特定座標を中心として画面を歪めるため、指定座標からの方向ベクトルに応じてUVオフセットをかける処理を実装します。

スクリーンショット 2024-02-21 午後11.45.32.png

この時点での画面は以下のようになります。 (画面中心を基準としてUVを歪ませています)

スクリーンショット 2024-02-21 午後11.46.46.png

さらに、集中線のような効果を得るため、Polar Coordinates ノードを用いた円形のUVとノイズ、またUVと特定座標との距離を用いて特定座標を中心にギザギザが広がるようなシェーダを実装します。

スクリーンショット 2024-02-21 午後11.47.51.png

最終的には以下のような見た目になりました。

スクリーンショット 2024-02-21 午後11.49.53.png

ここまでで一枚絵としての実装(シェーダの実装)は完了となります。

プロパティのアニメーション制御

ここまでの実装で画面に対して作成したポストエフェクトを適用することができましたが、今回実装する演出は画面に一瞬かけたい効果なので、アニメーション等でパラメータを操作する必要があります。

今回は以下のようなTimelineを作成し、AnimationTrackでシェーダのプロパティを操作できるようにします。

スクリーンショット 2024-02-22 午前12.01.22.png

シェーダプロパティのGlobal化

まずはShaderGraphで定義しているプロパティを外部から変更可能にするため、Globalなプロパティとして制御できるようにします。

(シェーダを使ったマテリアルのプロパティを制御する方法も考えられますが、今回はポストエフェクトであるのと実装の単純化のためGlobalなプロパティを用います)

ShaderGraphではプロパティの設定の Override Property Declaration にチェックを入れ、Shader Declaration をGlobalにすることでプロパティをGlobalなものとして定義することができます。

スクリーンショット 2024-02-22 午前12.05.20.png

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に並べることでアニメーション制御が可能になります。

スクリーンショット 2024-02-22 午前12.09.02.png

結果

これらの実装により、時間軸に合わせて激しい画面効果をかける演出を実現することができました。
(最終的な絵作りにはBloomなどの別の効果を併用しています)

スクリーンショット 2024-02-22 午前12.11.55.png

スクリーンショット 2024-02-22 午前12.12.07.png

スクリーンショット 2024-02-22 午前12.12.21.png

スクリーンショット 2024-02-22 午前12.12.35.png

さいごに

今回の記事ではFullscreen ShaderGraphの簡単な使い方と、それを用いてアニメ風のポストエフェクトを実現するためのアプローチを解説しました。

ポストエフェクトシェーダは画面の印象を操作することができる面白いものなので、ShaderGraphで気軽に実装できるようになった今、ぜひチャレンジしてみてください!

56
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
56
44