OpenGLの使い方:バッファ編
目標
バッファは用途に応じて扱い方が幾分異なりますが,ここでは個別の扱い方には触れず共通する項目を取り上げます.
バッファオブジェクト
バッファオブジェクトはバッファの諸々を管理するOpenGLオブジェクトです.
他の例に漏れず, glGenBuffers で生成, glBindBuffer で target にバインド,glDeleteBuffers で破棄します.
// 生成
GLuint buffer;
glGenBuffers(1, &buffer);
// バインド
GLenum target;
glBindBuffer(target, buffer);
// バインドを解除
glBindBuffer(target, 0);
// 破棄
glDeleteBuffers(1, &buffer);
以下では特に明示しない限り, target にバインドされたバッファが対象になります.
領域の確保
glBufferData で領域を確保します.確保する大きさを size に,初期データを data に渡します. data が NULL であれば領域の確保のみを行い初期化はしません. usage は領域へのアクセス頻度や方法に応じて適切な値を指定します.
GLsizeiptr size;
const GLvoid* data;
GLenum usage;
void glBufferData(target, size, data, usage);
マッピング
glMapBufferRange は offset から length バイト分の範囲に対してCPUから領域にアクセスが可能なポインタを返します. access はユーザが必要とするアクセス方法などを指定します.
使い終わったら glUnmapBuffer でマップしたポインタを無効化します.
// マップ
GLintptr offset;
GLsizeiptr length;
GLbitfield access;
void* mapped_data = glMapBufferRange(target, offset, length, access);
// アンマップ
glUnmapBuffer(target);
メモ
glBufferData
usage には領域へのアクセス頻度(STATIC, STREAM, DYNAMIC)やその方法(DRAW, READ, COPY)に応じて適切な値を指定します.
実際には,バッファの用途により決めるのが良いと思います.例えば,内容に変化の少ない頂点バッファには GL_STATIC_DRAW を,描画処理毎に書き換える必要があるUniformバッファには GL_DYNAMIC_DRAW を,パーティクルシステムを構成する変換フィードバックバッファには GL_STREAM_COPY を指定する,などです.
glMapBufferRange
access に GL_MAP_WRITE_BIT と合わせて GL_MAP_INVALIDATE_RANGE_BIT または GL_MAP_INVALIDATE_BUFFER_BIT を指定することで,マップされるときに領域の一部または全部を無効化することができます.領域を無効化するとそれまでに書き込まれたデータがすべて破棄されますが,領域が最新の状態であるかにかかわらずマップできるので,パフォーマンスの向上が期待できます.
しかし無効化された領域を読み取ろうとすると予期せぬ動作を引き起こすので,無効化された領域は残さず上書きする必要があります.
領域の更新
バッファの領域を更新するには glBufferSubData を使うことができます. glBufferSubData は glMapBufferRange と異なり,必要なデータを予めメモリ上に用意しておく必要があります.
バッファ間コピー
OpenGL3.1以上であれば, glCopyBufferSubData によりバッファ間でデータのコピーが可能です.