苦しみながら三角形を描いています…。とりあえず、今日描いた三角形です。
OpenGL をやっているということなのですが、 VBO(Vertex Buffer Object) と VAO(Vertex Array Object) がよくわかってないです。今日はそれについて独り言を書きます。テキストとしては、 Anton’s OpenGL 4 Tutorialsを使っています。
ベースとなるコードはこれ。
#include <GL/glew.h> // include GLEW and new version of GL on Windows
#include <GLFW/glfw3.h> // GLFW helper library
#include <stdio.h>
#include <iostream>
int main(int argc, const char \* argv\[\]) {
// start GL context and O/S window using the GLFW helper library
if (!glfwInit()) {
fprintf(stderr, "ERROR: could not start GLFW3\\n");
return 1;
}
glfwWindowHint(GLFW\_CONTEXT\_VERSION\_MAJOR, 3);
glfwWindowHint(GLFW\_CONTEXT\_VERSION\_MINOR, 2);
glfwWindowHint(GLFW\_OPENGL\_FORWARD\_COMPAT, GL\_TRUE);
glfwWindowHint(GLFW\_OPENGL\_PROFILE, GLFW\_OPENGL\_CORE\_PROFILE);
GLFWwindow \*window = glfwCreateWindow(640, 480, "Hello Triangle", NULL, NULL);
if (!window) {
fprintf(stderr, "ERROR: could not open window with GLFW3\\n");
glfwTerminate();
return 1;
}
glfwMakeContextCurrent(window);
// start GLEW extension handler
glewExperimental = GL\_TRUE;
glewInit();
// get version info
const GLubyte \* renderer = glGetString(GL\_RENDERER);
const GLubyte \* version = glGetString(GL\_VERSION);
printf("Renderer: %s\\n", renderer);
printf("OpenGL version supported %s\\n", version);
// tell GL to only draw onto a pixel in fthe shape is closer to the viewer
glEnable(GL\_DEPTH\_TEST); // enable depth-testing
glDepthFunc(GL\_LESS); // depth-testing interprets a smaller value as "closer"
GLfloat points\[\] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
GLuint vbo = 0;
glGenBuffers(1, &vbo);
glBindBuffer(GL\_ARRAY\_BUFFER, vbo);
glBufferData(GL\_ARRAY\_BUFFER, sizeof(points), points, GL\_STATIC\_DRAW);
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL\_ARRAY\_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL\_FLOAT, GL\_FALSE, 0, NULL);
const char\* vertex\_shader =
"#version 410\\n"
"in vec3 vp;"
"void main() {"
" gl\_Position = vec4(vp, 1.0);"
"}";
const char\* fragment\_shader =
"#version 410\\n"
"out vec4 frag\_colour;"
"void main() {"
" frag\_colour = vec4(0.5, 0.0, 0.5, 1.0);"
"}";
GLuint vs = glCreateShader(GL\_VERTEX\_SHADER);
glShaderSource(vs, 1, &vertex\_shader, NULL);
glCompileShader(vs);
GLuint fs = glCreateShader(GL\_FRAGMENT\_SHADER);
glShaderSource(fs, 1, &fragment\_shader, NULL);
glCompileShader(fs);
GLuint shader\_programme = glCreateProgram();
glAttachShader(shader\_programme, fs);
glAttachShader(shader\_programme, vs);
glLinkProgram(shader\_programme);
while (!glfwWindowShouldClose(window)) {
// wipe the drawing surface clear
glClear(GL\_COLOR\_BUFFER\_BIT | GL\_DEPTH\_BUFFER\_BIT);
glUseProgram(shader\_programme);
glBindVertexArray(vao);
// draw points 0-3 from the currently bound VAO with current in-use shader
glDrawArrays(GL\_TRIANGLES, 0, 3);
// update other events like input handling
glfwPollEvents();
// put the stuff we've been drawing onto the display
glfwSwapBuffers(window);
}
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
問題のポイント
GLuint vbo = 0;
glGenBuffers(1, &vbo);
glBindBuffer(GL\_ARRAY\_BUFFER, vbo);
glBufferData(GL\_ARRAY\_BUFFER, sizeof(points), points, GL\_STATIC\_DRAW);
GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL\_ARRAY\_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL\_FLOAT, GL\_FALSE, 0, NULL);
共通
- とりあえず、バッファは何か値を入れておく場所として考えておけばいい。
VBO(Vertex Buffer Object)
- 頂点バッファが扱う情報が 3 つの場合は、VBO も 3 つ必要になる。
- vertex shader の attribute に情報を渡す役割を担っている。
調べると長文ばっかり出てくるので、とりあえず、ひとつひとつの API を見ていくことにする。
GLuint vbo = 0;
vbo を格納する変数を作っている感じかな。
glGenBuffers(1, &vbo);
これは、
void glGenBuffers(GLsizei n, GLuint * buffers);
by glGenBuffers - OpenGL 4 Reference Pages
ということみたい。n に作成したい vbo の数を指定して、buffers に配列の先頭アドレスを指定すれば良いのかな。n に 1 を指定したのなら、vbo は要素(buffer 名)が 1 つの配列になるということかな。
glBindBuffer(GL_ARRAY_BUFFER, vbo);
これは、
void glBindBuffer(GLenum target, GLuint buffer);
ということみたい。 target は GLARRAYBUFFER の他に、GLTEXTUREBUFFER や GLATOMICCOUNTER_BUFFER などがある…。buffer を形式を指定して読み込む感じかな。
by glBindBuffer - OpenGL 4 Reference Pages
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
これは、
void glBufferData(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage);
ということみたい。 target は glBufferData をどのような形式で確保するかということ? size はデータサイズ、 data は読み込ませたいデータ、 usage はそのデータの用途。用途は、 GLSTREAMDRAW , GLSTREAMREAD , GLSTREAMCOPY , GLSTATICDRAW , GLSTATICREAD , GLSTATICCOPY , GLDYNAMICDRAW , GLDYNAMICREAD , or GLDYNAMICCOPY がある。
by glBufferData - OpenGL 4 Reference Pages
まだ、曖昧だけど、今のところとりあえず、 GLARRAYBUFFER という形式で確保された領域に、GLSTATICDRAW 目的で利用する points を格納した。その領域へのハンドルは変数 vbo であると理解しておこう!
とりあえず、この仮の理解があれば、先に進める><
VAO(Vertex Array Object)
GLuint vao = 0;
とりあえず、vbo と同じように変数を作成。
glGenVertexArrays(1, &vao);
これも、VBO と同様に、1 つ作るってことかな。
by glGenVertexArrays - OpenGL 4 Reference Pages
glBindVertexArray(vao);
void glBindVertexArray(GLuint array);
0 を指定したら、既存のやつを破棄するらしい。binding 成功したら、以前バインドしていたものは破棄される。
by glBindVertexArray - OpenGL 4 Reference Pages
glEnableVertexAttribArray(0);
void glEnableVertexAttribArray(GLuint index);
バインドした vao は今回は要素がひとつの配列だから、その 0 番目を有効にするって意味かな。
by glEnableVertexAttribArray - OpenGL 4 Reference Pages
glBindBuffer(GL_ARRAY_BUFFER, vbo);
むむ…。VBO で調べたのと同じのが出てきた。はぁ…。GLARRAYBUFFER に関連づけるところの考え方がなんか間違えてるっぽいな。。。。とりあえず、これはこういうものとして覚えておこう…。泣きたい。
glVertexAttribPointer(0, 3, GLFLOAT, GLFALSE, 0, NULL);
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer);
0 番目の vertex buffer は GL_FLOAT の vec3 で、normalized されてなくて、0 番目からレンダリングすると決めとく?
by glVertexAttribPointer - OpenGL 4 Reference Pages
もうここは強引に、glBindVertexArray あたりで、GLARRAYBUFFER は vao の管理下にあって、vbo をそこに追加して、どういう風に vertex shader がその情報を受け取るかを決めとく と理解しておこう。もうボロボロ。
とりあえず、そうすることで、vao は vbo のことも知ってて、vertex shader にどんな情報を渡せばいいか知ってるってことになります!!(強引)
…
定義を見ましたが、ちゃんと理解していません…。そもそも、OpenGL の全体像をつかめていない気がします。
GLARRAYBUFFER がさすものはそれぞれの箇所で違っているかもしれないですね。VAO の生成が始まったら、GLARRAYBUFFER は VAO の管理下にあるような印象が…。
問題山積み。
ついでに描画部分の一部を見ておく
glUseProgram(shader_programme);
コンパイル済みのプログラムを描画のために使うよってことだろ。
by glUseProgram - OpenGL 4 Reference Pages
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
きっと、glBindVertexArray(name)
で呼び出して、呼び出したやつを描画するんだろ。
参考
へるぷみ
へとへと。