WebGLでバッファやテクスチャなどを扱うと、ArrayBufferとArrayBufferViewを扱わなければなりません。この際、ArrayBufferとArrayBufferViewの適切な理解をしなければ多くのメモリを使ってしまったり、パフォーマンスを落としてしまったりすることがあります。
ArrayBufferとArrayBufferView
まず、ArrayBufferは、途中で容量を拡張したりすることができない要素が連続した配列つまりは、C++やJavaにおける標準的な配列です。C++で扱うときは、配列の途中のポインタを取れば、その途中のインデックスが0のように扱えるように、連続していることができます。
int* arr = new int[100];
int* arr2 = arr + 10;
int a = arr2[0]; // arrの10番目
(Cで書いたような例(最近ふれていないので何か間違っているかもしれない))
このように、配列の途中からの要素をあたかも別の配列のように見えるようにするポインタ的存在がArrayBufferViewです。
TypedArray
UInt8Array
やUInt16Array
など型名が入っている配列はTypedArray
と言います。 これは、実はArrayBuffer
のように見えてArrayBufferView
のような存在です。
つまり、以下のようなことをしても実際にメモリに確保されてるのは、ArrayBuffer
の100バイト分になります。
const arr = new ArrayBuffer(100);
const arr2 = new UInt8Array(arr,10);
const a = arr2[0];
要するに、ただ単にオフセットを指定して、あたかも配列のように扱わせる、ポインタのようなものかつ、型を指定して値を取れるためのものがTypedArray
です。
TypedArray
はサイズをコンストラクタにとってそのサイズ分の配列を作成することができます。
const arr = new UInt8Array(100);
しかし、これはあくまで以下の別記法にすぎません。
const arr = new UInt8Array(new ArrayBuffer(100),0);
したがって、コンストラクタにサイズを指定したとき以外、TypedArray
では実際の配列が確保されることはありません。
ArrayBuffer#slice()
sliceをすると、ArrayBuffer
の指定した部分だけコピーすることができます。しかし、これはTypedArray
などの役割とは異なり、実際にArrayBuffer
がコピーされます。したがって、その分だけ利用しているメモリは増えます。
おわり
以上、雑でしたが無駄に配列をコピーしてしまうことのないよう、素晴らしいパフォーマンスをWebGLで実現したいですね!