Quick Flow
이미지 저장소 준비 → FBO 생성·바인딩 → 첨부 연결
→ draw/read buffer 선택 → completeness 확인
→ viewport·출력 상태 설정 → draw → 다음 패스의 입력으로 사용FBO는 픽셀 저장소 자체가 아니라 어떤 이미지에 출력할지 연결하는 객체입니다. 이미지 크기·형식·샘플 조건을 바꾸면 다시 완전성을 확인합니다. 기본 경로는 GL 3.3 Core입니다.
최소 색 출력 FBO
// texture는 폭·높이가 양수인 GL_RGBA8 2D 저장소를 가진 객체입니다.
GLuint fbo = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texture, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
std::fprintf(stderr, "FBO status: 0x%x\n", status);
}
// COMPLETE인 경우에만 사용합니다. 마지막 사용 뒤 fbo와 texture를 각각 삭제합니다.색만 쓰는 이 FBO에 깊이 테스트를 켠다고 깊이 저장소가 생기지 않습니다. 깊이를 사용하려면 해당 첨부 이미지도 준비합니다. glBindFramebuffer(GL_FRAMEBUFFER, 0)은 창의 기본 프레임버퍼로 돌아가며, 크기나 viewport가 자동으로 창 크기로 복원되는 것은 아닙니다.
첨부와 버퍼 선택
| 항목 | 설정 범위·초기 조건 | 의존 관계와 실패 |
|---|---|---|
| COLOR_ATTACHMENTi | 색 출력 가능 형식, 처음에는 이미지 없음 | i는 구현 첨부 한도 이내 |
| DEPTH/STENCIL | 해당 성분을 제공하는 저장소 | packed depth-stencil은 조합을 맞춤 |
| texture 첨부 | 레벨·면·레이어의 이미지 | 셰이더 입력으로 재사용 가능 |
| renderbuffer 첨부 | 렌더링용 저장소 | 일반 sampler로 직접 읽지 못함 |
| draw buffers | 프래그먼트 출력 위치→첨부 매핑 | GL_NONE이면 해당 색 출력 폐기 |
| read buffer | 픽셀 읽기·blit의 색 소스 | draw와 다른 선택일 수 있음 |
새 사용자 FBO의 기본 draw/read 색 선택은 COLOR_ATTACHMENT0이지만, 코드에서는 필요한 매핑을 명시합니다. 깊이 전용 FBO는 색 draw/read를 GL_NONE으로 지정하는 호환성 있는 구성을 사용합니다. MRT의 glDrawBuffers 배열 순서는 fragment output location에 대응하며 첨부 번호와 자동으로 같은 순서라고 가정하지 않습니다.
두 색 출력의 MRT 연결
같은 크기의 색 렌더링 가능 텍스처 두 개 colorTexture·normalTexture를 준비한 GL 3.3 예입니다. 이미 바인딩한 사용자 FBO에 연결하며, 구성 변경 뒤 COMPLETE를 다시 확인합니다.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, colorTexture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D, normalTexture, 0);
const GLenum outputs[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, outputs);GLSL 330 core의 프래그먼트 셰이더는 layout(location=0) out vec4 outColor;, layout(location=1) out vec4 outNormal;을 선언하고 모든 필요한 실행 경로에서 각각의 값을 씁니다. outputs[1]을 GL_NONE으로 바꾸면 location 1의 출력은 버려집니다. 한 번의 MRT draw에서 색 attachment별 역할을 정하는 과정이며, 텍스처 유닛 번호와는 관계없습니다.
Renderbuffer 연결
셰이더에서 직접 샘플링하지 않을 깊이·스텐실 저장소라면 renderbuffer를 선택할 수 있습니다. texture 첨부와 달리 샘플러 입력으로 바로 사용하지 않습니다. fbo가 바인딩되어 있고 width·height가 양수인 초기화 구간입니다.
GLuint depthStencil = 0;
glGenRenderbuffers(1, &depthStencil);
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, depthStencil);
// 첨부 후 COMPLETE를 확인하고, 마지막 사용 뒤 별도로 삭제합니다.깊이 이미지를 그림자 sampler로 읽을 계획이면 texture 첨부가 적절합니다. MSAA 저장소는 별도 다중 샘플 할당 함수를 사용합니다.
완전성 확인
첨부 없는 상태, 유효하지 않은 이미지, 지원되지 않는 형식 조합, 다중 샘플 수 불일치, 레이어 첨부 조합 등을 확인합니다. 모든 첨부 크기가 다르면 무조건 오류라고 단정하지 않되, 의도한 렌더 영역과 각 첨부 크기를 일관되게 맞추는 것이 관리하기 쉽습니다. COMPLETE는 셰이더·viewport·블렌드가 맞다는 뜻은 아닙니다.
이미지를 삭제하거나 저장소를 재할당하면 FBO의 사용 조건도 달라집니다. FBO 삭제는 텍스처·renderbuffer의 삭제와 별개입니다. 읽으면서 동시에 같은 이미지에 쓰는 문제는 완전성 검사만으로 해결되지 않으며 다중 패스에서 구분합니다.
버전별 API
FBO는 3.0 코어에 포함되었습니다. 이전 EXT 계열 예제는 접미사뿐 아니라 규칙 차이를 확인해야 합니다. 4.5 DSA는 glNamedFramebufferTexture·glCheckNamedFramebufferStatus처럼 객체를 직접 지정합니다. 첨부 이미지·read/draw 대상의 의미는 유지됩니다.
참고 링크
6 sources