OpenGL "Advanced Data"
[ADVANCED DATA]
1. Buffer
- OpenGL에서의 buffer는 특정 메모리를 관리하는 것 그 이상 그 이하도 아니다
- 특정 buffer target에 바인딩하여 의미를 부여해준다
: GL_ARRAY_BUFFER에 바인딩하면 이 buffer는 vertex array buffer가 된다 (동일한 buffer를 GL_ELEMENT_ARRAY_BUFFER에 바인딩 할 수도 있다)
- OpenGL은 내부적으로 target에 대해 buffer를 저장하고 이 buffer들을 따로 처리한다
- 지금까지는 메모리를 할당해주고 그 메모리에 데이터를 삽입해주는 glBufferData 함수를 사용하여 buffer 객체에 의해 관리되는 메모리를 채워왔다
: 만약 이 함수의 data parameter에 NULL 값을 집어넣는다면 이 함수는 메모리 할당만 해주고 데이터를 채워넣지 않는다 (이것은 먼저 특정 메모리 크기를 reserve해놓고 나중에 이 buffer를 채우려 할 경우에 유용하다)
glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // Range: [24, 24 + sizeof(data)]
- 하나의 함수를 호출하여 전체 buffer를 채우는 것 대신 glBufferSubData 함수를 사용하여 buffer의 특정 부분을 채울 수 있다
glBufferSubData(buffer target, offset, data size, actual data)
: 해당 buffer를 어디에서부터 채울지를 지정하는 offset을 설정할 수 있다 (buffer 메모리의 특정 부분에만 삽입/수정 가능)
- 이 buffer는 충분한 메모리가 할당되어있어야 하므로 glBufferSubData 함수를 호출하기 전에 glBufferData 함수를 꼭 호출해야한다
float data[] = {
0.5f, 1.0f, -0.35f
[...]
};
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// get pointer
void *ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
// now copy data into memory
memcpy(ptr, data, sizeof(data));
// make sure to tell OpenGL we're done with the pointer
glUnmapBuffer(GL_ARRAY_BUFFER);
- pointer에게 buffer의 메모리를 요청하고 데이터를 buffer에 직접 복사하는 방법으로도 buffer에 데이터를 집어넣을 수 있다
- glMapBuffer 함수를 사용하면 OpenGL은 현재 바인딩 된 buffer의 메모리를 가리키고 있는 pointer를 return한다
- glUnmapBuffer 함수를 통해 pointer 작업이 끝났다고 알려줌으로써 OpenGL은 수행이 완료되었다는 것을 알 수 있다
: unmapping하여 이 pointer는 무효화되고 이 함수는 OpenGL이 buffer에 데이터를 성공적으로 매핑할 수 있었다면 GL_TRUE를 return 한다
- glMapBuffer 함수는 먼저 임시메모리에 저장하지 않고 직접적으로 데이터를 buffer에 매핑하는 것에 유용하다
2. Batching vertex attributes
- 모든 vector data들을 끼워넣는 것이 아닌 attribute 유형마다 큰 덩어리로 묶을 수 있다
: 123123123123 의 형태로 끼워넣는 것이 아니라 111122223333 의 형태로 묶을 수 있다
float positions[] = { ... };
float normals[] = { ... };
float tex[] = { ... };
// 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);
- 파일로부터 vertex data를 불러올 때 일반적으로 위치의 배열, 법선의 배열, texture coordinate의 배열을 얻는다
: 이 배열들을 끼워넣어진 형태로 하나의 큰 배열로 결합하는 것은 큰 비용이 든다
: glBufferSubData 함수를 통해 묶는 방법을 취한다
- 이 방법을 사용하면 먼저 attribute array를 처리하지 않고도 전체적으로 attribute array들을 하나의 buffer에 직접 전송할 수 있다
: 이 array들을 결합하여 하나의 큰 array로 결합하여 glBufferData 함수를 사용해 이 buffer를 채울 수 있으나 glBufferSubData 함수를 사용하는 것이 이러한 작업에 완벽하게 적합하다
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)));
- 이러한 변화를 반영하기 위해 vertex attribute pointer를 수정해준다
- Stride parameter는 vertex attribute의 크기와 동일하다
: 다음 vertex attribute vector가 바로 이 vector의 3(or 2) 요소 다음에 존재하기 때문이다
3. Copying Buffers
void glCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset,
GLintptr writeoffset, GLsizeiptr size);
- buffer가 데이터로 채워지기만 하면 이 데이터들을 다른 buffer와 공유할 수 있고, 이 buffer의 내용을 다른 buffer에 복사할 수도 있다
- glCopyBufferSubData 함수는 한 buffer에서 다른 buffer로 데이터를 비교적 수월하게 복사할 수 있도록 해준다
: readtarget과 writetarget은 각각 우리가 붙여넣기할, 복사할 buffer target을 지정한다
- 동시에 동일한 buffer target에 2개의 buffer를 바인딩할 수는 없다
: 이러한 이유로 OpenGL은 GL_COPY_READ_BUFFER와 GL_COPY_WRITE_BUFFER, 총 2개의 추가적인 buffer target을 제공한다
: 이 새로운 buffer target에 buffer들을 바인딩하고 readtarget, wirtetarget parameter에 넘겨준다
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));
- 그렇게 하면 glCopyBufferSubData 함수는 주어진 size의 data를 readoffset으로부터 읽고 writetarget buffer에 writeoffset을 시작지점으로 작성하게 된다
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));
- writetarget buffer만 바인딩하여 수행할 수도 있다