質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.42%

  • C#

    7963questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity

    4650questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

PostProcessingStackの効果が重複してしまう

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 469

regulus123

score 5

Unityでスマホ向けのアプリを制作しています。

アセットのPostProcessingStackを使って画面効果を付与しているのですが、メインカメラとは別にUI用のカメラを用意して両方のカメラにPostProcessingProfileを付与すると効果が重複してしまいます。

カメラを複数用意した場合でも重複せずに画面効果を付与することは可能でしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

先の回答にDefaultシェーダーの改変版についても例示しようとしましたが、字数制限に引っかかってしまったようで別回答にて失礼します。

オリジナルのコードはダウンロードアーカイブで入手でき、ダウンロードしたビルトインシェーダーの「builtin_shaders-2017.3.1f1/DefaultResourcesExtra/UI/UI-Default.shader」を下記のように変更しました。
変更箇所はシェーダー名をオリジナルと区別するために変えたことと、「Blend」の設定を「SrcAlpha OneMinusSrcAlpha」から「SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha」に変えたところのみです。

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "UI/Default (Modified Alpha Blending)" // シェーダーに別名を付けて...
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)

        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255

        _ColorMask ("Color Mask", Float) = 15

        [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Stencil
        {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha
        // デフォルトではアルファの係数が省略されて「SrcAlpha」になっているようで
        // アルファ成分が2乗されたような状態になってしまいます
        // 大抵の描画においては、RGBが正しく合成されていれば見た目は正しくなるため問題ないのですが
        // 今回のように、半透明な物体をひととおり描画した後で描画後のアルファを利用しようとするとおかしくなるため
        // 明示的に「One」を指定することで、この現象を防いでいます
        ColorMask [_ColorMask]

        Pass
        {
            Name "Default"
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"
            #include "UnityUI.cginc"

            #pragma multi_compile __ UNITY_UI_CLIP_RECT
            #pragma multi_compile __ UNITY_UI_ALPHACLIP

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                float2 texcoord  : TEXCOORD0;
                float4 worldPosition : TEXCOORD1;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            fixed4 _Color;
            fixed4 _TextureSampleAdd;
            float4 _ClipRect;

            v2f vert(appdata_t v)
            {
                v2f OUT;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
                OUT.worldPosition = v.vertex;
                OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);

                OUT.texcoord = v.texcoord;

                OUT.color = v.color * _Color;
                return OUT;
            }

            sampler2D _MainTex;

            fixed4 frag(v2f IN) : SV_Target
            {
                half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;

                #ifdef UNITY_UI_CLIP_RECT
                color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
                #endif

                #ifdef UNITY_UI_ALPHACLIP
                clip (color.a - 0.001);
                #endif

                return color;
            }
        ENDCG
        }
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

試してみましたが、ちょっと一手間かける必要がありそうでした。

通常の描画プロセスは

  • メインカメラでシーンを描く
  • 描画結果にメインカメラ用のエフェクトがかかる
  • 描画結果の上にUIカメラでUIを重ね描きする
  • 描画結果にUIカメラ用のエフェクトがかかる

という具合になって、おっしゃる通りUI用エフェクトも最終描画結果全体に適用されてしまうようですね。

Image effect on UI camera affecting entire scene | Unity Communityの回答によると、UIは別途レンダーテクスチャ上に描画し独立してエフェクトをかけさせ、それをシーンの描画結果と合成せよとのことでした。

しかし一部のエフェクト(Antialiasing、Depth Of Field、Bloom、Color Grading、Chromatic Aberration、Grain、Vignette、Ditheringなど)は処理前テクスチャのアルファを消してしまうようで、これをそのまま合成するとシーンの映像が見えなくなってしまうため、処理前テクスチャのアルファをとっておいて、処理後テクスチャのRGBと組み合わせてやる必要がありました。

さらに、UI用のデフォルトのシェーダーはブレンド係数の設定が不適切なようで、アルファチャンネルの合成結果が狂ってしまう様子です。設定を修正したマテリアルを作って、「Image」や「Text」などUI上に描画されるオブジェクトのマテリアルをひととおりそれに差し替えれば何とかなりました。

メインカメラに下記のようなスクリプトをアタッチ、さらにインスペクタで「UI Camera」にUI用カメラをセットして、

using UnityEngine;
using UnityEngine.Rendering;

[RequireComponent(typeof(Camera))]
public class UICompositor : MonoBehaviour
{
    public Camera UICamera;

    private new Camera camera;
    private Material dealphaMaterial;
    private Material compositionMaterial;
    private CommandBuffer preEffectCommands;
    private int uiTexBeforeEffectsID;
    private int uiTexAfterEffectsID;

    private void Start()
    {
        this.camera = this.GetComponent<Camera>();

        if (this.UICamera == null)
        {
            this.enabled = false;
            throw new System.InvalidOperationException("No UI camera!");
        }

        // UI用カメラの設定を変更、レンダリングはマニュアル制御とするためenabledはfalseとしておく
        this.UICamera.clearFlags = CameraClearFlags.SolidColor;
        this.UICamera.backgroundColor = new Color(0.0f, 0.0f, 0.0f, 0.0f);
        this.UICamera.enabled = false;

        // 加工用マテリアルを作成
        this.dealphaMaterial = new Material(Shader.Find("Hidden/DealphaShader"));
        this.compositionMaterial = new Material(Shader.Find("Hidden/UICompositionShader"));

        // シェーダープロパティへアクセスするためのIDを求めておく
        this.uiTexBeforeEffectsID = Shader.PropertyToID("_UITexBeforeEffects");
        this.uiTexAfterEffectsID = Shader.PropertyToID("_UITexAfterEffects");

        // UI用カメラがレンダリングを行った後、エフェクトをかける前に行う処理を作成
        this.preEffectCommands = new CommandBuffer();
        this.preEffectCommands.name = "PreprocessBeforeUIEffects";
        this.preEffectCommands.GetTemporaryRT(this.uiTexBeforeEffectsID, -1, -1); // レンダーテクスチャを用意し、_UITexBeforeEffectsにセットする
        this.preEffectCommands.Blit(BuiltinRenderTextureType.CurrentActive, this.uiTexBeforeEffectsID); // エフェクト処理前のUI描画結果を_UITexBeforeEffectsにコピーする
        this.preEffectCommands.Blit(this.uiTexBeforeEffectsID, BuiltinRenderTextureType.CameraTarget, this.dealphaMaterial); // コピーしたUI描画結果をカメラのターゲット(_UITexAfterEffects)に書き戻す...このときアルファを除去しておき、それに対してエフェクトをかけさせる
        this.UICamera.AddCommandBuffer(CameraEvent.BeforeImageEffects, this.preEffectCommands); // 以上の処理をエフェクト処理前の位置に差し込む
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        var currentActiveTexture = RenderTexture.active; // 現在のアクティブテクスチャを覚えておく
        var uiTextureAfterEffects = RenderTexture.GetTemporary(Screen.width, Screen.height); // レンダーテクスチャを用意し...

        Shader.SetGlobalTexture(this.uiTexAfterEffectsID, uiTextureAfterEffects); // それを_UITexAfterEffectsにセットする

        // ターゲットを_UITexAfterEffectsに設定してUIを描画させる
        // これにより、エフェクト処理後のUI描画結果が_UITexAfterEffectsに格納される
        // また、コマンドバッファを差し込んでおいたので、エフェクト処理前のUI描画結果が_UITexBeforeEffectsに格納される
        RenderTexture.active = uiTextureAfterEffects;
        this.UICamera.targetTexture = uiTextureAfterEffects;
        this.UICamera.Render();

        RenderTexture.active = currentActiveTexture; // アクティブテクスチャを元に戻し...
        Graphics.Blit(source, destination, this.compositionMaterial); // シーン描画結果とUI描画結果を合成する

        RenderTexture.ReleaseTemporary(uiTextureAfterEffects);
    }
}

アルファ除去用のイメージエフェクトシェーダーと、

Shader "Hidden/DealphaShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;

            fixed4 frag (v2f i) : SV_Target
            {
                float4 color = tex2D(_MainTex, i.uv);

                // RGBにAが乗算されているので、Aで割って元の色を復元
                color.rgb /= color.a;
                // ただし、上記の式でRGBを復元するには、UI用マテリアルのアルファブレンド指定を
                // 「Blend SrcAlpha OneMinusSrcAlpha」から「Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha」に
                // 変更しておく必要があります
                // その変更を加えなくても、半透明な物体の重なり合いがなければ
                // color.rgb /= sqrt(color.a); としてやれば、一応RGBを復元できるかと思います

                // アルファを1に書き換え
                color.a = 1.0;

                return color;
            }
            ENDCG
        }
    }
}

