Unity でテクスチャの色を Jobs/Burst で処理できる NativeArray の形で取得できる Texture2D.GetPixelData
の使い方をまとめます。
Unity 2021.3.0f1
はじめに
Unity2020.1 から Texture2D.GetPixelData()
というAPIが新しく追加されました。
このメソッドは Texture2D.GetPixels()
のように Color 型の配列を返すのではなく、NativeArray<Color>
を返します。
つまり、テクスチャの色をC#で頻繁に変更するようなケースにおいて、Job システム や Burst コンパイラによる高速化を行うことができます。
本記事ではこの API の使い方についてまとめます。
使い方
以下は Job システムなどと組み合わせていない、この API の簡単な使い方です。
using UnityEngine; using UnityEngine.UI; public sealed class Example : MonoBehaviour { [SerializeField] private Vector3 _colorSeed; [SerializeField] private RawImage _rawImage; private Texture2D _texture; private void Update() { // テクスチャの色情報をNativeArrayで取得 var pixelData = _texture.GetPixelData<Color32>(0); // 色を適当に変更する var seeds = _colorSeed + Vector3.one * Time.time; for (var i = 0; i < pixelData.Length; i++) { var p = (float)i / pixelData.Length; pixelData[i] = GetColor(p, seeds); } // GPUにアップロード _texture.Apply(); } public void OnEnable() { var tex = new Texture2D(128, 128, TextureFormat.RGBA32, false); _rawImage.texture = tex; _texture = tex; } private void OnDisable() { Destroy(_texture); } // 適当に色を作って返すメソッド private static Color GetColor(float p, Vector3 s) { var r = 0.5f + 0.5f * Mathf.Cos(Mathf.PI * 2 * (p + s.x)); var g = 0.5f + 0.5f * Mathf.Cos(Mathf.PI * 2 * (p + s.y)); var b = 0.5f + 0.5f * Mathf.Cos(Mathf.PI * 2 * (p + s.z)); return new Color(r, g, b); } }
説明はコメントの通りです。
結果は以下のようになります(実際にはアニメーションします)。
Color Seed プロパティを変更することでグラデーションのかかり方が変わります。
Jobシステム・Burstコンパイラと組み合わせたサンプル
さて実際にはこれを Job システムによりマルチスレッド化したり、Burst コンパイラにより高速化したりします。
このサンプルと処理速度の比較については、以下の公式リポジトリがわかりやすいです。
リポジトリの内容としては、下図のようなプロシージャルテクスチャを毎フレーム更新するものになります(実際にはアニメーションします)。
以下の4パターンで処理を分け、処理速度が比較されているので、その結果を以下に転載します。
(計測環境は 2019 MacBookPro(Core i9 2.4GHz, 8 cores / 16 threads) とのことです。)
処理 | 速度 |
---|---|
Texture2D.SetPixel() を使ってシングルスレッドで処理(Texture2D.GetPixelData() は使わない) | 140ms |
Texture2D.SetPixels() を使ってシングルスレッドで処理(Texture2D.GetPixelData() は使わない) | 113ms |
Texture2D.GetPixelData() でNativeArray を取得して Burst コンパイラを適用 | 17ms |
Texture2D.GetPixelData() でNativeArray を取得して Job システムと Burst コンパイラを適用 | 1.7ms |
Job システムによるマルチスレッド化と Burst コンパイラの効果が明確に表れていることが確認できます。