OpenGL 에서 FrameBuffer 사용

프레임 버퍼 에 대한 함 수 를 빠르게 이해 할 수 있 도록 다른 사람 이 쓴 좋 은 글 을 먼저 인용 합 니 다.
http://longzxr.i.sohu.com/blog/view/168909774.htm
《----------------------------------------------------------------------------------------------------------
 
Frame Buffer Object(FBO)확장,텍 스 처 이미지 에 데 이 터 를 렌 더 링 하 는 데 추천 합 니 다.데이터 복사 나 교환 버퍼 등 다른 동종 기술 에 비해 FBO 기술 을 사용 하면 더욱 효율 적 이 고 실현 하기 쉽다.이 글 에서 나 는 이 확장 을 어떻게 사용 하 는 지 빠르게 설명 하고 사용 과정 에서 우리 가 주의해 야 할 부분 을 소개 할 것 이다.이 기술 을 배 운 후에 텍 스 처(render to texture)에 렌 더 링 하 는 기능 을 프로그램 에 추가 하여 더욱 빠 른 운행 을 실현 할 수 있 습 니 다.OpenGL 의 다른 쌍 을 만 듭 니 다.예 를 들 어 텍 스 처 대상(texture object),픽 셀 버퍼 대상(pixel buffer objects),정점 버퍼 대상(vertex buffer object)등 이 있 습 니 다.FBO 쌍 을 사용 하기 전에 이 쌍 을 만 들 고 효과 적 인 쌍 상 표 지 를 가 져 야 합 니 다.GLuint fbo;glGenFramebuffersEXT(1, &fbo); FBO 에 대해 어떠한 조작 도 하려 면 먼저 그것 을 연결 해 야 합 니 다.이 절 차 는 우리 가 평소에 VBO 나 텍 스 처 를 사용 하 는 과정 과 비슷 하 다.대상 을 연결 한 후에 우 리 는 FBO 에 대해 각종 조작 을 할 수 있 습 니 다.다음 코드 는 어떻게 연결 하 는 지 보 여 줍 니 다.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); 첫 번 째 매개 변 수 는"대상(target)"입 니 다.FBO 를 어느 프레임 버퍼 와 연결 하 시 겠 습 니까?현재 제 매개 변 수 는 미리 정 의 된 선택 만 있 습 니 다(GLFRAMEBUFFER_EXT),하지만 앞으로 확 장 될 발전 은 다른 선택 을 할 수 있 습 니 다.FBO 를 다른 목표 와 연결 시 킬 수 있 습 니 다.정형 변수 fbo 는 FBO 대상 표 지 를 저장 하 는 데 사 용 됩 니 다.이 표 지 는 앞에서 생 성 되 었 습 니 다.FBO 와 관련 된 모든 조작 을 실현 하려 면,우 리 는 반드시 FBO 가 연결 되 어야 합 니 다.그렇지 않 으 면 호출 이 잘못 될 것 입 니 다.
깊이 캐 시(Depth Buffer)를 추가 하 는 것 자체 가 큰 도움 이 되 지 않 습 니 다.더 효과적으로 이용 하려 면 렌 더 링 이 가능 한 버퍼 와 연결 해 야 합 니 다.이러한 버퍼 는 무늬 일 수도 있 고 아래 에 소개 할 렌 더 링 버퍼(renderbuffers)일 수도 있 습 니 다.렌 더 링 버퍼 는 화면 에서 렌 더 링 을 지원 하 는 버퍼 입 니 다.보통 프레임 버퍼 의 일부분 으로 텍 스 처 형식 이 없습니다.흔히 볼 수 있 는 모드 버퍼 와 깊이 버퍼 는 바로 이러한 쌍 이다.여기 서 우 리 는 FBO 에 렌 더 링 버퍼 를 지정 해 야 합 니 다.이렇게 해서 우리 가 렌 더 링 을 할 때,우 리 는 이 렌 더 링 버퍼 를 FBO 의 깊이 캐 시 로 사용 합 니 다.FBO 의 생 성과 마찬가지 로 우 리 는 먼저 렌 더 링 버퍼 에 효과 적 인 표 지 를 지정 해 야 합 니 다.GLuint depthbuffer;glGenRenderbuffersEXT(1, &depthbuffer); 위의 단 계 를 성공 적 으로 완성 한 후에 우 리 는 이 버퍼 를 연결 하여 현재 렌 더 링 버퍼 가 되도록 해 야 합 니 다.다음은 실현 코드 입 니 다.glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer); FBO 의 바 인 딩 함수 와 마찬가지 로 첫 번 째 매개 변 수 는'목표(target)'입 니 다.어떤 목표 와 바 인 딩 을 하려 는 지 말 합 니 다.현재 로 서 는 미리 정 의 된 목표 일 수 밖 에 없습니다.변수 dephtbuffer 는 이미지 표 지 를 저장 하 는 데 사 용 됩 니 다.여기 에는 중요 한 부분 이 있 습 니 다.즉,우리 가 만 든 렌 더 링 버퍼 쌍 상 입 니 다.그 자체 가 메모리 공간 을 자동 으로 분배 하지 않 습 니 다.따라서 우 리 는 OpenGL 의 함 수 를 호출 하여 지정 한 크기 의 메모리 공간 을 분배 해 야 합 니 다.여기 서 우 리 는 고정된 크기 의 깊이 와 느 린 디 스 플레이 공간 을 분배 합 니 다.glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height); 위의 함수 가 성공 적 으로 실행 되면 OpenGL 은 width x height 크기 의 깊이 버퍼 를 할당 합 니 다.주의해 야 할 것 은 여기 GL 을 사 용 했 습 니 다.DEPTH_COMPONENT 는 우리 의 공간 이 깊이 값 을 저장 하 는 데 사용 되 는 것 을 말 합 니 다.그러나 이것 을 제외 하고 렌 더 링 버퍼 는 일반적인 RGB/RGBA 형식의 데이터 나 템 플 릿 버퍼 정 보 를 저장 하 는 데 도 사용 할 수 있 습 니 다.깊이 캐 시 된 메모리 공간 이 준 비 된 후에 다음 에 해 야 할 일 은 바로 앞에서 우리 가 준비 한 FBO 쌍 과 연결 하 는 것 입 니 다.glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer); 이 함 수 는 보기에 좀 복잡 해 보이 지만,사실 그것 은 매우 이해 하기 쉽다.이것 이 해 야 할 모든 작업 은 앞에서 우리 가 생 성 한 깊이 캐 시 를 현재 의 FBO 와 연결 하 는 것 입 니 다.물론 우 리 는 하나의 FBO 가 여러 개의 서로 다른 연결 점 이 있 는 지 주의해 야 합 니 다.여 기 는 FBO 의 깊이 버퍼 연결 점 에 연결 해 야 합 니 다.
렌 더 링 에 사용 할 텍 스 처 를 추가 합 니 다.아직 까지 FBO 에 색상 정 보 를 쓸 방법 이 없습니다.이것 도 우리 가 다음 에 토론 하려 고 하 는 것 이다.우 리 는 다음 과 같은 두 가지 방법 으로 그것 을 실현 할 수 있다.
색상 렌 더 링 버퍼 를 FBO 와 연결 합 니 다
하나의 무늬 를 FBO 와 연결 합 니 다
전 자 는 어떤 곳 에서 사용 되 고,뒤의 장절 은 우리 가 깊이 토론 할 것 이다.이제 두 번 째 방법 부터 말씀 드 리 겠 습 니 다.당신 이 무늬 를 FBO 와 연결 시 키 기 전에 우 리 는 먼저 이 무늬 를 만들어 야 합 니 다.이 무늬 를 만 드 는 과정 은 우리 가 평소에 본 무늬 의 생 성 과 별 차이 가 없다.GLuint img;glGenTextures(1, &img);glBindTexture(GL_TEXTURE_2D, img);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 이 인 스 턴 스 에서 우 리 는 일반적인 RGBA 그림 을 만 듭 니 다.크기 는 width x height 입 니 다.앞에서 우리 가 만 든 렌 더 링 버퍼 의 크기 와 같 습 니 다.이 점 은 매우 중요 합 니 다.즉,FBO 의 모든 바 인 딩 대상 은 똑 같은 너비 와 높이 가 있어 야 합 니 다.그리고 주의해 야 할 것 은 여기 서 우 리 는 어떠한 데 이 터 를 업로드 하지 않 았 고 OpenGL 이 분 배 된 공간 을 유지 하도록 했 을 뿐 잠시 후에 사용 할 것 입 니 다.좋 은 무늬 를 만 든 후에 다음 작업 은 바로 이 무늬 를 FBO 와 연결 시 켜 우리 가 데 이 터 를 무늬 공간 에 렌 더 링 할 수 있 도록 하 는 것 이다.glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, img, 0); 여기 서 이 매우 무서워 보 이 는 함 수 를 다시 보 았 다.물론 그것 도 우리 가 상상 하 는 것 처럼 그렇게 이해 하기 어렵 지 않다.파라미터 GLCOLOR_ATTACHMENT0_EXT 는 OpenGL 에 FBO 에 결 을 연결 하 는 0 번 바 인 딩 점(하나의 FBO 는 같은 시간 에 여러 개의 색 버퍼 를 연결 할 수 있 고 각 FBO 에 대응 하 는 바 인 딩 점)을 알려 주 는 것 입 니 다.매개 변수 GLTEXTURE_2D 는 텍 스 처 를 지정 하 는 형식 입 니 다.img 은 텍 스 처 표 지 를 저장 하고 전에 준 비 된 텍 스 처 를 가리 킵 니 다.무늬 는 다 중 맵 의 이미지 일 수 있 습 니 다.마지막 매개 변 수 는 등급 을 0 으로 지정 합 니 다.원 이미 지 를 사용 하 는 것 을 말 합 니 다.마지막 으로 해 야 할 일 은 FBO 의 준비 작업 이 모두 완성 되 었 는 지,경 을 통 해 정확하게 사용 되 었 는 지 확인 하 는 것 이다.이 테스트 작업 은 다음 함수 로 이 루어 집 니 다.현재 연 결 된 FBO 의 정확 한 상태 정 보 를 되 돌려 줍 니 다.GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); 모든 작업 이 완료 되 었 다 면 돌아 오 는 상태 값 은 GL 입 니 다.FRAMEBUFFER_COMPLETE_EXT,즉 당신 의 FBO 는 이미 준비 가 되 어 있 고 렌 더 링 대상 으로 사용 할 수 있 습 니 다.그렇지 않 으 면 다른 오류 코드 를 되 돌려 줍 니 다.정 의 된 문 서 를 찾 으 면 관련 오류 정 보 를 찾 을 수 있 습 니 다.그래서 각 오 류 는 어느 단계 에서 발생 했 는 지 알 수 있 습 니 다.
텍 스 처 에 렌 더 링 하 는 모든 어 려 운 작업 은 바로 앞에서 FBO 환경 을 구축 하 는 부분 입 니 다.남 은 작업 은 상당히 간단 합 니 다.관련 된 일 은 다음 과 같은 함수 만 호출 하 는 것 입 니 다.glBind FramebufferEXT().우리 가 데 이 터 를 렌 더 링 하고 FBO 에 출력 하려 면 이 함수 로 FBO 를 연결 해 야 합 니 다.FBO 로 출력 을 중지 하려 면 매개 변 수 를 0 으로 설정 하고 이 함 수 를 다시 호출 하면 됩 니 다.물론 FBO 로 의 출력 을 중단 하 는 것 도 중요 하 다.우리 가 FBO 작업 을 마 쳤 을 때 FBO 를 멈 추고 화면 에서 그림 을 정확하게 출력 할 수 있 도록 해 야 한다.glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);glPushAttrib(GL_VIEWPORT_BIT);glViewport(0,0,width, height);// Render as normal here// output goes to the FBO and it's attached buffersglPopAttrib();glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); 위의 세 줄 코드 glPushAttrib/glPopAttrib 및 glViewport 는 FBO 렌 더 링 에서 뛰 어 내 릴 때 원래 의 렌 더 링 경 로 를 되 돌 릴 수 있 도록 하 는 데 사 용 됩 니 다.glViewport 가 여기 서 호출 하 는 것 은 매우 필요 합 니 다.우 리 는 자주 데 이 터 를 FBO 크기 보다 크 거나 작은 지역 으로 렌 더 링 하지 마 십시오.함수 glPushAtrrib 와 glPopAttrib 는 시각 정 보 를 빠르게 저장 하 는 데 사 용 됩 니 다.FBO 가 주 컨 텍스트 의 모든 정 보 를 공유 하기 때문에 이 단계 도 필요 하 다.모든 변동 은 FBO 와 메 인 컨 텍스트 에 동시에 영향 을 줄 수 있 습 니 다.물론 정상 적 인 화면 렌 더 링 에 도 직접적인 영향 을 줄 수 있 습 니 다.이 중요 한 정 보 는 우리 가 그 릴 때 만 연결 하거나 FBO 를 해제 하 는 것 을 알 수 있 습 니 다.그러나 우 리 는 무늬 나 렌 더 링 버퍼 를 다시 연결 하지 않 았 습 니 다.여 기 는 FBO 에 이러한 연결 관 계 를 계속 저장 하기 때 문 입 니 다.분리 하거나 FBO 쌍 을 소각 하지 않 는 한.
 
