苦しみながら三角形を描いています…。とりあえず、今日描いた三角形です。
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 はGL_ARRAY_BUFFERの他に、GL_TEXTURE_BUFFERやGL_ATOMIC_COUNTER_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 はそのデータの用途。用途は、 GL_STREAM_DRAW , GL_STREAM_READ , GL_STREAM_COPY , GL_STATIC_DRAW , GL_STATIC_READ , GL_STATIC_COPY , GL_DYNAMIC_DRAW , GL_DYNAMIC_READ , or GL_DYNAMIC_COPY がある。
by glBufferData – OpenGL 4 Reference Pages
まだ、曖昧だけど、今のところとりあえず、 GL_ARRAY_BUFFERという形式で確保された領域に、GL_STATIC_DRAW目的で利用する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で調べたのと同じのが出てきた。はぁ…。GL_ARRAY_BUFFERに関連づけるところの考え方がなんか間違えてるっぽいな。。。。とりあえず、これはこういうものとして覚えておこう…。泣きたい。
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 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あたりで、GL_ARRAY_BUFFERはvaoの管理下にあって、vboをそこに追加して、どういう風にvertex shaderがその情報を受け取るかを決めとく と理解しておこう。もうボロボロ。
とりあえず、そうすることで、vaoはvboのことも知ってて、vertex shaderにどんな情報を渡せばいいか知ってるってことになります!!(強引)
…
定義を見ましたが、ちゃんと理解していません…。そもそも、OpenGLの全体像をつかめていない気がします。
GL_ARRAY_BUFFERがさすものはそれぞれの箇所で違っているかもしれないですね。VAOの生成が始まったら、GL_ARRAY_BUFFERはVAOの管理下にあるような印象が…。
問題山積み。
ついでに描画部分の一部を見ておく
glUseProgram(shader_programme);
コンパイル済みのプログラムを描画のために使うよってことだろ。
by glUseProgram – OpenGL 4 Reference Pages
glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, 3);
きっと、glBindVertexArray(name)
で呼び出して、呼び出したやつを描画するんだろ。
参考
へるぷみ
へとへと。