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

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

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

ARKitは、iPhone/iPad向けのARアプリ用フレームワーク。iOS11以降に標準搭載されています。これを用いたARアプリは、特殊なデバイスがなくてもiPhone/iPadの単眼カメラを使用して動作することが可能です。

C#

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

Unity

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

Q&A

解決済

1回答

3539閲覧

【Unity】CommandBufferを使用してキャプチャーした画像が逆さまになる

nakamu

総合スコア82

ARKit

ARKitは、iPhone/iPad向けのARアプリ用フレームワーク。iOS11以降に標準搭載されています。これを用いたARアプリは、特殊なデバイスがなくてもiPhone/iPadの単眼カメラを使用して動作することが可能です。

C#

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

Unity

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

1グッド

0クリップ

投稿2020/02/20 14:12

編集2020/02/21 05:06

ARのスクショ時にGUIを消したいのでこちらを参照しました。
特定のUIを除いて画面のスクリーンショットを撮影する

今回はリンク内にあるmainCameraの部分をCamera.mainではなく、AR Cameraでやっております。
その結果、GUIは消せたのですが、スクショした画像が逆さまになってしまい解決法がわからずにいます。

イメージ説明

イメージ説明
イメージ説明
イメージ説明

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using System.IO; 5using UnityEngine.Rendering; 6 7 8public class ScreenShot : MonoBehaviour 9{ 10 11 public event System.Action<RenderTexture> OnCaptured; 12 13 [SerializeField, Tooltip("GUIをレンダリングしているカメラ")] 14 private Camera _guiCamera = null; 15 16 [SerializeField, Tooltip("キャプチャするタイミング")] 17 private CameraEvent _cameraEvent = CameraEvent.BeforeImageEffects; 18 19 [SerializeField, Tooltip("合成時に無視されるUIのレイヤー")] 20 private LayerMask _captureTargetLayer = -1; 21 22 [SerializeField, Tooltip("ARカメラ")] 23 private Camera _mainCamera = null; 24 private RenderTexture _buf = null; 25 private CommandBuffer _commandBuffer = null; 26 27 #region ### MonoBehaviour ### 28 29 private void Awake() 30 { 31 CreateBuffer(); 32 } 33 /// <summary> 34 /// 動作確認用にGizmoでテクスチャを表示する 35 /// </summary> 36 private void OnGUI() 37 { 38 if (_buf == null) return; 39 GUI.DrawTexture(new Rect(5f, 5f, Screen.width * 0.5f, Screen.height * 0.5f), _buf); 40 } 41 42 public void OnClick() 43 { 44 TakeScreenshot(); 45 } 46 47 #endregion ### MonoBehaviour ### 48 49 /// <summary> 50 /// バッファを生成する 51 /// </summary> 52 private void CreateBuffer() 53 { 54 _buf = new RenderTexture(Screen.width, Screen.height, 0); 55 56 _commandBuffer = new CommandBuffer(); 57 _commandBuffer.name = "CaptureScene"; 58 _commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, _buf); 59 } 60 61 /// <summary> 62 /// スクリーンショットを撮影する 63 /// </summary> 64 public void TakeScreenshot() 65 { 66 AddCommandBuffer(); 67 68 StartCoroutine(WaitCapture()); 69 } 70 71 /// <summary> 72 /// コマンドバッファの処理を待つ 73 /// </summary> 74 private IEnumerator WaitCapture() 75 { 76 yield return new WaitForEndOfFrame(); 77 78 BlendGUI(); 79 80 if (OnCaptured != null) 81 { 82 OnCaptured.Invoke(_buf); 83 } 84 85 RemoveCommandBuffer(); 86 } 87 88 /// <summary> 89 /// GUI要素をブレンドする 90 /// </summary> 91 private void BlendGUI() 92 { 93 _guiCamera.targetTexture = _buf; 94 95 int tmp = _guiCamera.cullingMask; 96 _guiCamera.cullingMask = _captureTargetLayer; 97 98 _guiCamera.Render(); 99 100 _guiCamera.cullingMask = tmp; 101 102 _guiCamera.targetTexture = null; 103 } 104 105 /// <summary> 106 /// メインカメラにコマンドバッファを追加する 107 /// </summary> 108 private void AddCommandBuffer() 109 { 110 _mainCamera.AddCommandBuffer(_cameraEvent, _commandBuffer); 111 } 112 113 /// <summary> 114 /// メインカメラからコマンドバッファを削除する 115 /// </summary> 116 private void RemoveCommandBuffer() 117 { 118 if (_mainCamera == null) 119 { 120 return; 121 } 122 123 _mainCamera.RemoveCommandBuffer(_cameraEvent, _commandBuffer); 124 } 125 126} 127

追加添付
イメージ説明

taro.nn👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

もしかして「Edit」→「Project Settings...」の「Other Settings」→「Graphics APIs for Mac」が「Metal」の時だけ反転したりしますかね?
試しにScreenShotスクリプトの「Camera Event」を一段階手前の「After Forward Alpha」に変更してみるとどうでしょうか。もしそれでは改善しない、あるいは他の問題が発生するようでしたら何か別の手を考えてみます。

ScreenShot改造案

まず下記のようなY軸反転シェーダーを用意して...

ShaderLab

1Shader "Hidden/FlipY" 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 o.uv.y = 1.0 - o.uv.y; 37 return o; 38 } 39 40 sampler2D _MainTex; 41 42 fixed4 frag(v2f i) : SV_Target 43 { 44 return tex2D(_MainTex, i.uv); 45 } 46 ENDCG 47 } 48 } 49}

