VBOとは?

目次

  • VBOとは
  • VBOがどのようなデータを格納するのか?
  • VBOの作り方(従来バージョンと最新バージョン)
  • VBOの値を変更してみよう

 

一、VBOとは

→VBO=Vertex Buffer Object

→バッファオブジェクトであり、GPU上に作られる。

→格納するデータは頂点データ(座標、色情報など)

OpenGLにて描画するために最も基礎的部分(VBO→VAO→Vertex Puller)

 

 VBOはVertex Buffer Object(頂点バッファ―オブジェクト)の頭文字からなる。

 GPUメモリに作られるバッファオブジェクト(データを格納するメモリ上の領域)の一種である。データを格納するメモリ上の領域というのは、例えば、glGenBuffersを呼び出しでも、バッファーオブジェクトはまだ作られておらず、領域だけ確保されている状態である。

 OpenGLにて描画するためには、煩雑なプロセスを辿らないと描画できない。簡単に説明すると、頂点データを持っているVBOをたくさん集めて、このようなVBOの集まりをVertex Array Object(VAO)と呼ぶ。そしてOpenGLの描画手順Graphics PipelineのVertex Pullerにより、描画に必要なだけの頂点データが取られて描画に進むという流れになる。

 glDeleteBuffers

二、VBOにはどのようなデータが格納できるのか

 

三、VBOの作り方

方法①:

1.glGenBuffers(GLsizei n, GLuint *buffers);

 こちらの関数を呼び出してバッファーのID(names)を予約する(中身が空で領域も割り当てておらず、IDだけ生成される)。nには作成する個数、buffersにはバッファ―オブジェクトのID(names)の格納先のポインタを指定する。

 glGenBuffersは作成されたID(names)が連続であることを保証しない。例えば一気にバッファーオブジェクトを五個作成しても、必ずしも1から5という連続的な値が割り当てられるというわけではない。ただし、割り当てられたID(names)はglGenBuffersを呼び出した時点で必ず使用されていないことが保障されている。

 glDeleteBuffersによりバッファーオブジェクトのID(names)が削除されてから、glGenBuffersではこのID(names)を再使用することが可能となる。

 生成失敗することはあまりないが、個数に負の値を指定してしまうと、GL_INVALID_VALUEという値はエラーコールバックで返される。

 

2.glBindBuffer(GLenum target, GLuint bufffer);

 glGenBuffersでID(names)が生成されただけでは、ただID(names)が確保されただけで、中身や何のバッファーオブジェクトかが分からないので、用途を指定する必要がある。そのためにはglBindBufferを使用する。

 glBindBufferはバッファーオブジェクトを指定したバッファーバインディングポイントに割り当てる。targetにOpenGLが用意した定数の中から用途を指定する。bufferにはバッファーオブジェクトのID(names)へのポインタを指定する。glBindBufferは指定した用途にID(names)を割り当てる。もしID(names)が存在しなければ、新たにIDが作られ格納される。そして同じ用途を同時に二つ指定することができず、指定した用途がすでに他のバッファーオブジェクトに割り当てられている状態であれば、その割り当てが解除され、新たに指定したバッファーオブジェクトが適用される。

 バッファーオブジェクトのID(names)とそのバッファーオブジェクトのコンテンツは現在使用しているGL Rendering コンテンツのローカルに配置される。

 glBindBufferのtargetに指定できる用途は全部14個ある。

  • GL_ARRAY_BUFFER
  • GL_ATOMIC_COUNT_BUFFER
  • GL_COPY_READ_BUFFER
  • GL_COPY_WRITE_BUFFER
  • GL_DISPATCH_INDIRECT_BUFFER
  • GL_DRAW_INDIRECT_BUFFER
  • GL_ELEMENT_ARRAY_BUFFER
  • GL_PIXEL_PACK_BUFFER
  • GL_PIXEL_UNPACK_BUFFER
  • GL_QUERY_BUFFER
  • GL_SHADER_STORAGE_BUFFER
  • GL_TEXTURE_BUFFER
  • GL_TRANSFORM_FEEDBACK_BUFFER
  • GL_UNIFORM_BUFFER

 具体的にどれはどんな目的なのかについて、今回は割愛させてもらう。

3.glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);

 glBufferDataは指定している目的用のバッファーオブジェクトのデータストアを作成する。もしこの関数を呼び出した時点で既にデータストアが存在しているのであれば、それを削除する。データストアは指定したサイズと使用方法によりつくられている。もしdataはNULLでなければ、そのdataで初期化される。初期化時にはmap pointerにNULLが設定されており、mapped accessはGL_READ_WRITEと設定される。

 usageはデータストアはどのようにアクセスされるのかを指定する。usageを指定することで、バッファーオブジェクトのパフォーマンスを著しく上げることができる。usageは二つのパートに分けられる。一つはアクセスの頻度で、もう一つはアクセスの目的である。

  • 頻度

  STREAM  データストアコンテンツは一回しか変更しない、使用回数少ない

  STATIC     データストアコンテンツは一回しか変更しない、使用回数多い

  DYNAMIC  データストアコンテンツは何度も変更する、使用回数も多い

  • 目的

  DRAW   データストアコンテンツはアプリにより変更され、描画や画像指定として使われる

  READ    データストアコンテンツはGL側の読み込みデータにより変更され、アプリに要求される時にデータを転送する

  COPY    データストアコンテンツはGL側の読み込みデータにより変更され、描画や画像指定として使われる

 

4.glBindBuffer(GLenum target, 0);

 バッファーオブジェクトのIDは符号なしのint型で、ID(names)に0を指定することが可能だが、デフォルトではどの用途のバッファーオブジェクトにも割り当てることができない。したがって、一般的に前の割り当てを解除する目的で0を指定する。0を指定することで、もう一つの効果として、もしデバイスは0を指定する以前のバッファーオブジェクトをサポートしているのであれば、そのバッファーオブジェクトのクライアントメモリを保存することができる。

 

以上の流れでバッファーオブジェクトは作成される。

 

方法②:

 今までは方法①のやり方でVBOを作成していた。しかし、これらの関数は現代的なGPUの特性に合っておらず、GPUの性能を発揮しにくくなってきたので、OpenGL4.5では、新しい方法が実装された。

 1.glCreateBuffers(GLsizei n, GLuint *buffers);

 2.glNamedBufferStorage(GLuint buffer, GLsizeiptr size, const void *data, GLbitdield flags);

 やっていることは方法①と変わらないが、用途の指定が必要なくなったみたい。バッファーオブジェクトを発行して、設定やデータを送り込むだけになった。

 

四、VBOのデータを変更してみよう

 VBOはクライアント側のメモリスペースにバッファーをマッピングすれば、データの修正が可能となる。

 glBindBuffer(GLenum target, GLuint bufffer);

 glMapBuffer(GLenum target, GLenum access);

 データを修正

 glUnMapBuffer();