이상 의 내용 은 인용------------------------------------------------------------------------------
위의 내용 을 보고 FrameBuffer 에 대해 비교적 완전한 이 해 를 가 져 야 합 니 다.사실은 제 가 해 야 할 일 은 framebuffer 프로그램 을 인터페이스 로 정리 하여 사용 할 수 있 도록 하 는 것 입 니 다.
CFramebuffer.h
#pragma once

#include 
#include 
#include 
#include 

class CFrameBuffer
{
public:
	CFrameBuffer();
public:
	~CFrameBuffer();
private:
	unsigned int m_FboID;
	unsigned int m_RboID;
	unsigned int m_tex;
	bool     m_bIsBegined;
	int      m_curbuff;

public:
	int     m_width;
	int		m_height;

public:
	void init(int width, int height);
	bool begin();
	bool end();
	void saveFrameBuff(const char* fileName);

	unsigned int getTex(){return m_tex;}
};

CFramebuffer.cpp
#include "stdafx.h"

#include 
#include "CFrameBuffer.h"
CFrameBuffer::CFrameBuffer()
{
	m_FboID = 0;
	m_RboID = 0;
	m_tex   = 0;
	m_bIsBegined = false;
	m_width = 0;
	m_height = 0;
	m_curbuff = 0;
}

