UnityでGPU上のRenderTextureのピクセル情報を非同期的に取得するAsyncGPUReadbackについてまとめました。
Unity2019.4.0
RenderTextureのピクセル情報を取得する方法と問題点
いま、RenderTextureからピクセル情報を取得することを考えます。
RenderTextureのデータは少し特殊でGPU上にしか存在しないため、ちょっと回りくどいことをする必要があります。
まず同期的に読み込むには以下の記事のようにRenderTexture.activeに設定したRenderTextureの情報をTexture2D.ReadPixels()で読むという方法を使います。
ただしこの方法は処理負荷が高いため、データサイズによっては一瞬画面が固まってしまったりします。
AsyncGPUReadbackで非同期的に取得
そこでAsyncGPUReadbackを使うとRenderTextureの情報を非同期的に取得することができます。
AsyncGPUReadbackは以下のようにして使用します。
using UnityEngine; using UnityEngine.Assertions; using UnityEngine.Rendering; using UnityEngine.UI; public class AsyncGPUReadbackExample : MonoBehaviour { [SerializeField] private Camera _camera; [SerializeField] private RawImage _ui; private void Start() { Assert.IsNotNull(_camera); Assert.IsNotNull(_ui); // カメラの描画結果をRenderTextureに描画する var rt = RenderTexture.GetTemporary(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32); var oldTarget = _camera.targetTexture; _camera.targetTexture = rt; _camera.Render(); _camera.targetTexture = oldTarget; // GPU上にあるピクセル情報を取得する AsyncGPUReadback.Request(rt, 0, request => { if (request.hasError) { // エラー Debug.LogError("Error."); } else { // データを取得してTexture2Dに反映する var data = request.GetData<Color32>(); var texture = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false); texture.LoadRawTextureData(data); texture.Apply(); // UIに反映 _ui.texture = texture; // 元のRenderTextureはもういらないので解放 RenderTexture.ReleaseTemporary(rt); } }); } }
使える環境について
AsyncGPUReadbackはすべてのプラットフォームで使えるわけではありません。
Windowsに対応しているのと、Unity2018.3からはMetalに対応しています。
[2021.08.17 追記] Vulkanでも使えるようです。
対応しているかどうかはSystemInfoで調べられるので、マルチプラットフォーム対応する場合にはこれを使って同期処理と分岐する必要がありそうです。