メインカメラ映像にUI映像を合成するイメージエフェクトシェーダーを作り、

Shader "Hidden/UICompositionShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            sampler2D _UITexBeforeEffects;
            sampler2D _UITexAfterEffects;

            fixed4 frag(v2f i) : SV_Target
            {
                // シーン描画結果にUI描画結果をアルファブレンド
                // このとき、UIのRGBはエフェクト処理後の、Aはエフェクト処理前のものを使用する
                fixed3 mainColor = tex2D(_MainTex, i.uv).rgb;
                fixed3 uiColor = tex2D(_UITexAfterEffects, i.uv).rgb;
                fixed uiAlpha = tex2D(_UITexBeforeEffects, i.uv).a;
                // ここでもアルファ除去シェーダーの場合と同じく、UI用マテリアルに修正を加えていない場合は
                // fixed uiAlpha = sqrt(tex2D(_UITexBeforeEffects, i.uv).a); としてやる必要があるでしょう
                fixed3 resultColor = (uiColor * uiAlpha) + (mainColor * (1.0 - uiAlpha));

                return fixed4(resultColor, 1.0);
            }
            ENDCG
        }
    }
}

ビルトインのUI/Defaultの改変版を作り、UIオブジェクトのマテリアルは全部これを使ったマテリアルに差し替えて、とりあえずメインカメラ側はAntialiasing、Ambient Occlusion、Screen Space Reflection、Color Grading(色温度を赤側に)、Vignetteを適用し、UIカメラ側はColor Grading(色温度を青側に)、Grainを適用したところ、下図のようなそれらしい感じになりました。

プレビュー

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • C#

    7963questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity

    4650questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。