DOTS…特にECSで色々とやっていると、内部のデータは同じなのに型が違うせいで変換しないといけないというケースがあります。
例えば float
のバッファを流し込んでバッチ処理を行うAPIがあった時、ローカルのデータで NativeArray<FloatData>
のような構造体の配列は直接流し込めません。しかしメモリ的にはこの二つはほぼ同じものです。そこで Reinterpret<T, U>()
でデータを再解釈して NativeArray<FloatData>
を NativeArray<float>
として扱ってみます。
動かない例
例えば下のようなコードがあったとします。 MyData
という構造体が定義されていて、これを ShowFloatLog(NativeArray<float> inputs)
で一気に表示したい。当然MyDataは中身がfloatであっても扱いはfloatではないので、下のコードはエラーになります。
using Unity.Collections; using UnityEngine; struct MyData { public float Value; } public class Sample: MonoBehaviour { void Start() { var input1 = new NativeArray<MyData>(new[] { new MyData { Value = 11 }, new MyData { Value = 22 }, new MyData { Value = 33 }, }, Allocator.Temp); ShowLog(input1 ); input1.Dispose(); } static void ShowFloatLog(NativeArray<float> inputs) { foreach (var data in inputs) Debug.Log(data); } }
Reinterpret<T, U>()で異なる型へ「再解釈」する
Reinterpret<T, U>()
を使用して、NativeArray<MyData>()を
NativeArrayCollection
パッケージに含まれているので、パッケージのインポートが必要です。
下のように使用します。MyDataの中身がfloatしかないので、floatと解釈することが出来ています。なお、あくまで解釈してるだけなのでDisposeはしてはいけません。参照先のポインタは同じものです。
void Start() { var input1 = new NativeArray<MyData>(new[] { new MyData { Value = 11 }, new MyData { Value = 22 }, new MyData { Value = 33 }, }, Allocator.Temp); // MyDataをFloatに再解釈 var floatInput = input1.Reinterpret<MyData, float>(); // NativeArray<float>なので動作 ShowLog(floatInput); input1.Dispose(); }
この再解釈はポインタ的に、内部データが同じなら色々なデータに解釈できるみたいです。例えばfloat3の配列をfloatに解釈するといった事も可能です。当然、データの長さが異なるので注意が必要ですが、少し面白いと思わなくもないです。
なお float3 -> float
の場合は特に問題は無いですが、 float -> float3
の場合は3で割り切れる数の要素数でないとエラーになります。多い方がベクタライズに有利になりやすいみたいですが、そこのところは注意が必要です。
void Start() { var input1 = new NativeArray<float3>(new[] { new float3(111, 222, 33), new float3(444, 555, 666), new float3(777, 888, 999), }, Allocator.Temp); // float3をfloatに再解釈 var floatInput = input1.Reinterpret<float3, float>(); // output : input length 3, reinterpret length 9 // float3をfloatにするにあたり、配列の長さが変わっている Debug.Log($"input length {input1.Length}, reinterpret length {floatInput.Length}"); // 111 ~ 999 までの要素を個別に出力 ShowLog(floatInput); input1.Dispose(); }
感想
NativeArray<Vector3>
を返してくる古いAPIと、NativeArray<float3>
を要求する新しいAPIの間で苦しんだ時に思い出すと幸せになるかも。