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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

2799閲覧

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

regulus123

総合スコア16

C#

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2018/04/05 16:02

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

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

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

HLSL

1// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) 2 3Shader "UI/Default (Modified Alpha Blending)" // シェーダーに別名を付けて... 4{ 5 Properties 6 { 7 [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} 8 _Color ("Tint", Color) = (1,1,1,1) 9 10 _StencilComp ("Stencil Comparison", Float) = 8 11 _Stencil ("Stencil ID", Float) = 0 12 _StencilOp ("Stencil Operation", Float) = 0 13 _StencilWriteMask ("Stencil Write Mask", Float) = 255 14 _StencilReadMask ("Stencil Read Mask", Float) = 255 15 16 _ColorMask ("Color Mask", Float) = 15 17 18 [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 19 } 20 21 SubShader 22 { 23 Tags 24 { 25 "Queue"="Transparent" 26 "IgnoreProjector"="True" 27 "RenderType"="Transparent" 28 "PreviewType"="Plane" 29 "CanUseSpriteAtlas"="True" 30 } 31 32 Stencil 33 { 34 Ref [_Stencil] 35 Comp [_StencilComp] 36 Pass [_StencilOp] 37 ReadMask [_StencilReadMask] 38 WriteMask [_StencilWriteMask] 39 } 40 41 Cull Off 42 Lighting Off 43 ZWrite Off 44 ZTest [unity_GUIZTestMode] 45 Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha 46 // デフォルトではアルファの係数が省略されて「SrcAlpha」になっているようで 47 // アルファ成分が2乗されたような状態になってしまいます 48 // 大抵の描画においては、RGBが正しく合成されていれば見た目は正しくなるため問題ないのですが 49 // 今回のように、半透明な物体をひととおり描画した後で描画後のアルファを利用しようとするとおかしくなるため 50 // 明示的に「One」を指定することで、この現象を防いでいます 51 ColorMask [_ColorMask] 52 53 Pass 54 { 55 Name "Default" 56 CGPROGRAM 57 #pragma vertex vert 58 #pragma fragment frag 59 #pragma target 2.0 60 61 #include "UnityCG.cginc" 62 #include "UnityUI.cginc" 63 64 #pragma multi_compile __ UNITY_UI_CLIP_RECT 65 #pragma multi_compile __ UNITY_UI_ALPHACLIP 66 67 struct appdata_t 68 { 69 float4 vertex : POSITION; 70 float4 color : COLOR; 71 float2 texcoord : TEXCOORD0; 72 UNITY_VERTEX_INPUT_INSTANCE_ID 73 }; 74 75 struct v2f 76 { 77 float4 vertex : SV_POSITION; 78 fixed4 color : COLOR; 79 float2 texcoord : TEXCOORD0; 80 float4 worldPosition : TEXCOORD1; 81 UNITY_VERTEX_OUTPUT_STEREO 82 }; 83 84 fixed4 _Color; 85 fixed4 _TextureSampleAdd; 86 float4 _ClipRect; 87 88 v2f vert(appdata_t v) 89 { 90 v2f OUT; 91 UNITY_SETUP_INSTANCE_ID(v); 92 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); 93 OUT.worldPosition = v.vertex; 94 OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); 95 96 OUT.texcoord = v.texcoord; 97 98 OUT.color = v.color * _Color; 99 return OUT; 100 } 101 102 sampler2D _MainTex; 103 104 fixed4 frag(v2f IN) : SV_Target 105 { 106 half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color; 107 108 #ifdef UNITY_UI_CLIP_RECT 109 color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); 110 #endif 111 112 #ifdef UNITY_UI_ALPHACLIP 113 clip (color.a - 0.001); 114 #endif 115 116 return color; 117 } 118 ENDCG 119 } 120 } 121} 122

投稿2018/04/08 22:48

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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用カメラをセットして、

C#

