Advanced OpenGL(6) - Advanced Data

흑빡·2026년 7월 6일

그래픽스

목록 보기
41/50

glBufferSubData

glBufferData라는 메서드가 있음

unsigned int cubeVBO;
glGenBuffers(1, &cubeVBO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);

이런식으로 vbo의 사이즈를 지정하고, data를 넘겨서 gpu메모리에 박을때 사용하는거임

만약 gpu메모리에 박힌 vbo를 사용하던중에 임의의 vbo데이터 변경이 생겨야한다면??

뭐 다시 glBufferData를 호출할 수도 있겠음ㅇㅇ
하지만 기본적으로 glBufferData는 메모리 초기화, 재할당을 하게됨

따라서 최적화를 위해 glBufferSubData라는걸 사용해주면 좋음

glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // Range: [24, 24 + sizeof(data)]

파라미터는 순서대로

target, offset, size, data임
target버퍼에 offset만큼 건너뛴 메모리 공간에 변경할 값들의 size와 값 변경할 data를 넣어주면 됨

간단스~

대신 glBufferSubData는 이미 할당된 메모리 공간을 사용해야하므로,
glBufferData로 먼저 메모리를 할당해두고 사용해야함

꼼수로

glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), nullptr, GL_STATIC_DRAW);

이렇게 data를 비워뒀다가
glBufferSubData로 나중에 값이 완전해진후에 채워도 됨

glMapBuffer

gpu 버퍼를 cpu의 포인터로 연결해서 사용할 수 있도록 하는거임

위의 glBufferSubData는 gpu내에서 직접 버퍼에 수정을 하는거였다면
glMapBuffer는 버퍼를 cpu로 불러와서 cpu에서 수정을 하거나 읽기만 하도록 할 수 있는거임

float data[] = {
  0.5f, 1.0f, -0.35f
  [...]
};

glBindBuffer(GL_ARRAY_BUFFER, buffer);

// mapBuffer로 포인터 얻기
void *ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);

// 복사
memcpy(ptr, data, sizeof(data));

// 포인터 해제
glUnmapBuffer(GL_ARRAY_BUFFER);

정점속성 일괄처리(batching)

위의 glBufferSubData를 이용해 여러개로 나뉘어진 정점 속성을 하나로 묶어서 더 간편하고 알아보기 쉽게 사용할 수 있음

지금까지 우리는

float cubeVertices[] = {
    // positions          // texture Coords
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
     0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
     0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
	//...
};

이런식으로 하나의 data를 이용해

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));

직접 offset을 계산해서 넣어주는 방식으로 사용했음

하지만 glBufferSubData를 사용하면 이제 다르게 사용가능함

float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };

uint32_t VAO, VBO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals) + sizeof(tex), nullptr, GL_STATIC_DRAW)

// fill buffer
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(positions), &positions);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions), sizeof(normals), &normals);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(positions) + sizeof(normals), sizeof(tex), &tex);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);  
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(sizeof(positions)));  
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(sizeof(positions) + sizeof(normals)));

확실히 코드가 더 직관적이게 바뀜
3개의 정점마다 vertex attributes매핑
이지~~

버퍼 복사 glCopyBufferSubData

자 위의 방식들은
버퍼의 값 변경,
gpu버퍼를 cpu에서 사용하도록 포인터 오픈
이었음

그럼 버퍼를 버퍼로 복사하려면 어떻게 해야할까?

걍 개쉬움

void glCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size);

를 사용하면 됨

readtarget의 버퍼를 writetarget으로 복사를 하는데
readtarget버퍼의 readoffset을 시작으로
writetarget버퍼의 writeoffset부터 size만큼 버퍼를 채움

예를들어
GL_ARRAY_BUFFER -> GL_ELEMENT_ARRAY_BUFFER
이렇게 복사하는거임

근데 문제가 있음
GL_ARRAY_BUFFER에서 GL_ARRAY_BUFFER로 복사를 하려고 하면??

readtarget과 writetarget에 같은 버퍼를 넣을순 없음

이걸 해결하기위해 존재하는 버퍼가
GL_COPY_READ_BUFFER & GL_COPY_WRITE_BUFFER

그래서 대충 사용법을 보면

glBindBuffer(GL_COPY_READ_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, 8 * sizeof(float));

//_______________________________________________

float vertexData[] = { ... };
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBindBuffer(GL_COPY_WRITE_BUFFER, vbo2);
glCopyBufferSubData(GL_ARRAY_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, 8 * sizeof(float));

이렇게 되는거임

profile
그래픽스 하는 퍼그

0개의 댓글