Quick Flow
GLSL uniform block 선언 → 링크 → block index 조회
→ 프로그램의 block을 binding point에 연결
→ 같은 point에 UBO 바인딩 → std140 배치로 데이터 업로드UBO는 여러 uniform을 버퍼로 묶습니다. 블록 인덱스는 프로그램 내부 값, binding point는 컨텍스트 연결 위치, buffer는 저장소 객체이므로 숫자를 서로 대신 넣지 않습니다.
std140 최소 예제
GL 3.3 Core와 GLSL 330 core의 블록 선언입니다.
layout(std140) uniform Camera {
mat4 viewProjection;
vec4 eyePosition;
};CPU는 열 우선 float 16개와 float 4개, 총 80바이트를 준비할 수 있습니다. viewProjection은 실제로 사용해야 활성 블록으로 남습니다. 다음은 ubo에 충분한 저장소가 할당되어 있다는 전제의 연결입니다.
GLuint block = glGetUniformBlockIndex(program, "Camera");
if (block != GL_INVALID_INDEX) {
glUniformBlockBinding(program, block, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo);
}80바이트 생성·업로드
선언만 있는 블록을 실제 자료와 연결하려면 저장소를 만들어야 합니다. 다음은 단위 viewProjection과 카메라 점 (0,0,3,1)을 넣는 GL 3.3 코드입니다. 위 Camera 블록을 사용하는 program의 링크가 성공한 뒤 실행합니다.
const GLfloat cameraData[20] = {
1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1,
0,0,3,1
};
GLuint ubo = 0;
glGenBuffers(1, &ubo);
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
glBufferData(GL_UNIFORM_BUFFER, sizeof(cameraData), cameraData, GL_DYNAMIC_DRAW);
GLuint block = glGetUniformBlockIndex(program, "Camera");
if (block != GL_INVALID_INDEX) {
glUniformBlockBinding(program, block, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo);
}
// 마지막 사용 뒤 glDeleteBuffers(1, &ubo);위 연결 구간과 같은 작업을 저장소 생성부터 확장한 예이며 두 코드의 ubo를 따로 만들 필요는 없습니다. 이 std140 블록에서 행렬은 offset 0, 각 열 stride는 16바이트, eyePosition은 offset 64입니다. 매 프레임 카메라 값만 바뀌면 새 블록을 만들기보다 BufferSubData 등으로 해당 범위를 갱신합니다.
블록 크기를 조회할 때는 glGetActiveUniformBlockiv(program, block, GL_UNIFORM_BLOCK_DATA_SIZE, &size)를 사용합니다. 멤버의 uniform index를 얻은 뒤 glGetActiveUniformsiv의 GL_UNIFORM_OFFSET·ARRAY_STRIDE·MATRIX_STRIDE로 배치를 조회할 수 있습니다. 이 index는 glUniform에 넣는 location이 아닙니다.
배치 인벤토리
| 항목 | 규칙·기본 조건 | 잘못 맞췄을 때 |
|---|---|---|
| 스칼라 float/int | 보통 4바이트 성분 기준 | C++ bool 크기를 그대로 사용하지 않음 |
| vec2 | 8바이트 기준 정렬 | 앞 멤버 뒤 패딩 확인 |
| vec3/vec4 | 16바이트 기준 정렬 | vec3 크기만 12로 단순 합산하지 않음 |
| 배열·행렬 | std140의 stride·정렬 규칙 | float 배열이 밀집 4바이트 stride라고 가정 금지 |
| block binding | 초기 0, 한도 이내 위치 | 여러 블록이 의도 없이 같은 버퍼를 읽음 |
| range offset | UBO offset alignment의 배수 | 구조체 크기와 별개의 바인딩 정렬 |
중첩 구조체·배열·행렬은 필요한 offset·array stride·matrix stride·block size를 프로그램 조회 정보와 대조합니다. GL_UNIFORM_BLOCK_DATA_SIZE가 요구하는 전체 크기 이상을 준비합니다. bool·vec3·비정방 행렬은 CPU 타입이 같은 이름이라고 메모리 배치까지 같지 않습니다.
범위와 갱신
glBindBufferRange로 큰 UBO의 일부를 연결할 수 있습니다. offset은 구현의 GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, size는 블록이 필요로 하는 범위를 만족해야 합니다. 여러 draw가 같은 범위를 읽는 동안 데이터를 덮어쓰는 문제는 버퍼 스트리밍의 책임입니다.
블록의 uniform은 일반 location으로 갱신하지 않습니다. 버퍼에 쓰고 바인딩을 맞춥니다. 재링크하면 프로그램의 블록 인덱스·바인딩 관련 설정을 다시 확인합니다.
버전과 레이아웃
UBO는 3.1부터이며 3.3에서는 위처럼 API로 블록 binding을 지정합니다. 소스의 layout(binding = ...) 지정은 4.2 또는 대응 확장 조건을 확인합니다. SSBO에서 쓰는 std430을 표준 3.3 uniform block에 적용하지 않습니다. shared·packed 등 다른 레이아웃은 std140의 고정 배치와 같은 것으로 처리하지 않습니다.
참고 링크
4 sources