ScreenShotにフィールドを追加、CreateBufferメソッド中にY軸反転処理を組み込んでみました。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using System.IO; 5using UnityEngine.Rendering; 6using System; 7 8public class ScreenShot : MonoBehaviour 9{ 10 11 public event System.Action<RenderTexture> OnCaptured; 12 13 [SerializeField, Tooltip("GUIをレンダリングしているカメラ")] 14 private Camera _guiCamera = null; 15 16 [SerializeField, Tooltip("キャプチャするタイミング")] 17 private CameraEvent _cameraEvent = CameraEvent.BeforeImageEffects; 18 19 [SerializeField, Tooltip("合成時に無視されるUIのレイヤー")] 20 private LayerMask _captureTargetLayer = -1; 21 22 [SerializeField, Tooltip("ARカメラ")] 23 private Camera _mainCamera = null; 24 25 // ここに前述のY反転シェーダーをセットしておく 26 [SerializeField, Tooltip("Y反転シェーダー")] 27 private Shader _flipYShader; 28 private Material _flipYMaterial; 29 30 private RenderTexture _buf = null; 31 private CommandBuffer _commandBuffer = null; 32 33 #region ### MonoBehaviour ### 34 35 private void Awake() 36 { 37 CreateBuffer(); 38 } 39 /// <summary> 40 /// 動作確認用にGizmoでテクスチャを表示する 41 /// </summary> 42 private void OnGUI() 43 { 44 if (_buf == null) return; 45 GUI.DrawTexture(new Rect(5f, 5f, Screen.width * 0.5f, Screen.height * 0.5f), _buf); 46 } 47 48 public void OnClick() 49 { 50 TakeScreenshot(); 51 } 52 53 #endregion ### MonoBehaviour ### 54 55 /// <summary> 56 /// バッファを生成する 57 /// </summary> 58 private void CreateBuffer() 59 { 60 _buf = new RenderTexture(Screen.width, Screen.height, 0); 61 62 _commandBuffer = new CommandBuffer(); 63 _commandBuffer.name = "CaptureScene"; 64 if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Metal) 65 { 66 // Metal上で動作している場合、CurrentActiveを一旦別のレンダーテクスチャに写し取り 67 // それをさらにY反転シェーダーを通して_bufにレンダリングする 68 if (_flipYMaterial == null) 69 { 70 _flipYMaterial = new Material(_flipYShader); 71 } 72 int tempTexture = Shader.PropertyToID("_TempTex"); 73 _commandBuffer.GetTemporaryRT(tempTexture, -1, -1); 74 _commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, tempTexture); 75 _commandBuffer.Blit(tempTexture, _buf, _flipYMaterial); 76 _commandBuffer.ReleaseTemporaryRT(tempTexture); 77 } 78 else 79 { 80 _commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, _buf); 81 } 82 } 83 84 /// <summary> 85 /// スクリーンショットを撮影する 86 /// </summary> 87 public void TakeScreenshot() 88 { 89 AddCommandBuffer(); 90 91 StartCoroutine(WaitCapture()); 92 } 93 94 /// <summary> 95 /// コマンドバッファの処理を待つ 96 /// </summary> 97 private IEnumerator WaitCapture() 98 { 99 yield return new WaitForEndOfFrame(); 100 101 BlendGUI(); 102 103 if (OnCaptured != null) 104 { 105 OnCaptured.Invoke(_buf); 106 } 107 108 RemoveCommandBuffer(); 109 } 110 111 /// <summary> 112 /// GUI要素をブレンドする 113 /// </summary> 114 private void BlendGUI() 115 { 116 _guiCamera.targetTexture = _buf; 117 118 int tmp = _guiCamera.cullingMask; 119 _guiCamera.cullingMask = _captureTargetLayer; 120 121 _guiCamera.Render(); 122 123 _guiCamera.cullingMask = tmp; 124 125 _guiCamera.targetTexture = null; 126 } 127 128 /// <summary> 129 /// メインカメラにコマンドバッファを追加する 130 /// </summary> 131 private void AddCommandBuffer() 132 { 133 _mainCamera.AddCommandBuffer(_cameraEvent, _commandBuffer); 134 } 135 136 /// <summary> 137 /// メインカメラからコマンドバッファを削除する 138 /// </summary> 139 private void RemoveCommandBuffer() 140 { 141 if (_mainCamera == null) 142 { 143 return; 144 } 145 146 _mainCamera.RemoveCommandBuffer(_cameraEvent, _commandBuffer); 147 } 148 149}

_commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, _buf, _flipYMaterial);とせずにわざわざtempTextureに写してから反転していますが、これはCurrentActiveがテクスチャではなくレンダーバッファであるケースを考慮したものです。
どうやらBlitはソース側がテクスチャでない場合、シェーダーを通してのレンダリングができないために代わりに単純なビットブリット的な処理(Texture2D.ReadPixelsのようなもの?)を行うらしく、独自のマテリアルを使っての加工ができなそうだったためあのようにしました。