CFrameBuffer::~CFrameBuffer()
{
	if(m_bIsBegined)
	{
		end();
		m_bIsBegined = false;
	}
	glDeleteTextures(1,&m_tex);
	glDeleteRenderbuffersEXT(1,&m_RboID);
	glDeleteFramebuffersEXT(1,&m_FboID);
}

void CFrameBuffer::init(int width, int height)
{
	glewInit();
	m_width = width;
	m_height = height;

	glEnable(GL_TEXTURE_2D);
	glGenTextures(1,&m_tex);
	glBindTexture(GL_TEXTURE_2D,m_tex);

	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,m_width,m_height,0,GL_BGR,GL_UNSIGNED_BYTE,NULL);
	glBindTexture(GL_TEXTURE_2D,0);
	glDisable(GL_TEXTURE_2D);

	glEnable(GL_RENDERBUFFER_EXT);
	glGenRenderbuffersEXT(1,&m_RboID);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,m_RboID);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT,m_width,m_height);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,0);
	glDisable(GL_RENDERBUFFER_EXT);

	glEnable(GL_FRAMEBUFFER_EXT);
	glGenFramebuffersEXT(1,&m_FboID);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,m_FboID);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D,m_tex,0);
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT,m_RboID);
	

	GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

	if(status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		switch(status)
		{
		case GL_FRAMEBUFFER_COMPLETE_EXT:
			std::cout << "Framebuffer complete." << std::endl;
			break;

		case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
			std::cout << "[ERROR] Framebuffer incomplete: Attachment is NOT complete." << std::endl;
			break;

		case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
			std::cout << "[ERROR] Framebuffer incomplete: No image is attached to FBO." << std::endl;
			break;

		case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
			std::cout << "[ERROR] Framebuffer incomplete: Attached images have different dimensions." << std::endl;
			break;

		case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
			std::cout << "[ERROR] Framebuffer incomplete: Color attached images have different internal formats." << std::endl;
			break;

		case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
			std::cout << "[ERROR] Framebuffer incomplete: Draw buffer." << std::endl;
			break;

		case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
			std::cout << "[ERROR] Framebuffer incomplete: Read buffer." << std::endl;
			break;

		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
			std::cout << "[ERROR] Unsupported by FBO implementation." << std::endl;
			break;

		default:
			std::cout << "[ERROR] Unknow error." << std::endl;
			break;
		}
	}
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
	glDisable(GL_FRAMEBUFFER_EXT);
	
	m_curbuff = 0;
}

bool CFrameBuffer::begin()
{
	if(m_bIsBegined)
	{
		return false;
	}
	else
	{
		//glPushAttrib(GL_ALL_ATTRIB_BITS);
		//glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT,&m_curbuff);
		//glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,m_FboID);

		glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT,&m_curbuff);
		glPushAttrib(GL_VIEWPORT_BIT);
		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();

		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,m_FboID);
		//cout<imageData);
	glDisable(GL_TEXTURE_2D);

	cvFlip(pImage,NULL,0);
	cvSaveImage(fileName,pImage);
	cvReleaseImage(&pImage);
}

위 에 상세 하 게 적 힌 framebuffer 의 내용 은 draw 함수 전에 begin()과 draw 함 수 를 호출 한 후에 end()로 무늬 를 framebuffer 에 그 리 는 것 을 완성 할 수 있 습 니 다.여기 에는 framebuffer 의 무늬 를 그림 에 저장 하고 OpenCV 의 일부 함수 에 연결 하 는 함수 도 사용 합 니 다.
 
 
 
다음으로 전송:https://www.cnblogs.com/leven20061001/archive/2012/08/28/2724692.html

좋은 웹페이지 즐겨찾기