- 유니폼 블록
- 목적
- glUniform 함수를 매번 호출하여 발생하는 성능 저하 예방
- 유니폼 업데이트를 단순하게 할 수 있도록
- 프로그램간의 유니폼을 쉽게 공유할 수 있음
- 유니폼들을 유니폼 블록으로 그룹화 하는 방법
- 버퍼 객체에 저장
- 블록 전체를 버퍼에 저장 가능
- 유니폼 버퍼 객체 (UBO : Uniform Buffer Object)
- 프로그램을 변경해도 버퍼 바인딩은 그대로 둘 수 있기에,
프로그램들은 유니폼 값을 공유할 수 있다. - 일반적으로 사용하는 쉐이더 전역구간에 선언한 유니폼은
'디폴트 유니폼 블록'에 있게 된다. - Example
- uniform TransformBlock
{
float scale;
vec3 translation;
float rotation[3];
mat4 projection_matrix;
} transform; - 유니폼 블록 만들기
- 표준 방법
- 데이터의 레이아웃에 의존
- 애플리케이션이 버퍼로 그냥 데이터를 복사하고, 멤버의 블록 내 위치가 그대로 일치한다고 가정
- Example
- layout(std140) uniform TransformBlock
{
float scale;
vec3 translation;
float rotation[3];
mat4 projection_matrix;
} transform; - 표준 또는 std140으로 선언되면, 각 블록의 멤버는 버퍼에 정의된 양만큼의 공간을 차지함.
- std140 레이아웃과 C++ 컴파일러의 패킹 룰(타입 별 차지하는 공간, 배치에 대한 룰) 사이에는 차이가 있다. 따라서 C배열의 데이터를 그대로 복사할 수 없음.
- 공유 레이아웃 방법
- 데이터가 어디에 위치할지 OpenGL이 결정하게 하는 방법
- 성능은 좋지만 불편하고 코드가 많이 필요함
- OpenGL이 성능 및 접근성에 최적화된 형태로 버퍼에 배치
- 사용하기 위해서는 유니폼 블록 멤버에 대한 버퍼 객체 상의 위치를 애플리케이션이 결정해야 함?
- 사용하기 위해서는 OpenGL이 블록 멤버에 할당한 오프셋을 알아내야 한다.
- glGetUniformIndices
void glGetUniformIndices(
GLuint program, GLsizei uniformCount, const GLchar **uniformNames, GLuint *uniformIndices )
;- uniformCount: 인덱스를 얻어올 유니폼의 개수
- uniformNames: 유니폼의 이름
- uniformIndices: 유니폼 인덱스 리턴값
- Example
- static const GLchar * uniformNames[4] = {
"TransformBlock.scale",
"TransformBlock.translation",
"TransformBlock.rotation",
"TransformBlock.projection_matrix"
}
GLuint uniformIndices[4];
glGetUniformIndices(program, 4, uniformNames, uniformIndices); - uniformIndices 배열 안에는 유니폼 블록의 네 멤버에 대한 인덱스가 들어감.
- glGetActiveUniformsiv
void glGetActiveUniformsiv(
GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params )
;- 버퍼 내 멤버의 오프셋, 배열 stride, 행렬 stride 등을 알아낼 수 있음
- Example
- GLint uniformOffsets[4];
GLint arrayStrides[4];
GLint matrixStrides[4];
glGetActiveUniformsiv(program, 4, uniformIndices, GL_UNIFORM_OFFSET, uniformOffsets);
glGetActiveUniformsiv(program, 4, uniformIndices, GL_UNIFORM_ARRAY_STRIDE, arrayStrides);
glGetActiveUniformsiv(program, 4, uniformIndices, GL_UNIFORM_MATRIX_STRIDE, matrixStrides); - pname: 얻는 정보
- 타입
- 사이즈
- 유니폼 이름의 길이
- 유니폼이 속한 블록 내 인덱스
- 블록 내 유니폼의 오프셋
- 배열에서 다음 요소까지의 바이트수
- 배열이 아니라면 0이다.
- 유니폼이 행렬일 때 (열우선 행렬: 열, 행우선 행렬: 행)의 각 첫번째 요소들 간의 바이트수.
- 행렬이 아니라면 0이다.
- 행우선 행렬이면 1, 열우선 행렬 또는 행렬이 아닌경우 0
- 값 설정
- scale
- 단일 부동소수점 (float)
- Example
- unsigned char * buffer = (unsigned char *)malloc(4096);
*((float *)(buffer + uniformOffsets[0])) = 3.0f; - TransformBlock.scale이 블록의 uniformOffsets[0]에 위치한다.
- translation
- vec3
- Example
- *((float *)(buffer + uniformOffsets[1]))[0] = 1.0f;
*((float *)(buffer + uniformOffsets[1]))[1] = 2.0f;
*((float *)(buffer + uniformOffsets[1]))[2] = 3.0f; - rotation
- 3요소 배열
- Example
- const GLfloat rotations[] = {30.0f, 40.0f, 50.0f};
- unsigned int offset = uniformOffsets[2];
- for (int i = 0; i < 3; i++)
- {
- *((float *)(buffer + offset)) = rotations[i];
- offset += arrayStrides[2];
- }
- projection_matrix
- Example
- const GLflost matrix[] =
- {
- // 4x4 array
- };
- for (int i = 0; i < 4; i++)
- {
- GLuint offset = uniformOffsets[3] + matrixStride[3] * i;
- for (int j = 0; j < 4; j++)
- {
- *((float *)(buffer + offset)) = matrix[i*4 + j];
- offset += sizeof(GLfloat);
- }
- }
- 데이터 버퍼를 프로그램 유니폼 블록에 바인딩
- 프로그램 내 각 유니폼 블록은 컴파일러가 할당한 인덱스를 가짐
- 유니폼 블록의 최대 개수에는 제한이 있음
- glGetIntegerv()에 GL_MAX_UNIFORM_BUFFERS로 확인
- glGetUniformBlockIndex
GLuint glGetUniformBlockIndex(
GLuint program, const GLchar *uniformBlockName )
;- uniformBlockName: 유니폼 블록의 이름
- 바인딩 순서
- [버퍼 - 유니폼 버퍼 바인딩(바인딩 포인트) - 프로그램(유니폼 블록)]
- 유니폼 블록을 바인딩 포인트에 할당
- 바인딩 포인트에 버퍼를 바인딩
- 유니폼 블록에 바인딩 포인트를 할당
- glUniformBlockBinding
void glUniformBlockBinding(
GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding )
;- program: 유니폼 블록이 위치하는 프로그램
- uniformBlockIndex: 유니폼 블록 인덱스
- uniformBlockBinding: 유니폼 블록 바인딩 포인트의 인덱스
- 유니폼 블록의 인덱스를 쉐이더에서 직접 지정
- Example
- layout(std140, binding =2) uniform TransformBlock
- {
- ...
- }
- 바인딩 포인트에 버퍼를 바인딩
- glBindBufferBase
void glBindBufferBase(
GLenum target, GLuint index, GLuint buffer )
;- target: GL_UNIFORM_BUFFER
- index: 바인딩 포인트에 대한 인덱스(유니폼 블록의 인덱스가 아니다.)
- buffer: attach 시키려는 버퍼 객체의 이름
- Example
- // 버퍼 A -- 바인딩 포인트 3 -- Bob
- // 버퍼 B -- 바인딩 포인트 0 -- Susan
- // 버퍼 C -- 바인딩 포인트 1 -- Harry
- GLuint harry_index = glGetUniformBlockIndex(program, "Harry");
- GLuint bob_index = glGetUniformBlockIndex(program, "Bob");
- GLuint susan_index = glGetUniformBlockIndex(program, "Susan");
- // 버퍼 바인딩 -- 유니폼 블록
- glUniformBlockBinding(program, harry_index, 1);
- glUniformBlockBinding(program, bob_index, 3);
- glUniformBlockBinding(program, susan_index, 0);
- // 버퍼 -- 바인딩 포인트
- glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer_b);
- glBindBufferBase(GL_UNIFORM_BUFFER, 1, buffer_c);
- glBindBufferBase(GL_UNIFORM_BUFFER, 3, buffer_a);
- 쉐이더 내부에서 binding으로 유니폼 블록에 대한 바인딩을 설정하면 glUniformBlockBinding 함수호출이 필요없다.
- Example
- layout (binding = 1) uniform Harry
- {
- };
- layout (binding = 3) uniform Bob
- {
- };
- layout (binding = 0) uniform Susan
- {
- };
- 쉐이더 내에 바인딩을 설정하는 방식은 OpenGL 함수 호출이 적고, 이름을 몰라도 바인딩 포인트에 유니폼 블록을 연결할 수 있음.
2018년 3월 27일 화요일
5.2.2 유니폼 블록
피드 구독하기:
댓글 (Atom)
댓글 없음:
댓글 쓰기