本サイトでは、アフィリエイト広告およびGoogleアドセンスを利用しています。

OpenGL 4世代での描画手順 その2

前回はとりあえず三角形が出せるまで、だったので今回はもう少し進めてみたいと思います。DirectX11ではシェーダー定数については定数バッファ(ConstantBuffer)というものを使って、パラメータをCPUからGPU(シェーダー)に送ります。これのOpenGL版は Uniform Buffer Object (UBO)というものに該当します。

Uniform Buffer Object (UBO)

定数バッファとして使用し、シェーダーにデータを転送します。バッファそのものは glGenBuffers で作成するため、頂点バッファ(VBO)と同じようにして、作成することができます。作成過程で違うのは、GL_UNIFORM_BUFFER をターゲットとして設定することくらいでしょうか。初期データも glBufferData などで設定することができます。

使用するまでが若干ややこしいです。少なくとも自分はちょっと手間取りました。
いくつかの OpenGL API を用いて設定していかなくてはならないのですが、関連がなかなかわかりませんでした。そこで、各GL関数が何を行っているかの図を作成してみました。

fig1_uniform_buffer

この図を見てもらいつつ、説明を辿ってもらうとわかりやすいかと思います。定数バッファは先に説明したとおりVBO等と同等に作成します。青色の四角の部分がこれです。GLSLのシェーダー内では定数バッファを使用する際には uniform block で記述します。そしてこのブロック1つごとに Block Index というものが割り当てられます。これはシェーダーをコンパイルした後で取得することができ、GL関数は glGetUniformBlockIndex を使用します。
 ここで取得できたブロックインデックスは、Binding Point と呼ばれる場所に設定します。Binding Point とは、バッファとの関連づけを保持するテーブルになります。この図では、Binding Point の 0番目に Block Index 0 のものを設定しています。
 そして、描画の際には Uniform Buffer Object をこの Binding Point の何番目に対して設定するのかを指定します。これが glBindBufferBase 関数になります。バッファの中身を更新しないのであれば、描画の際にはこのglBindBufferBase関数でバッファをBinding Pointへ設定するだけになり、glBindBuffer( GL_UNIFORM_BUFFER, )というコードは不要です。このあたりが頂点バッファなどとは違う点になると思います。

また、定数バッファ(UBO)は複数のシェーダーで同じ物を設定することができます。このときの図を示すと以下のようになります。
fig2_uniform_buffer
この図では Binding Point 2 に設定されている UBO を、Shader 間で共有している状態となります。

定数バッファの使用例

とりあえず長い説明だったので、定数バッファに行列をセットして描画をやってみます。
作成したシェーダーはこんな感じです。

#version 140
in vec4 in_position;
in vec4 in_color;
out vec4 vsout_col;

uniform VertexBlock {
  mat4 pvw;
  vec4 col;
};
void main() {
  gl_Position = pvw * in_position;
  vsout_col = in_color * col;
}

そしてこれを使用するC++プログラム側はこんな感じとなっています。

/* UBOの生成およびBindingPointへの設定 */
glGenBuffers( 1, &ubo );
blockIndex = glGetUniformBlockIndex( shaderProgram, "VertexBlock" );
glUniformBlockBinding( shaderProgram, blockIndex, 1 );

/* 描画.  */
glUseProgram;
glBindBufferBase( GL_UNIFORM_BUFFER, 1, ubo );
glDrawArrays;

X,Y軸に 0.5 乗算した PVW行列をセットして描画してみた図がこちらです。
ちゃんと値を送れているようで、三角形が出てます。

ubo_result

今回のまとめ

Uniform Buffer Object について説明しました。割と理解に手間取ったのと図の作成で時間をかけてしまいました。3D空間を回っているような結果を作るつもりだったのですが…。Uniform Buffer はDirectXのほうが簡単な印象があります。このOpenGLのほうはテーブルに一度登録したりするところが理解を難しくしているような気がします。このほうが柔軟に色々とできる可能性があるのもわかりますが・・・。

OpenGLプログラミング
すらりんをフォローする
すらりん日記
タイトルとURLをコピーしました