OpenGL 1.0 (1992)
一番最初は,Begin()からEnd()の間に,1頂点ずつ送るコマンドを使っていた.glBegin(GL_TRIANGLE_STRIP);
glVertex2f( 0.0f, 0.5f);
glVertex2f( 0.5f, 0.5f);
glVertex2f(-0.5f, -0.5f);
glEnd();
OpenGL 1.1 (1997)
glVertexPointer()により,頂点をまとめて送れるようになる.// 直接描画
GLfloat vertices[] = {
0.0f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(
2, // 要素数
GL_FLOAT, // 型
0, // stride (0なので詰めてある想定になる)
vertices
);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
更に,インデックス指定による頂点の共有が可能に.この場合は,glDrawElements()で描画を行う.
// インデックス指定による描画
GLfloat vertices[] = {
-0.5f, 0.5f,
0.5f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
};
GLushort indices[] = {
0, 1, 2,
0, 2, 3
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, indices);
四角形を書くのに三角形2つを使う場合,6個の頂点が必要だったのが,これで4つで済むように.
OpenGL 1.5 (2003)
glEnableClientState()という名前からも分かるように,今までは頂点情報をCPU側に置いていたが,GPU側に頂点バッファオブジェクト(Vertex Buffer Object, VBO)を用意し,データを格納できる機能が追加される.// 直接描画
// バッファの生成
GLuint buffer;
glGenBuffers(1, &buffer);
// バッファの種類を設定
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// バッファにデータを設定
GLfloat vertices[] = {
0.0f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
};
glBufferData(
GL_ARRAY_BUFFER,
sizeof vertices,
vertices,
GL_STATIC_DRAW
);
// バッファのデータと関連づけ
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);
// 描画
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
// バッファの削除
glDeleteBuffers(1, &buffer);
// インデックス指定による描画
// 頂点用バッファの生成
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
// インデックス用バッファの生成
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
GLfloat vertices[] = {
-0.5f, 0.5f,
0.5f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
};
glBufferData(
GL_ARRAY_BUFFER,
sizeof vertices,
vertices,
GL_STATIC_DRAW
);
GLushort indices[] = {
0, 1, 2,
0, 2, 3
};
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof indices,
indices,
GL_STATIC_DRAW
);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);
glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, 0);
glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &indexBuffer);
OpenGL 2.0 (2004)
プログラマブルシェーダの登場により,頂点シェーダとバッファを関連づける機能が追加される.とりあえず頂点位置を指定するだけの簡単な頂点シェーダ.
#version 110
attribute vec4 position;
void main(void)
{
gl_Position = position;
}
頂点シェーダに関連付けて三角形を書く.
// バッファの生成
GLuint buffer;
glGenBuffers(1, &buffer);
// バッファの種類を設定
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// バッファにデータを設定
GLfloat vertices[] = {
0.0f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
};
glBufferData(
GL_ARRAY_BUFFER,
sizeof vertices,
vertices,
GL_STATIC_DRAW
);
// アトリビュート変数のインデックスを取得
GLuint position = glGetAttribLocation(program, "position");
// アトリビュート変数を有効化
glEnableVertexAttribArray(position);
// アトリビュート変数の設定
glVertexAttribPointer(position, 2, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
OpenGL 3.0 (2008)
バッファをバインドして,glEnableVertexAttribArray()で有効化して,glVertexAttribPointer()で位置を指定して,というのを切り替える度に実行しないといけないのは面倒だよね,ということで,それらをまとめるための頂点配列オブジェクト(Vertex Array Object, VAO)が導入される.とりあえず,頂点位置以外に頂点色も指定できる単純な頂点シェーダ.
#version 130
in vec4 position;
in vec4 color;
out vec4 oColor;
void main(void)
{
gl_Position = position;
oColor = color;
}
良い感じにVAOを活用した短いコードを思いつかなかったので,適当に赤,緑,青を切り替えられるプログラム.
// 現在のプログラムの取得
GLuint program;
glGetIntegerv(GL_CURRENT_PROGRAM, reinterpret_cast<GLint*>(&program));
// 頂点配列オブジェクトの生成
GLuint VAOs[3];
glGenVertexArrays(3, VAOs);
// 最初の頂点配列オブジェクトのバインド
glBindVertexArray(VAOs[0]);
GLfloat const vertices[] = {
0.0f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f,
};
// 頂点バッファの生成,バインド,データ設定
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(
GL_ARRAY_BUFFER,
sizeof vertices,
vertices,
GL_STATIC_DRAW
);
// 頂点シェーダのin変数positionの設定
GLint position = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(
position,
2,
GL_FLOAT,
GL_FALSE,
sizeof(GLfloat) * 2,
0
);
// カラーバッファの生成,バインド,データ設定
GLuint colorBuffers[3];
glGenBuffers(3, colorBuffers);
GLfloat const r[] = {
1.f, 0.f, 0.f, 1.f,
1.f, 0.f, 0.f, 1.f,
1.f, 0.f, 0.f, 1.f,
};
glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof r, r, GL_STATIC_DRAW);
// 頂点シェーダのin変数colorの設定
GLint color = glGetAttribLocation(program, "color");
glEnableVertexAttribArray(color);
glVertexAttribPointer(
color,
4,
GL_FLOAT,
GL_FALSE,
sizeof(GLfloat) * 4,
0
);
// 2つ目の頂点配列オブジェクトのバインド
glBindVertexArray(VAOs[1]);
{
// 頂点バッファのバインドやin変数の設定など
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(position);
glVertexAttribPointer(
position,
2,
GL_FLOAT,
GL_FALSE,
sizeof(GLfloat) * 2,
0
);
GLfloat const g[] = {
0.f, 1.f, 0.f,
0.f, 1.f, 0.f,
0.f, 1.f, 0.f,
};
glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof g, g, GL_STATIC_DRAW);
glEnableVertexAttribArray(color);
glVertexAttribPointer(
color,
3,
GL_FLOAT,
GL_FALSE,
sizeof(GLfloat) * 3,
0
);
}
// 3つ目の頂点配列オブジェクトのバインド
glBindVertexArray(VAOs[2]);
{
// 頂点バッファのバインドやin変数の設定など
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(position);
glVertexAttribPointer(
position,
2,
GL_FLOAT,
GL_FALSE,
sizeof(GLfloat) * 2,
0
);
GLfloat const b[] = {
0.f, 0.f, 1.f,
0.f, 0.f, 1.f,
0.f, 0.f, 1.f,
};
glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof b, b, GL_STATIC_DRAW);
glEnableVertexAttribArray(color);
glVertexAttribPointer(
color,
3,
GL_FLOAT,
GL_FALSE,
sizeof(GLfloat) * 3,
0
);
}
glBindVertexArray(0);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
// 描画前にバインドする頂点配列オブジェクトを切り替えると,
// 色が変わる.
glBindVertexArray(VAOs[0]);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glFlush();
glDeleteBuffers(3, colorBuffers);
glDeleteBuffers(1, &vertexBuffer);
glDeleteVertexArrays(3, VAOs);
最近のOpenGLの入門書だと最初からシェーダを用意して,VAO用意して,VBO用意して,ようやく描画,という感じのコードが載ってたりして,初心者からすると非常に難しそうに思える気がする.でも,こうやって歴史を辿ってみると,何となく必要性が分かったような気がしないでもない.
3.0以降の変化は気が向いたら調べよう.VAOの例を考えてたら疲れた.
0 件のコメント:
コメントを投稿