[openGL] FrameBuffer

나우히즈·2024년 10월 11일

Graphics

목록 보기
15/17

FrameBuffer

프레임버퍼(Frame Buffer)는 렌더링 결과를 저장하는 메모리 공간이다. OpenGL에서는 렌더링된 픽셀 데이터를 보관하는 기본 장소로서 역할을 하며, 화면에 출력되기 전에 처리된 그래픽 데이터가 일시적으로 저장된다.

프레임버퍼의 종류

  1. 기본 프레임버퍼

기본 프레임버퍼는 시스템에서 제공하는 디폴트 프레임버퍼로, 보통 화면의 해상도와 연결되어 있으며, OpenGL에서 화면에 그릴 때 사용된다. 렌더링이 완료되면 해당 데이터는 디스플레이 장치에 출력된다.

  1. 프레임버퍼 객체 (FBO)

프레임버퍼 객체는 기본 프레임버퍼와 달리 사용자가 제어하는 버퍼이다. 이를 통해 화면에 직접 출력하지 않고도 오프스크린 렌더링을 할 수 있다. FBO는 렌더링된 결과를 텍스처 또는 렌더버퍼로 출력할 수 있게 해주며, 주로 후처리 효과, 쉐도우 맵 생성, 환경 맵핑 등 다양한 작업에 사용된다.

FBO의 주요 특징:
• FBO를 사용하면 프레임버퍼의 컬러, 깊이, 스텐실 첨부(attachment)를 직접 설정할 수 있다.
• 텍스처 또는 렌더버퍼에 렌더링할 수 있어, 후처리 효과와 같은 커스텀 렌더링 파이프라인을 만들 때 유용하다.

프레임버퍼의 구성 요소

프레임버퍼는 여러 개의 첨부(attachment)를 가질 수 있으며, 각 첨부는 컬러, 깊이, 스텐실 등의 렌더링 데이터를 보관하는 역할을 한다.

1.	컬러 첨부(Color Attachment): 최종 이미지의 색상 데이터를 저장하는 버퍼.
2.	깊이 첨부(Depth Attachment): 깊이 테스트에서 사용할 깊이 값을 저장하는 버퍼.
3.	스텐실 첨부(Stencil Attachment): 스텐실 테스트에서 사용할 스텐실 값을 저장하는 버퍼.

이 첨부들은 텍스처나 렌더버퍼로 지정될 수 있다. 보통 컬러 첨부는 텍스처로 사용하고, 깊이나 스텐실 첨부는 렌더버퍼로 사용하게 된다.

FBO 생성과 설정

  1. 프레임버퍼 생성 및 삭제
glGenFramebuffers(GLsizei n, GLuint* ids);
glDeleteFramebuffers(GLsizei n, const GLuint* ids);
  • 프레임버퍼 객체를 생성/삭제
  • n은 생성/삭제할 프레임버퍼의 개수이고, ids는 생성/삭제를 위한 프레임버퍼 ID들이 저장되는 배열
  1. 프레임버퍼 바인딩
glBindFramebuffer(GLenum target, GLuint framebuffer);
  • 프레임버퍼를 바인딩하여 활성화합니다.
  • target은 바인딩할 프레임버퍼의 대상
    • GL_FRAMEBUFFER
    • GL_DRAW_FRAMEBUFFER
    • GL_READ_FRAMEBUFFER
  • framebuffer는 바인딩할 프레임버퍼의 ID입니다. 기본 프레임버퍼를 사용하려면 0을 바인딩합니다.
  1. 프레임버퍼 첨부
glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);

프레임버퍼는 렌더버퍼나 텍스처 같은 첨부 대상을 가지며, 이를 첨부하는 함수들이 있습니다.

  • glFramebufferTexture2D
    • 텍스처를 프레임버퍼에 첨부합니다.
    • target은 프레임버퍼 대상 (주로 GL_FRAMEBUFFER)입니다.
    • attachment는 첨부할 버퍼의 종류.
      • GL_COLOR_ATTACHMENT0은 컬러 버퍼
      • GL_DEPTH_ATTACHMENT는 깊이 버퍼
      • GL_STENCIL_ATTACHMENT는 스텐실 버퍼입니다.
    • textarget은 텍스처의 대상 (주로 GL_TEXTURE_2D)이며, texture는 첨부할 텍스처의 ID입니다.
    • level은 텍스처의 밉맵 레벨입니다 (보통 0).
  • glFramebufferRenderbuffer
    • 렌더버퍼를 프레임버퍼에 첨부합니다.
    • renderbuffertarget은 주로 GL_RENDERBUFFER로 설정됩니다.
    • renderbuffer는 첨부할 렌더버퍼의 ID입니다.
  1. 프레임버퍼 상태 확인
glCheckFramebufferStatus(GLenum target);
  • glCheckFramebufferStatus
    • 프레임버퍼의 상태를 확인하는 함수입니다.
    • target은 GL_FRAMEBUFFER로 설정되며, 프레임버퍼가 제대로 구성되었는지 확인합니다.
    • 이 함수는 상태 코드(GL_FRAMEBUFFER_COMPLETE 등)를 반환하며, 성공적으로 설정된 경우 GL_FRAMEBUFFER_COMPLETE를 반환합니다.
  1. 프레임버퍼 클리어링
