Computer Graphics/OpenGL

OpenGL 정리 - 20. 프레임 버퍼 (Frame Buffer)

surkim 2024. 10. 25. 17:12

1. 프레임 버퍼

1.1 프레임 버퍼란

프레임 버퍼는 OpenGL에서 렌더링된 이미지 데이터를 저장하는 버퍼로, 색상, 깊이, 스텐실 버퍼로 구성된 집합체이다. 일반적으로 OpenGL 컨텍스트를 생성할 때 기본 프레임 버퍼가 자동으로 생성되며, 화면에 그림을 그리기 위해 사용된다. 그러나 개발자가 직접 프레임 버퍼 객체(FBO)를 생성하여 렌더링 결과를 텍스처로 활용하거나, 포스트 프로세싱을 적용할 수도 있다.

1.2 프레임 버퍼 목적

프레임 버퍼는 다음과 같은 경우에 유용하게 사용된다:

  • 렌더링된 장면을 텍스처로 활용: 텍스처 매핑, 쉐도우 맵핑, 반사 효과 등.
  • 포스트 프로세싱: 렌더링 후 추가적인 효과(예: 블러, 감마 보정, 색상 반전 등)를 적용.

2. 프레임 버퍼 사용 과정

2.1 프레임 버퍼 생성 및 설정

프레임 버퍼를 사용하는 기본적인 단계는 다음과 같다:

  1. 프레임 버퍼 객체 생성
    glGenFramebuffersglBindFramebuffer 함수를 사용하여 새로운 프레임 버퍼 객체를 생성하고 바인딩한다.
  2. 렌더버퍼 생성
    색상, 깊이, 스텐실 버퍼 등 다양한 렌더버퍼를 생성하고 설정할 수 있다. 렌더링이 될 색상 버퍼는 텍스처를 사용하고, 깊이 및 스텐실 버퍼는 렌더버퍼를 사용하는 것이 일반적이다.
  3. 렌더버퍼를 프레임 버퍼에 연결
    생성된 렌더버퍼를 프레임 버퍼의 attachment로 연결한다. 예를 들어, 깊이 및 스텐실 버퍼는 glFramebufferRenderbuffer 함수를 사용해 연결한다.
  4. 프레임 버퍼 상태 확인
    glCheckFramebufferStatus 함수를 사용하여 프레임 버퍼가 올바르게 구성되었는지 확인한다. 오류가 발생하면 적절한 처리를 해야 한다.

2.2 프레임 버퍼 초기화

bool Framebuffer::InitWithColorAttachment(const TexturePtr colorAttachment) {
    m_colorAttachment = colorAttachment;
    glGenFramebuffers(1, &m_framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);

    // 텍스처를 색상 첨부로 설정
    glFramebufferTexture2D(GL_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
        colorAttachment->Get(), 0);

    // 깊이 및 스텐실 렌더버퍼 생성 및 설정
    glGenRenderbuffers(1, &m_depthStencilBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
    glRenderbufferStorage(
        GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
        colorAttachment->GetWidth(), colorAttachment->GetHeight());
    glBindRenderbuffer(GL_RENDERBUFFER, 0);

    // 렌더버퍼를 깊이 및 스텐실 첨부로 연결
    glFramebufferRenderbuffer(
        GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
        GL_RENDERBUFFER, m_depthStencilBuffer);

    // 프레임 버퍼 상태 확인
    auto result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (result != GL_FRAMEBUFFER_COMPLETE) {
        SPDLOG_ERROR("failed to create framebuffer: {}", result);
        return false;
    }

    // 기본 프레임 버퍼로 바인딩 복원
    BindToDefault();
    return true;
}

위 코드는 프레임 버퍼를 초기화하고, 색상 첨부를 텍스처로 설정하며, 깊이 및 스텐실 첨부를 렌더버퍼로 설정한다. 마지막으로 glCheckFramebufferStatus를 통해 프레임 버퍼의 상태를 확인한다(중요)


3. 포스트 프로세싱(Post-processing)

포스트 프로세싱은 프레임 버퍼에 렌더링된 장면에 추가적인 효과를 적용하는 과정이다. 예를 들어, 색상 반전, 감마 보정, 블러 등의 시각 효과를 구현할 수 있다.

3.1 포스트 프로세싱을 적용하는 예제

포스트 프로세싱을 적용하기 위해서는 먼저 렌더링 결과를 프레임 버퍼에 저장하고, 이후 이 텍스처를 이용해 추가적인 효과를 적용한다.

m_framebuffer->Bind(); 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 
glEnable(GL_DEPTH_TEST);

// 이후 렌더링 과정
  1. 프레임 버퍼 바인딩 및 초기화
    먼저 프레임 버퍼를 바인딩하고, 렌더링할 색상, 깊이, 스텐실 버퍼를 초기화한다. 이렇게 하면 이후의 렌더링이 화면 대신 프레임 버퍼에 저장된다.위 코드에서 m_framebuffer->Bind()를 호출하여 프레임 버퍼를 활성화하고, 이후의 렌더링 결과가 해당 프레임 버퍼에 저장되도록 한다. 그런 다음, glClear로 버퍼를 초기화하고, 깊이 테스트를 활성화하여 렌더링이 제대로 이루어지도록 한다.
  2. 카메라와 광원의 설정
    카메라의 위치와 방향, 광원의 속성을 설정하여 장면을 렌더링한다. 예를 들어, 광원의 위치와 방향을 설정하고, 카메라의 투영 및 뷰 행렬을 계산한다.
  3. 렌더링 및 텍스처 바인딩
    장면을 렌더링한 후, 기본 프레임 버퍼로 다시 바인딩하여 저장된 텍스처를 화면에 그린다.
  4. 포스트 프로세싱 셰이더 사용 및 감마 보정 적용
    포스트 프로세싱 셰이더를 사용하여 감마 값을 조정하고, 프레임 버퍼에 저장된 텍스처를 화면에 보정된 상태로 렌더링한다.
// 렌더링 과정 후
Framebuffer::BindToDefault(); 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 

m_postProgram->Use(); 
m_postProgram->SetUniform("transform", glm::scale(glm::mat4(1.0f), glm::vec3(2.0f, 2.0f, 1.0f))); 
m_framebuffer->GetColorAttachment()->Bind(); 

m_postProgram->SetUniform("tex", 0); 
m_postProgram->SetUniform("gamma", m_gamma); 
m_plane->Draw(m_postProgram.get());

위 코드는 기본 프레임 버퍼로 바인드한 후 화면을 초기화하고, m_postProgram 셰이더 프로그램을 사용하여 감마 보정을 적용한다. m_framebuffer->GetColorAttachment()->Bind()를 통해 텍스처를 바인딩하고, 감마 값을 셰이더에 전달한 다음, 텍스처가 적용된 장면을 렌더링한다.