1using UnityEngine; 2using UnityEngine.Rendering; 3 4[RequireComponent(typeof(Camera))] 5public class UICompositor : MonoBehaviour 6{ 7 public Camera UICamera; 8 9 private new Camera camera; 10 private Material dealphaMaterial; 11 private Material compositionMaterial; 12 private CommandBuffer preEffectCommands; 13 private int uiTexBeforeEffectsID; 14 private int uiTexAfterEffectsID; 15 16 private void Start() 17 { 18 this.camera = this.GetComponent<Camera>(); 19 20 if (this.UICamera == null) 21 { 22 this.enabled = false; 23 throw new System.InvalidOperationException("No UI camera!"); 24 } 25 26 // UI用カメラの設定を変更、レンダリングはマニュアル制御とするためenabledはfalseとしておく 27 this.UICamera.clearFlags = CameraClearFlags.SolidColor; 28 this.UICamera.backgroundColor = new Color(0.0f, 0.0f, 0.0f, 0.0f); 29 this.UICamera.enabled = false; 30 31 // 加工用マテリアルを作成 32 this.dealphaMaterial = new Material(Shader.Find("Hidden/DealphaShader")); 33 this.compositionMaterial = new Material(Shader.Find("Hidden/UICompositionShader")); 34 35 // シェーダープロパティへアクセスするためのIDを求めておく 36 this.uiTexBeforeEffectsID = Shader.PropertyToID("_UITexBeforeEffects"); 37 this.uiTexAfterEffectsID = Shader.PropertyToID("_UITexAfterEffects"); 38 39 // UI用カメラがレンダリングを行った後、エフェクトをかける前に行う処理を作成 40 this.preEffectCommands = new CommandBuffer(); 41 this.preEffectCommands.name = "PreprocessBeforeUIEffects"; 42 this.preEffectCommands.GetTemporaryRT(this.uiTexBeforeEffectsID, -1, -1); // レンダーテクスチャを用意し、_UITexBeforeEffectsにセットする 43 this.preEffectCommands.Blit(BuiltinRenderTextureType.CurrentActive, this.uiTexBeforeEffectsID); // エフェクト処理前のUI描画結果を_UITexBeforeEffectsにコピーする 44 this.preEffectCommands.Blit(this.uiTexBeforeEffectsID, BuiltinRenderTextureType.CameraTarget, this.dealphaMaterial); // コピーしたUI描画結果をカメラのターゲット(_UITexAfterEffects)に書き戻す...このときアルファを除去しておき、それに対してエフェクトをかけさせる 45 this.UICamera.AddCommandBuffer(CameraEvent.BeforeImageEffects, this.preEffectCommands); // 以上の処理をエフェクト処理前の位置に差し込む 46 } 47 48 private void OnRenderImage(RenderTexture source, RenderTexture destination) 49 { 50 var currentActiveTexture = RenderTexture.active; // 現在のアクティブテクスチャを覚えておく 51 var uiTextureAfterEffects = RenderTexture.GetTemporary(Screen.width, Screen.height); // レンダーテクスチャを用意し... 52 53 Shader.SetGlobalTexture(this.uiTexAfterEffectsID, uiTextureAfterEffects); // それを_UITexAfterEffectsにセットする 54 55 // ターゲットを_UITexAfterEffectsに設定してUIを描画させる 56 // これにより、エフェクト処理後のUI描画結果が_UITexAfterEffectsに格納される 57 // また、コマンドバッファを差し込んでおいたので、エフェクト処理前のUI描画結果が_UITexBeforeEffectsに格納される 58 RenderTexture.active = uiTextureAfterEffects; 59 this.UICamera.targetTexture = uiTextureAfterEffects; 60 this.UICamera.Render(); 61 62 RenderTexture.active = currentActiveTexture; // アクティブテクスチャを元に戻し... 63 Graphics.Blit(source, destination, this.compositionMaterial); // シーン描画結果とUI描画結果を合成する 64 65 RenderTexture.ReleaseTemporary(uiTextureAfterEffects); 66 } 67}

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

HLSL

1Shader "Hidden/DealphaShader" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 } 7 SubShader 8 { 9 Cull Off ZWrite Off ZTest Always 10 11 Pass 12 { 13 CGPROGRAM 14 #pragma vertex vert 15 #pragma fragment frag 16 17 #include "UnityCG.cginc" 18 19 struct appdata 20 { 21 float4 vertex : POSITION; 22 float2 uv : TEXCOORD0; 23 }; 24 25 struct v2f 26 { 27 float2 uv : TEXCOORD0; 28 float4 vertex : SV_POSITION; 29 }; 30 31 v2f vert (appdata v) 32 { 33 v2f o; 34 o.vertex = UnityObjectToClipPos(v.vertex); 35 o.uv = v.uv; 36 return o; 37 } 38 39 sampler2D _MainTex; 40 41 fixed4 frag (v2f i) : SV_Target 42 { 43 float4 color = tex2D(_MainTex, i.uv); 44 45 // RGBにAが乗算されているので、Aで割って元の色を復元 46 color.rgb /= color.a; 47 // ただし、上記の式でRGBを復元するには、UI用マテリアルのアルファブレンド指定を 48 // 「Blend SrcAlpha OneMinusSrcAlpha」から「Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha」に 49 // 変更しておく必要があります 50 // その変更を加えなくても、半透明な物体の重なり合いがなければ 51 // color.rgb /= sqrt(color.a); としてやれば、一応RGBを復元できるかと思います 52 53 // アルファを1に書き換え 54 color.a = 1.0; 55 56 return color; 57 } 58 ENDCG 59 } 60 } 61}

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

HLSL

1Shader "Hidden/UICompositionShader" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 } 7 SubShader 8 { 9 Cull Off ZWrite Off ZTest Always 10 11 Pass 12 { 13 CGPROGRAM 14 #pragma vertex vert 15 #pragma fragment frag 16 17 #include "UnityCG.cginc" 18 19 struct appdata 20 { 21 float4 vertex : POSITION; 22 float2 uv : TEXCOORD0; 23 }; 24 25 struct v2f 26 { 27 float2 uv : TEXCOORD0; 28 float4 vertex : SV_POSITION; 29 }; 30 31 v2f vert (appdata v) 32 { 33 v2f o; 34 o.vertex = UnityObjectToClipPos(v.vertex); 35 o.uv = v.uv; 36 return o; 37 } 38 39 sampler2D _MainTex; 40 sampler2D _UITexBeforeEffects; 41 sampler2D _UITexAfterEffects; 42 43 fixed4 frag(v2f i) : SV_Target 44 { 45 // シーン描画結果にUI描画結果をアルファブレンド 46 // このとき、UIのRGBはエフェクト処理後の、Aはエフェクト処理前のものを使用する 47 fixed3 mainColor = tex2D(_MainTex, i.uv).rgb; 48 fixed3 uiColor = tex2D(_UITexAfterEffects, i.uv).rgb; 49 fixed uiAlpha = tex2D(_UITexBeforeEffects, i.uv).a; 50 // ここでもアルファ除去シェーダーの場合と同じく、UI用マテリアルに修正を加えていない場合は 51 // fixed uiAlpha = sqrt(tex2D(_UITexBeforeEffects, i.uv).a); としてやる必要があるでしょう 52 fixed3 resultColor = (uiColor * uiAlpha) + (mainColor * (1.0 - uiAlpha)); 53 54 return fixed4(resultColor, 1.0); 55 } 56 ENDCG 57 } 58 } 59}

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

プレビュー

投稿2018/04/08 22:33

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問