glClear(GLbitfield mask)
glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
glClearDepth(GLdouble depth);
glClearStencil(GLint s);
  • glClear
    • 현재 바인딩된 프레임버퍼를 클리어하는 함수입니다.
    • mask는 클리어할 버퍼들을 지정합니다.
      • GL_COLOR_BUFFER_BIT는 컬러 버퍼
      • GL_DEPTH_BUFFER_BIT는 깊이 버퍼
      • GL_STENCIL_BUFFER_BIT는 스텐실 버퍼를 클리어합니다.
  • glClearColor
    • 컬러 버퍼를 클리어할 때 사용할 색상을 지정합니다.
  • glClearDepth
    • 깊이 버퍼를 클리어할 때 사용할 깊이 값을 지정합니다.
  • glClearStencil
    • 스텐실 버퍼를 클리어할 때 사용할 스텐실 값을 지정합니다.
  1. 프레임버퍼 해제
glBindFramebuffer(GLenum target, 0);
  • 프레임버퍼 바인딩을 해제하고, 기본 프레임버퍼로 돌아갑니다.
  • target은 바인딩할 프레임버퍼의 대상(GL_FRAMEBUFFER)입니다.

이 함수들을 조합해서 프레임버퍼 생성 → 텍스처/렌더버퍼 첨부 → 바인딩 → 렌더링 → 상태 확인의 과정을 수행할 수 있습니다.

  1. FBO 생성
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);  // FBO 바인딩
  1. 컬러 텍스처 첨부

텍스처에 렌더링된 결과를 저장하고 싶다면, 텍스처를 FBO에 첨부한다.

GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// 텍스처를 FBO에 첨부
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
  1. 깊이 첨부

깊이 값을 저장하기 위한 깊이 버퍼를 첨부하는 방법.

GLuint depthBuffer;
glGenRenderbuffers(1, &depthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);

// FBO에 깊이 버퍼 첨부
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
  1. FBO 상태 확인

FBO가 제대로 설정되었는지 확인하는 단계.

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
    std::cerr << "Error: Framebuffer is not complete!" << std::endl;
}
  1. FBO를 사용하여 렌더링

FBO에 바인딩된 텍스처나 버퍼에 렌더링하는 단계. 렌더링 후, 다시 기본 프레임버퍼로 바인딩할 수 있다.

glBindFramebuffer(GL_FRAMEBUFFER, fbo);  // FBO에 렌더링
// ... 렌더링 작업 ...
glBindFramebuffer(GL_FRAMEBUFFER, 0);    // 기본 프레임버퍼로 복귀

이후 FBO에 바인딩된 텍스처에 렌더링된 결과가 저장되었으므로, 그 텍스처를 가져와서 기본 프레임버퍼에서 바인딩해 렌더링하여 후처리를 진행하게 된다.

프레임버퍼에 바인딩한 텍스처에 렌더링하면 그 텍스처의 내용이 변경됩니다. 즉, 렌더링된 결과가 그 텍스처에 저장되죠. 그렇다면, 원본 텍스처를 다시 사용하고 싶다면 원본 텍스처 데이터를 다시 텍스처에 로드해야 합니다.

1.	프레임버퍼에 텍스처 바인딩: 처음에 텍스처를 프레임버퍼에 attach해서 렌더링을 시작합니다. 이때, 텍스처는 렌더링 결과로 덮어쓰여지기 때문에 원본 텍스처 데이터는 사라집니다.
2.	프레임버퍼 렌더링 후: 프레임버퍼에 렌더링이 끝난 후, 텍스처의 내용은 변해있습니다. 만약 원본 텍스처로 다시 돌아가서 사용하고 싶다면, 원본 데이터를 다시 텍스처로 복사해줘야 합니다.
3.	원본 텍스처 데이터 복원: 이때 glTexImage2D() 또는 glTexSubImage2D()를 사용해서 원본 텍스처 데이터를 다시 텍스처로 복사해줍니다.

FBO의 활용

프레임버퍼 객체(FBO)는 오프스크린 렌더링에서 매우 유용하다. 즉, 렌더링을 화면에 표시하지 않고 다른 텍스처나 버퍼에 렌더링한 다음, 이를 나중에 사용할 수 있다.

  1. 후처리 효과(Post-Processing):
  • 화면 전체에 대한 렌더링이 완료된 후 텍스처로 저장하고, 이 텍스처에 추가적으로 블러, 그림자, 톤 매핑과 같은 후처리 효과를 적용할 수 있다.
  1. 쉐도우 맵 생성
  • 그림자 효과를 위한 깊이 맵(depth map)을 생성할 때 FBO를 사용하여 렌더링된 깊이 정보를 저장할 수 있다.
  1. 환경 맵핑:
  • 환경 맵(예: 큐브 맵)을 만들 때, 각 면(face)을 텍스처로 렌더링하여 캡처할 수 있다.

0개의 댓글