Posts OpenGL 공부 - 04 - VAO, VBO, Attributes
Post
Cancel

OpenGL 공부 - 04 - VAO, VBO, Attributes

목표


  • Vertex Attributes, Layout, VBO, VAO에 대한 이해


Attributes, VAO, VBO


  • 버텍스 버퍼에는 버텍스 좌표, 텍스쳐 좌표, 노멀 벡터 등 여러 데이터가 float 값으로 들어갈 수 있다.
  • 하지만 그 자체로는 그저 메모리에 올라가는 값일 뿐이기 때문에 각각의 데이터가 어떤 역할을 하고, 길이는 얼마나 갖고 있고, 시작 위치는 어디인지 OpenGL에 알려줘야 한다.


  • VAO(Vertex Array Object)

    • 하나 이상의 VBO를 담을 수 있는 객체
    • 개별 오브젝트의 모든 데이터를 담고 있다.
    • 고유 ID를 가진다.
1
2
3
4
5
6
7
8
// 1. VAO ID 준비
GLuint vao;

// 2. VAO 객체 생성 및 ID에 바인딩
glGenVertexArrays(1, &vao);

// 3. 객체 타입 바인딩
glBindVertexArray(vao);


  • VBO(Vertex Buffer Object)

    • 하나의 정점 속성을 갖고 있는 GPU 상의 메모리 버퍼
    • 예를 들어 위치 정보, 색상 정보, 노멀 정보 등
    • 고유 ID를 가진다.
1
2
3
4
5
6
7
8
9
10
11
12
// 1. 버퍼 객체 ID 준비
GLuint vbo;

// 2. 버퍼 객체 생성 및 ID에 바인딩
glGenBuffers(1, &vbo);

// 3. 버퍼 객체에 타입 바인딩
glBindBuffer(GL_ARRAY_BUFFER, vbo);

// 4. 버퍼에 실질적 데이터 담기
// (미리 준비된 정점, 색상 등등의 배열 데이터(Attribute)를 vbo에 연결)
glBufferData(GL_ARRAY_BUFFER, size, attribute, GL_STATIC_DRAW);


  • Vertex Attribute(정점 속성)

    • 버텍스 버퍼에 들어가는 입력 데이터
    • 각각의 속성은 배열로 이루어진다.
    • glVertexAttribPointer() 메소드를 통해 정점 속성을 어떻게 해석해야 하는지 지정해줄 수 있다.
    • 각각의 정점 속성은 VBO(Vertex Buffer Object)에 작성하며, 이를 하나의 VAO(Vertex Array Object)에 저장한다.
1
2
3
4
5
// 1. 정점 속성의 레이아웃 지정
glVertexAttribPointer(index, size, type, normalized, stride, pointer);

// 2. 정점 속성 배열을 인덱스를 통해 등록
glEnableVertexAttribArray(index);



공부 내용


  • glVertexAttribPointer()

    • 정점 속성 배열을 정의 : 레이아웃 지정
index 해당 정점 속성의 순서(좌표, 색상, 노멀이 있다면 0, 1, 2 순서)
size 정점 속성의 구성 크기(벡터를 의미 : 1, 2, 3, 4 중 하나)
type 배열 내 데이터들의 타입
normalized 배열 내 데이터들이 정규화되어야 하는지 여부 전달
stride 배열 내 각각 데이터의 byte 오프셋 크기
(sizeof(float) * 2는 float 2개씩 구성되어 있음을 의미)
pointer 해당 정점 속성의 시작 byte 위치
(좌표가 12, 색상이 16, 노멀이 12를 갖는다면
좌표는 0, 색상은 12, 노멀은 28의 byte 위치를 가짐)
1
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);


  • glEnableVertexAttribArray()

    • 해당 인덱스에 위치한 정점 속성 배열을 활성화
index 활성화시킬 정점 속성 배열이 위치한 인덱스
1
glEnableVertexAttribArray(0);


Source Code


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
using namespace std;

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    // glewInit은 rendering context를 만들고 난 이후에 해야 함
    if (glewInit() != GLEW_OK)
    {
        cout << "GLEW INIT ERROR" << endl;
    }

    // 간단히 GLEW 버전 확인
    cout << glGetString(GL_VERSION) << endl;

    // Vertex Attribute : 위치 데이터
    float positions[6] = {
        -0.5f, -0.5f,
         0.0f,  0.5f,
         0.5f, -0.5f,
    };

    // VBO(Vertex Buffer Object) ID 생성
    GLuint buffer;

    // VBO 객체 생성
    glGenBuffers(1, &buffer);

    // VBO 타입 바인딩
    glBindBuffer(GL_ARRAY_BUFFER, buffer);

    // VBO에 위치 데이터 연결
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW);

    // 정점 속성 정의
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);

    // 정점 속성 활성화
    glEnableVertexAttribArray(0);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        glDrawArrays(GL_TRIANGLES, 0, 3);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}


References


This post is licensed under CC BY 4.0 by the author.