Home [learn-opengl] Advanced OpenGL: Advanced Data
Post
Cancel

[learn-opengl] Advanced OpenGL: Advanced Data

Advanced Data

  • 버퍼들을 좀 더 흥미로운 방법과 texture들을 통해 shader에 많은 양의 data를 전달하는 흥미로운 방법이 존재한다.

  • 이런 버퍼함수들과, 많은 양의 데이터를 저장하기 위해 텍스처 객체를 사용하는 방법을 다룰 것이다.

  • OpenGL에서의 buffer는 특정 메모리를 관리하는것이다.

    • 특정 buffer target에 바인딩하여 의미를 부여해준다.
    • GL_ARRAY_BUFFER 에 바인딩 하면 이 버퍼는 vertex array buffer
    • 이 동일한 버퍼를 다른 것에 바인딩 가능
    • GL_ELEMENT_ARRAY_BUFFER에 바인딩 가능.
    • OpenGL은 내부적으로 target에 대해 buffer를 저장하고 이 buffer들을 따로 처리한다.

glBufferData

  • 지금까지 메모리를 할당해주고, 이 메모리에 데이터를 삽입해주는 glBufferData 함수를 사용하여 buffer 객체에 의해 관리되는 메모리를 채워 왔음.

    • 여기에 NULL 값을 넣는다면, 이 함수는 메모리 할당만 해주고, 데이터를 채워 넣지 않는다.
    • 이는 특정 메모리 크기를 예약하고, 나중에 이 buffer를 채우려고 할 경우에 유용하다.

glBufferSubData

  • 대신 glBufferSubData 함수를 사용하여, buffer의 특정 부분을 채우는 것 또한 가능하다.
    • 이 함수는 buffer target, offset, data size, 실제 data를 파라미터로 받는다.
    • offset 지정이 이 함수의 특징
    • 이는 buffer메모리의 특정 부분에만 삽입/ 수정할 수 있도록 해준다.
    • 이 buffer는 충분한 메모리가 할당되어 있어야하므로, glBufferSubData 함수를 호출하기 전에 glBufferData함수를 꼭 호출해야한다.
1
glBufferSubData(GL_ARRAY_BUFFER, 24, sizeof(data), &data); // Range: [24, 24 + sizeof(data)]

glMapBuffer

  • pointer에게 buffer의 메모리를 요청하고 데이터를 buffer에 직접 복사하는 방법

  • 이 함수를 사용하면 OpenGL은 현재 바인딩된 buffer의 메모리를 가리키고 있는 포인터를 리턴한다.

1
2
3
4
5
6
7
8
9
10
11
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);
  • glUnmapBuffer 함수를 통해 포인터 작업이 끝났다고 OpenGL에게 알려줄 수 있음.
    • 이 포인터는 무효화됨.
    • 이 함수는 OpenGL이 buffer에 데이터를 성공적으로 매핑할 수 있는 경우 GL_TRUE를 리턴한다.(unless the data store’s contents became corrupted during the time the data store was mapped)
  • glMapBuffer 함수를 사용하는 것은 먼저 임시 메모리에 저장하지 않고 직접 매핑하기에 유용하다.

Batching vertex attributes

  • glVertexAttributePointer 함수를 사용하여 vertex array buffer 내용의 attribute layout을 지정할 수 있었음.

    • vertex array buffer내부에 attribute들을 끼워넣었음.(위치, 법선, 텍스처 좌표들을 메모리에 서로 옆에 배치)
  • 이와 같은 방법말고 다른 방법으로 지정할 수 있다.

  • attribute 유형마다 큰 덩어리로 묶는 방법

    • 파일로부터 vertex 데이터를 불러올 때, 일반적으로 위치, 법선, 텍스처 좌표 배열을 얻는다.
      • 이를 하나의 큰 배열로 결합하는것은 큰 비용
      • 각 유형으로 묶는것이 더 쉬움
  • glBufferSubData로 이를 쉽게 구현가능하다.

1
2
3
4
5
6
7
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);
  • 이를 통해 직접적으로 하나의 buffer에 배열을 옮길 수 있다.

  • 또한 이렇게 할 경우, vertex attribute pointer를 수정해야 한다.

1
2
3
4
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)));
  • Stride 파라미터는 vertex attribute의 크기와 동일하다.(바로 옆에 같은 유형의 데이터가 있으므로)

  • 이런 방법을 사용하는 것은 OpenGL에 즉각적인 효과는 없다.

    • 단지 좀더 vertex attribue를 설정하는게 좀 더 체계적인 방법임.

Copying buffers

  • 하나의 버퍼에 데이터가 채워지면, 이 데이터들을 다른 버퍼와 공유, 복사 할 수 있다.

glCopyBufferSubData

  • 한 버퍼에서 다른 버퍼로 비교적 수월하게 복사함
  • 이 함수의 프로토타입은 다음과 같다.
1
2
void glCopyBufferSubData(GLenum readtarget, GLenum writetarget, GLintptr readoffset,
                         GLintptr writeoffset, GLsizeiptr size);
  • readtarget, writetarget: 복붙할 버퍼 타겟 지정

    • buffer target: VERTEX_ARRAY_BUFFER => VERTEX_ELEMENT_ARRAY_BUFFER 가능
    • 그러면 현재 해당 버퍼 대상에 바인딩된 버퍼들이 영향을 받는다.
  • 하지만 둘다 같은 buffer target일 경우.(같은 유형에 2개의 버퍼 바인딩 불가능)

    • 추가적인 buffer target을 사용한다.
    • GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER
    • 이 새로운 버퍼 타겟에 버퍼들을 바인딩하고 파라미터로 넘겨주면 된다.
  • 주어진 size만큼 readoffset에서부터 읽고 writeoffset을 시작지점으로 붙여넣는다.

1
2
3
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));
  • 또한 writetarget 버퍼만 바인딩하여 수행 가능
1
2
3
4
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));

출처

Advanced Data: 원문

Advanced Data: 번역본

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

[learn-opengl] Advanced OpenGL: Cubemaps

[learn-opengl] Advanced OpenGL: Advanced GLSL