苦しみながら三角形を描いてるけどVBOとVAOがわからないので調べてみる(ぐちゃぐちゃ)

苦しみながら三角形を描いてるけどVBOとVAOがわからないので調べてみる(ぐちゃぐちゃ)苦しみながら三角形を描いています…。とりあえず、今日描いた三角形です。

Hello Triangle

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)で呼び出して、呼び出したやつを描画するんだろ。

参考

へるぷみ

へとへと。

教材

Pocket
LINEで送る

You may also like...