投稿2020/02/20 21:10

編集2020/02/21 21:08
Bongo

総合スコア10807

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

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

nakamu

2020/02/21 05:08

Bongo様 ご回答ありがとうございます。 実機でテストしてるのですが、Autoの状態です。(追加で添付しております) Autoの状態でAfter Forward Alphaにしましたが変化ありません
Bongo

2020/02/21 21:10

ダメでしたか...「Camera Event」はとりあえず元通り「Before Image Effects」に戻してしまってください。 Unityは座標系の上下みたいな環境の違いを大抵は勝手に直してくれるのでありがたいのですが、どうも今回の場合はそれが機能していないような気がします。自前で反転させる案を追記しましたが、これならどうでしょう。 それと念のため確認したいのですが、Unityエディターのウィンドウのタイトルバーの右端にどのグラフィックスシステムを使っているかが表示されていると思うのですが、「<Metal>」になっていますでしょうか?
nakamu

2020/02/22 09:41

>>それと念のため確認したいのですが、Unityエディターのウィンドウのタイトルバーの右端にどのグラフィックスシステムを使っているかが表示されていると思うのですが、「<Metal>」になっていますでしょうか? こちら先にご回答致します。 確認しましたところ<Metal>の表記になっております
nakamu

2020/02/22 11:28

ScreenShot改造案の結果、反転せずにしっかり正常な形で実機のアルバムに保存できました! やはり当初からBongo様がご指摘していた通りMetalが絡んでるみたいですね。 Blit周りの解説もありがとうございます! Bongo様ご対応頂きありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問