インデックスバッファを用いた描画の概要
gl.drawArrays()
による描画には、3 つの三角形の描画モードがあり、連なった三角形を描画するときには、gl.TRIANGLE_STRIP
あるいは gl.TRIANGLE_FAN
の描画モードを使用すると、頂点情報を使い回しながら効率的に描画することができます。
ただし、図形が少し複雑になってくると、一度の gl.drawArrays()
呼び出しではうまく描画できなくなってきます。
例えば次のような 3 つの三角形(トライフォース)を描画することを考えてみます。
面 A、B、C は独立した三角形に見えるので、それぞれに 3 つの頂点(合計 9 頂点)を用意して gl.drawArrays()
の gl.TRIANGLES
モードでレンダリングすればよさそうですが、頂点 1、2、4 に関しては座標が同じなので、本来であれば上記のように 6 つの頂点情報を用意するだけで足りそうです。
このような場合は、インデックスバッファと gl.drawElements() を使用すると、効率的な描画を行えます。
頂点バッファオブジェクト (VBO) に座標情報を入れておくのは gl.drawArrays()
を使った場合と同様ですが、もう一つ別のバッファオブジェクトとして、インデックスバッファオブジェクト (IBO: Index Buffer Object) を作成します。
IBO には、VBO 内のどの頂点情報を使って図形描画を行うかを示す、頂点インデックスの情報を格納します。
- 頂点バッファオブジェクト (VBO)
- 頂点情報(座標、色など)を重複しないように格納する。
- 上記の例では、頂点 0~5 の 6 つの頂点情報を格納する。
- インデックスバッファオブジェクト (IBO)
- 図形描画に VBO 内のどの頂点情報を使うかを示すインデックス配列。
- 上記の例では、面Aは 0,1,2、面Bは 1,3,4、面Cは 2,4,5 の頂点を使用するという情報。一次元で、0,1,2,1,3,4,2,4,5 と格納すればよい。
実装
ここでは、各頂点に異なる色をつけたトライフォースを描画してみます。
頂点バッファオブジェクト (VBO) を作成する
頂点バッファオブジェクトの作成方法は、gl.drawArrays()
で描画する場合と同様です。
ここでは、ひとつのバッファオブジェクト内にインターリーブする形で頂点座標と頂点カラーを格納し、それぞれ a_Position
、a_Color
という attribute 変数で 1 つずつ取り出せるように設定しています。
インデックスバッファオブジェクト (IBO) を作成する
インデックス情報を格納するためのバッファオブジェクトも、VBO と同様に gl.createBuffer()
で作成します。
ただし、gl.bindBuffer()
と gl.bufferData()
のターゲットには gl.ELEMENT_ARRAY_BUFFER
を指定します(gl.ARRAY_BUFFER
ではない)。
OpenGL ES の仕様では、インデックスバッファの各要素は、gl.UNSIGNED_BYTE
型、あるいは gl.UNSIGNED_SHORT
型の値でなければいけないため、JavaScript 側の頂点インデックス配列も Uint8Array
型(gl.UNSIGNED_BYTE
に対応)で作成しています。
gl.drawElements() で描画する
VBO と IBO の作成が終わったら、後は gl.drawElements
を使って描画を行います。
それぞれの面(三角形)には独立した頂点インデックスが 3 つずつ与えられているため、第1引数 (mode) の描画モードとしては gl.TRIANGLES
を指定すれば OK です。
第2引数 (count) には頂点インデックスの数(IBO の要素数)、第3引数 (type) には頂点インデックスの型(ここでは gl.UNSIGNED_BYTE
)、第4引数 (offset) には使用するデータのバイトオフセット(IBO の先頭から参照するなら 0 でよい)を指定します。