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

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

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

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

Q&A

0回答

5947閲覧

カメラにOnRenderImageを含むスクリプトがアタッチされていると、Multiple Render Targetsが無視される

ItoZakura

総合スコア8

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

0グッド

0クリップ

投稿2016/03/22 08:22

###実現したいことと、起こっている問題
Unity5.3.4f1を使用しています。
オブジェクトの描画時にMultiple Render Targets(MRT)を使用し、通常の描画と並行してそのオブジェクトに関する値を別のRenderTextureに書き込み、それを後段のImageEffectで使用したいと考えています。

しかし、ImageEffectを行うためのOnRenderImageをカメラのスクリプトに追加するとMRTが無視されてしまい、値を書き込んだRenderTextureをImageEffectまで持ってくることができません。

###具体的な状況
テストとして以下のようなシーンを作成しました。

  • カメラ - 画面と同じ大きさのRenderTextureを2枚作成し、SetTargetBuffersでそれらを描画先として指定するスクリプトをアタッチ
  • オブジェクト - 通常描画をSV_Target0、赤成分のみをSV_Target1に出力するシェーダで描画される

下の画面写真は、テストシーンの描画履歴をFrameDebuggerで表示したものです。
描画先としてRT0とRT1がリストに表示されており、RT1には赤成分が書き込まれています。ここまでは成功です。
このRenderTexture(RT1)を後段のImageEffectで使用したいと考えています。
OnrenderImageなし

しかし、カメラにアタッチしたスクリプトにOnRenderImageを追加すると、MRTが無視されてしまいます。
下の画面写真はOnRenderImageを追加した状態のものですが、リストにはRT0しかなく、RenderTargetも「ImageEffects Temp」という、こちらで作成したRenderTextureではないものが指定されています。
OnrenderImageあり

OnRenderImage とMRTを併用することはできないのでしょうか?

###ソースコード
以下に、テストに使用したコードを掲載します。

    • カメラにアタッチするスクリプト(OnRenderImage あり/なし の2種類)
    • RenderTextureの内容を表示するためのシェーダ
    • MRTを使用するオブジェクトのマテリアル用のシェーダ

カメラにアタッチするスクリプトの、OnRenderImage なしのものです。

CSharp

1using UnityEngine; 2using System.Collections; 3 4public class MRTCameraTest : MonoBehaviour 5{ 6 public RenderTexture[] RT; 7 public Material postmat; 8 private Camera cam; 9 10 // Use this for initialization 11 void Start() 12 { 13 cam = GetComponent<Camera>(); 14 15 RT = new RenderTexture[2]; 16 for (int i = 0; i < 2; i++) 17 { 18 int Depth = i == 0 ? 24 : 0; 19 RT[i] = new RenderTexture(Screen.width, Screen.height, Depth); 20 RT[i].Create(); 21 } 22 23 RenderBuffer[] rb = new RenderBuffer[2]; 24 for (int i = 0; i < 2; i++) 25 rb[i] = RT[i].colorBuffer; 26 27 cam.SetTargetBuffers(rb, RT[0].depthBuffer); 28 } 29 30 // Update is called once per frame 31 void Update() 32 { 33 } 34 35 void OnPostRender() 36 { 37 // render to screen 38 Graphics.SetRenderTarget(null); 39 //Graphics.Blit(RT[0], postmat); // standard 40 Graphics.Blit(RT[1], postmat); // red only 41 } 42} 43

OnRenderImageありの場合、OnPostRender以降が下のように差し替わります。

CSharp

1 void OnPostRender() 2 { 3 } 4 5 void OnRenderImage(RenderTexture source, RenderTexture destination) 6 { 7 RenderTexture tmpRT = RenderTexture.GetTemporary(256, 256, 0); // confirm value of RenderTexture on FrameDebugger 8 //Graphics.Blit(RT[0], tmpRT, postmat); 9 Graphics.Blit(RT[1], tmpRT, postmat); 10 11 Graphics.Blit(source, destination); 12 } 13

RenderTextureの内容をそのまま画面に表示するためのシェーダです。
このシェーダを割り当てたマテリアルを作成し、カメラスクリプトの postmat に指定して使用します。

HLSL

1// Created by 2// Create > Shader > Image Effect Shader 3 4Shader "Custom/Post Only" 5{ 6 Properties 7 { 8 _MainTex ("Texture", 2D) = "white" {} 9 } 10 SubShader 11 { 12 // No culling or depth 13 Cull Off ZWrite Off ZTest Always 14 15 Pass 16 { 17 CGPROGRAM 18 #pragma vertex vert 19 #pragma fragment frag 20 21 #include "UnityCG.cginc" 22 23 struct appdata 24 { 25 float4 vertex : POSITION; 26 float2 uv : TEXCOORD0; 27 }; 28 29 struct v2f 30 { 31 float2 uv : TEXCOORD0; 32 float4 vertex : SV_POSITION; 33 }; 34 35 v2f vert (appdata v) 36 { 37 v2f o; 38 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); 39 o.uv = v.uv; 40 return o; 41 } 42 43 sampler2D _MainTex; 44 45 fixed4 frag (v2f i) : SV_Target 46 { 47 fixed4 col = tex2D(_MainTex, i.uv); 48 // just invert the colors 49 //col = 1 - col; 50 return col; 51 } 52 ENDCG 53 } 54 } 55} 56

オブジェクトのマテリアルに割り当てるシェーダです。
オブジェクトの通常の描画結果をSV_Target0、赤成分をSV_Target1に出力します。
長いのでここに全体を載せることは出来ないのですが、以下の手順で作成したものです。

  • Create > Shader > Standard Surface Shader でsurfaceシェーダを作成
  • インスペクタから「Show generated code」で同内容のVertex/Fragmentシェーダを表示
  • MRT用の出力構造体(ps_out_multi)を追加

HLSL

1struct ps_out_multi 2{ 3 fixed4 diffuse : SV_Target0; 4 fixed4 sub : SV_Target1; 5}; 6
  • frag_surfの返値の型を変更し、通常描画をSV_Target0、赤成分をSV_Target1に出力

HLSL

1ps_out_multi frag_surf (v2f_surf IN) { 2 // prepare and unpack data 3 4 //// (中略) 5 6 UNITY_OPAQUE_ALPHA(c.a); 7 8 ps_out_multi pom; 9 pom.diffuse = c; // all color > SV_Target0 10 pom.sub = fixed4(c.r, 0, 0, 1); // red only > SV_Target1 11 12 return pom; 13} 14

###まとめ
長くなってしまいましたが、当方の疑問としては以下の2点です。

  • 何故 OnRenderImage がカメラスクリプトに含まれていると、SetTargetBuffersによる描画先指定が無視されてしまうのか?
  • MRTによって書き込んだRenderTextureを後段のImageEffectで使用する方法は無いのか?

これらについて、何かご存知の方がいらっしゃいましたら、ご教示いただけますと幸いです。
どうぞよろしくお願いいたします。

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

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

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

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問