일반적인 프로그램의 데이터는 메인 메모리(RAM)에 저장
RAM -> CPU -> GPU로 매 프레임 같은 데이터를 전달하는 건 비효율적
그래픽스 데이터는 RAM에서 VRAM으로 1번만 복사하여 저장
이후 VRAM -> GPU로 데이터를 매 프레임 전달
피라미드 회전 예제를 베이스로 VBO를 사용하도록 수정한 프로그램
glm::vec4 vertPos[] = { ... };
glm::vec4 vertColor[] = { ... };
GLuint vbo[1];
void prepareVBO(void) {
// 버퍼 생성하여 vbo 배열에 버퍼ID 저장
glGenBuffers(1, vbo);
// 생성한 버퍼를 GPU의 attribute 레지스터에서 사용할 배열로 바인딩
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
// 버퍼의 사이즈를 결정 (18개의 xyzw 벡터가 2개), 크기만큼 VRAM에 할당
// NULL을 넣어 아직 데이터 복사를 하지 않음
glBufferData(GL_ARRAY_BUFFER, 2 * 18 * 4 * sizeof(GLfloat), NULL, GL_STATIC_DRAW);
// offset을 0으로, vertPos 배열을 복사
glBufferSubData(GL_ARRAY_BUFFER, 0, 18 * 4 * sizeof(GLfloat), vertPos);
// 이후 위치에 vertColor 배열을 복사
glBufferSubData(GL_ARRAY_BUFFER, 18 * 4 * sizeof(GLfloat), 18 * 4 * sizeof(GLfloat), vertColor);
}
void drawFunc(void) {
...
// 절대주소가 아닌 offset을 넘겨줌
GLuint locPos = glGetAttribLocation(prog, "aPos");
glEnableVertexAttribArray(locPos);
glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(0));
GLuint locColor = glGetAttribLocation(prog, "aColor");
glEnableVertexAttribArray(locColor);
glVertexAttribPointer(locColor, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(18 * 4 * sizeof(GLfloat)));
...
}
이전 프로그램의 결과대로 정상적으로 회전하는 것을 확인

vertex = position + color
struct vertex {
glm::vec4 pos;
glm::vec4 color;
};
0번째 vertex의
pos의 offset은 0 byte,
color의 offset은 4 x 4 bytes
상대 거리 stride = 8 x 4 bytes 만큼 vertex 위치 계산 가능
vertex 데이터 뿐만 아니라 index 배열 정보도 VRAM에 복사 가능
(glDrawElements() 함수가 index 배열을 활용하여 vertex 데이터를 참고함)
버퍼 바인딩 시 target을 GL_ELEMENT_ARRAY_BUFFER로만 세팅하면 VBO와 세팅방법은 똑같음
VBO와 IBO를 한 번에 사용하는 예제 프로그램
glm::vec4 vertPos[] = { // 5 vertices
{ 0.0F, 0.5F, 0.0F, 1.0F }, // v0
{ 0.5F, -0.3F, 0.0F, 1.0F }, // v1
{ 0.0F, -0.3F, -0.5F, 1.0F }, // v2
{ -0.5F, -0.3F, 0.0F, 1.0F }, // v3
{ 0.0F, -0.3F, 0.5F, 1.0F }, // v4
};
glm::vec4 vertColor[] = { // 5 colors
{ 1.0F, 1.0F, 1.0F, 1.0F, }, // v0: white
{ 1.0F, 0.3F, 0.3F, 1.0F, }, // v1: red
{ 0.3F, 1.0F, 0.3F, 1.0F, }, // v2: green
{ 0.3F, 0.3F, 1.0F, 1.0F, }, // v3: blue
{ 1.0F, 1.0F, 0.3F, 1.0F, }, // v4: yellow
};
GLuint indices[] = { // 6 * 3 = 18 indices
0, 1, 2, // face 0: v0-v1-v2
0, 2, 3, // face 1: v0-v2-v3
0, 3, 4, // face 2: v0-v3-v4
0, 4, 1, // face 3: v0-v4-v1
1, 4, 3, // face 4: v1-v4-v3
1, 3, 2, // face 5: v1-v3-v2
};
GLuint vbo[1];
GLuint ibo[1];
void prepareVBO(void) {
// vertex 수가 변경되어 버퍼 사이즈도 맞춰줌
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, 2 * 5 * 4 * sizeof(GLfloat), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, 5 * 4 * sizeof(GLfloat), vertPos);
glBufferSubData(GL_ARRAY_BUFFER, 5 * 4 * sizeof(GLfloat), 5 * 4 * sizeof(GLfloat), vertColor);
// IBO 세팅
glGenBuffers(1, ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo[0]);
// 18개의 인덱스 데이터를 IBO에 복사
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 18 * sizeof(GLuint), indices, GL_STATIC_DRAW);
}
void drawFunc(void) {
...
GLuint locPos = glGetAttribLocation(prog, "aPos");
glEnableVertexAttribArray(locPos);
glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(0));
// 5개의 vertex를 사용하도록 offset 값 변경
GLuint locColor = glGetAttribLocation(prog, "aColor");
glEnableVertexAttribArray(locColor);
glVertexAttribPointer(locColor, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(5 * 4 * sizeof(GLfloat)));
...
// IBO와 결합되어 있는 상황
glDrawElements(GL_TRIANGLES, 18, GL_UNSIGNED_INT, (GLvoid*)(0));
...
}