【Unity】ポストエフェクトで特定のオブジェクトにモザイクをかけてみた

どーも、ぐるたか@guru_takaです。

前々から特定のオブジェクトに特殊エフェクトをかけたい!と思い、実際にやってみました。成果物はこちらです!


© UTJ/UCL

ユニティちゃんにモザイクをかけてみました。結構、面白いです!笑

モザイクだけでなく、グレースケールにしたり歪ませるなど、エフェクト次第で色んな表現ができます。またAR・VRとも相性が良さそうです!

さっそく、特定のオブジェクトにエフェクトを実装するやり方を紹介していきます。GitHubにコードを掲載してますので、こちらも参考にしてみてください!
MosaicSpecificObject | GitHub

MEMO
Unityのバージョンは2019.1.1f1です。

主な流れ

超ざっくりまとめると、ポストエフェクトでモザイクをかけます。特定のオブジェクト限定にするため、専用のカメラを用意。最後に良い感じに合成されて、完成!って感じです。

STEP.1
モザイクかけるLayerを作成&設定
STEP.2
複数のカメラを用意&設定
STEP.3
ポストエフェクト用のScriptを作成
STEP.4
モザイクShaderを作成&アタッチ
STEP.5
影のレンダリングを調整するScriptを作成

STEP1.モザイクかけるLayerを作成&設定

まずはモザイクをかけるLayerを作成し、設定しましょう!

ここではユニティちゃんに、Layer=PostEffectとしています。

STEP2.複数のカメラを用意&設定

次に3つのカメラを用意します。描画順とざっくりしたイメージはこんな感じ!

STEP.1
背景用カメラ
背景がない場合は、必要なし()
STEP.2
ポストエフェクト用カメラ
モザイクかけたいオブジェクトのみ描画
STEP.3
メインカメラ
残りのオブジェクトとモザイクがかかったオブジェクトの影を描画

カメラの設定は画像の通りです。

背景用カメラ

ポストエフェクト用カメラ

メインカメラ

Depthは描画順です。Clear FlagsをDon't Clearにすることで、深度情報を保持したまま、ポストエフェクトを限定してかけられます。

Clear FlagsをDepth Onlyにすると、下画像のように、深度情報が関係なくなって上書き描画されるので注意が必要です!

STEP3.ポストエフェクト用のScriptを作成

続いて、ポストエフェクト用のScriptを作成します。

using UnityEngine;

public class PostEffect : MonoBehaviour
{
    public Material mosaic;

    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        Graphics.Blit(src, dest, mosaic);
    }
}

STEP4.モザイクShaderを作成&アタッチ

次に、モザイクシェーダーを作成します。シェーダーの解説はメインでないので割愛します!興味ある方は参考リンクをご覧ください。

Shader "Custom/mosaic" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _PixelNumber ("PixelNum", float) = 100
    }

    SubShader {
        Pass {
            Tags { "RenderType"="Opaque" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float _PixelNumber;

            struct v2f {
                half4 pos : POSITION;
                half2 uv : TEXCOORD0;
            };

            float4 _MainTex_ST;

            v2f vert(appdata_base v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            half4 frag(v2f i) : COLOR {
                half2 uv = floor(i.uv * _PixelNumber) / _PixelNumber;
                fixed4 col = tex2D(_MainTex, uv);
                return col;
            }

            ENDCG
        }
    }
    FallBack "Diffuse"
}
参考 Unityを利用して2D画像にモザイク効果をかけるSTYLY シェーダーが完成できたら、ポストエフェクト用カメラにアタッチしましょう!

STEP5.影のレンダリングを調整するScriptを作成

この状態でレンダリングすると、こんな風になります。

これはモザイクとキレイなオブジェクトが重なっている状態を意味しています。カメラの位置をずらすと一目瞭然!

シンプルにメインカメラでCulling MaskでLayer”PostEffect”を外せば良いじゃん!と思うかもしれませんが、罠が待ち受けています。

影が出なくなるんですね…。ここでめちゃくちゃ悩み、詰まりました。最終的に、以下のような処理で解決!

  • メインカメラのレンダリング前に影のみ描画するよう指示
  • メインカメラのレンダリング後にオブジェクトも描画するよう指示
レンダリング後にオブジェクトも描画するよう設定しないと、ポストエフェクト用カメラで映し出されたオブジェクトが消えるので注意しましょう。

ソースはこちらです。

using UnityEngine;

public class PostShadow : MonoBehaviour
{
    public GameObject renderTarget;

    protected Renderer[] _rendererComponents;

    void Start()
    {
        _rendererComponents = renderTarget.GetComponentsInChildren();
    }

    void OnPreRender()
    {
        foreach (var renderer in _rendererComponents)
        {
            renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly;
        }
    }
    void OnPostRender()
    {
        foreach (var renderer in _rendererComponents)
        {
            renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
        }
    }
}

メインカメラにアタッチして完成です!


MEMO
複数のオブジェクトにポストエフェクトをかけたい場合は、空のGameObject1つにまとめて、アタッチすればOKです!

最後に

以上です。

Unityでの表現の参考に少しでもなれば幸いです!

参考リンク

参考 Unity サウンドと同期してぷるぷるするエフェクトLLC DigiFie 参考 【Unity】特定のモデルにのみImageEffectがかからないようにするテラシュールブログ 参考 【Unityシェーダ入門】Unityのポストエフェクトでモノクロ画面を作るおもちゃラボ

コメントを残す