=======================
=======================
=======================
OpenGL을 쓰고 항시 API를 쓰고 다시 해제해주어야 하는 API들은 는 해제 해주는것을 잊지 마세요
예로들어 wglMakeCurrent(...)로 들자면
HDC hdc = getHDC();
HGLRC hglrc = getHGLRCRES_GL();
::wglMakeCurrent(hdc, hglrc); //사용
//-----------------------------------//{랜더링 코드들..................................................................//}//-----------------------------------::wglMakeCurrent(NULL, NULL); //::wglMakeCurrent(hdc, NULL); //해제
위와같이 wglMakeCurrent(...) 랜더링 부분에 Api 사용과 해제 부분을 제대로 하지 않으면 다른
위치의 wglMakeCurrent(...) 를 사용시 문제가 생길수 있습니다.
=======================
=======================
=======================
출처: http://iskim3068.tistory.com/21
FBO에 대해 알아봅시다~
우선 버퍼(buffer)가 무엇인지 알아보자
컴퓨팅에서, 버퍼(buffer, 문화어: 완충기억기)는 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안 일시적으로 그 데이터를 보관하는 메모리의 영역이다. 버퍼링(buffering)이란 버퍼를 활용하는 방식 또는 버퍼를 채우는 동작을 말한다. 다른 말로 '큐(Queue)'라고도 표현한다.
보통 데이터는 키보드와 같은 입력 장치로부터 받거나 프린터와 같은 출력 장치로 내보낼 때 버퍼 안에 저장된다. 그러나 버퍼는 컴퓨터 안의 프로세스 사이에서 데이터를 이동시킬 때 사용된다. 이는 전자 통신의 버퍼와 비유할 수 있다. 버퍼는 하드웨어나 소프트웨어에 추가될 수 있지만 버퍼는 상당수가 소프트웨어에 추가된다. 버퍼는 보통 속도가 계속 바뀔 수 있으므로 데이터 수신, 처리 속도에 차이가 있다. (예: 프린터 스풀러)
버퍼는 네트워크 상에서 자료를 주고 받을 때나 스피커에 소리를 재생할 때, 또는 디스크 드라이브와 같은 하드웨어의 입출력을 결합하는 데에 자주 이용된다. 버퍼는 또한 순서대로 데이터를 출력하는 FIFO 방식에서 보통 사용된다.
-위키백과-
프레임 버퍼(frame buffer) 란
래스터 주사 방식에서 화면에 나타날 영상 정보를 일시적으로 저장하는 기억 장치.
그래픽 프로세서가 중앙 처리 장치(CPU)로부터 도형을 표현하는 디스플레이 리스트를 받아 변환하여 프레임 버퍼에 기록한다. 프레임 버퍼의 각 기억 단위는 화면의 하나의 화소에 하나씩 대응하여 화면에 그대로 반영된다. 즉 화면의 각 점의 온(on)/오프(off)나 색깔을 비트 맵으로 기억하고 있으며 이 기억 장치에 어떤 내용을 써넣으면 그것이 화면에 표시된다. 이는 대개 시스템의 주기억 장치와는 별도로 분리되어 있으며, 특별한 기술을 사용하여 속도를 빠르게 하기도 한다.
FBO 란?( frame buffer object )
OpenGL 렌더링 파이프라인에서 geometry 데이터 및 질감 변화 몇 가지 테스트를 통과 그리고 마지막으로 2D 픽셀 화면에 렌더링.
OpenGL 파이프라인의 최종 렌더링 대상 프레임 버퍼를라고 합니다. 프레임 버퍼는 2D 배열 또는 스토리지 OpenGL;에 의해 활용 모음 색상 버퍼, 깊이 버퍼, 스텐실 버퍼와 누적 버퍼. 기본적으로 OpenGL 프레임 버퍼를 사용 하 여 생성 되 고 전적으로 윈도우 시스템에 의해 관리 되는 렌더링 대상으로. 이 기본 프레임 버퍼 창 시스템 제공 버퍼를 라고 합니다.OpenGL 확장 GL_ARB_framebuffer_object 추가 비 표시할 수 있는 프레임 버퍼 개체 (FBO)를 만들 수 있는 인터페이스를 제공 합니다. 이 버퍼 기본 윈도우 시스템 제공 버퍼에서 구분 하기 위해 응용 프로그램 생성 프레임 버퍼를 라고 합니다. 프레임 버퍼 개체 (FBO)를 사용 하 여 OpenGL 응용 프로그램 전통적인 창 시스템 제공 버퍼 이외 응용 프로그램 만든 프레임 버퍼 개체 (FBO) 렌더링 출력을 리디렉션할 수 있습니다. 그리고, 그것은 완전히 OpenGL에 의해 제어 됩니다.창 시스템 제공 버퍼와 마찬가지로 FBO 목적지; 렌더링의 컬렉션을 포함 색상, 깊이 스텐실 버퍼입니다. (누적 버퍼 FBO에서 정의 되지 않은 참고.) 이러한 논리는 FBO 버퍼는 프레임 버퍼 개체를 연결할 수 있는 픽셀의 2 차원 배열을 프레임 버퍼를 연결할 수 있는 이미지를 라고 합니다.거기 두 가지 유형의 프레임 버퍼 연결 가능한 이미지; 텍스처 이미지와 renderbuffer 이미지입니다. 텍스처 개체의 이미지를 프레임 버퍼에 연결 하는 경우 OpenGL "텍스처 렌더링"을수행 합니다. Renderbuffer 개체의 이미지를 프레임 버퍼에 연결, OpenGL 수행 "오프 스크린 렌더링"
.
그건 그렇고, renderbuffer 개체 는 GL_ARB_framebuffer_object 확장에 정의 된 저장소 개체의 새로운 유형입니다. 렌더링 프로세스 동안 단일 2D 이미지 렌더링 대상으로 사용 됩니다.
다음 다이어그램에서는 프레임 버퍼 개체, 텍스처 개체 renderbuffer 개체 간의 연결을 보여 줍니다. 여러 질감 개체 또는 renderbuffer 개체는 첨부 파일 포인트를 통해 프레임 개체에 첨부할 수 있습니다.여러 색상 첨부 파일 포인트 (GL_COLOR_ATTACHMENT0,..., GL_COLOR_ATTACHMENTn), 하나의 깊이 첨부 파일 점 (GL_DEPTH_ATTACHMENT), 및 1 개의 스텐실 첨부 파일 (GL_STENCIL_ATTACHMENT) 프레임 버퍼 개체에. 컬러 첨부 파일 포인트 수 구현 종속, 하지만 각 FBO 적어도 하나의 색상 부속품 지점이 있어야 합니다. 그래픽 카드에서 지 원하는 GL_MAX_COLOR_ATTACHMENTS와 컬러 부속품 포인트의 최대 수를 쿼리할 수 있습니다. 이유는 FBO 여러 컬러 부속품 포인트 동시에 여러 대상 색상 버퍼를 렌더링 하는 데 허용 됩니다. GL_ARB_draw_buffers 확장에 의해이 "여러 렌더링 대상" (MRT)을 수행할 수 있습니다. 프레임 버퍼 개체 자체는, 그러나, 그것은 어떤 이미지 storage(array) 통지만 여러 첨부 파일 포인트를 했다.프레임 버퍼 개체 (FBO)를 효율적인 스위칭 메커니즘; 이전 프레임 버퍼를 연결할 수 있는 이미지는 FBO에서 분리 하 고 FBO를 새로운 프레임 버퍼를 연결할 수 있는 이미지를 첨부. FBOs 사이 전환 보다 훨씬 빠릅니다 프레임 버퍼를 연결할 수 있는 이미지를 전환 합니다. FBO glFramebufferTexture2D() 2D 텍스처 개체 및 glFramebufferRenderbuffer() renderbuffer 개체를 전환 스위치를 제공 합니다.
참조 : http://www.songho.ca
출처: http://iskim3068.tistory.com/21 [LausdeoF]
=======================
=======================
=======================
출처: http://diehard98.tistory.com/m/entry/FBO-FrameBuffer-Object-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
FBO는 OpenGL에서 사용하는 '외부에 그리기' 기술중 하나로써 나도 종종 사용한다. FBO를 사용함으로써 사용자는 다양한 작업이 가능해 진다.
1. 셋업
GLuint fbo; glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
2. 깊이 버퍼 (Depth buffer) 추가
GLuint depthbuffer; glGenRenderbuffersEXT(1, &depthbuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthbuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthbuffer);
3. 렌더링 텍스쳐 추가하기
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);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, img, 0);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
4. 텍스쳐로 렌더링하기
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); // FBO 바인딩 glPushAttrib(GL_VIEWPORT_BIT); glViewport(0,0,width, height); // 여기서 부터는 텍스쳐에 렌더링한다.
// Render as normal here // output goes to the FBO and it’s attached buffers glPopAttrib(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // 언바인딩. FBO에 렌더링하기 중지
5. 렌더링 된 FBO의 색상 버퍼를 텍스쳐로 사용하기
glBindTexture(GL_TEXTURE_2D, img);
glGenerateMipmapEXT(GL_TEXTURE_2D);
glGenTextures(1, &img); glBindTexture(GL_TEXTURE_2D, img); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glGenerateMipmapEXT(GL_TEXTURE_2D);
void display(void){// FBO 바인딩 - FBO에 렌더링 하겠다고 알려줌glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);// 각종 화면 관련 속성 저장해 놓기 - FBO에 렌더링 끝나면 이전값으로 복귀하기 위해서glPushAttrib(GL_VIEWPORT_BIT);glViewport(0,0,width,height);// 이제 부터 회전하는 작은 큐브를 FBO에 그린다.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();glTranslatef(0.0f,0.0f,-2.0f);glRotatef(xrot,1.0f,0.0f,0.0f);glRotatef(yrot,0.0f,1.0f,0.0f);glBegin(GL_QUADS);// Front FaceglColor4f(0.0f,1.0f,0.0f,1.0f);glVertex3f(-0.5f, -0.5, 0.5);glVertex3f( 0.5, -0.5, 0.5);glVertex3f( 0.5, 0.5, 0.5);glVertex3f(-0.5, 0.5, 0.5);// Back FaceglColor4f(1.0f,0.0f,0.0f,1.0f);glVertex3f(-0.5, -0.5, -0.5);glVertex3f(-0.5, 0.5, -0.5);glVertex3f( 0.5, 0.5, -0.5);glVertex3f( 0.5, -0.5, -0.5);// Top FaceglColor4f(0.0f,0.0f,1.0f,1.0f);glVertex3f(-0.5, 0.5, -0.5);glVertex3f(-0.5, 0.5, 0.5);glVertex3f( 0.5, 0.5, 0.5);glVertex3f( 0.5, 0.5, -0.5);// Bottom FaceglColor4f(0.0f,1.0f,1.0f,1.0f);glVertex3f(-0.5, -0.5, -0.5);glVertex3f( 0.5, -0.5, -0.5);glVertex3f( 0.5, -0.5, 0.5);glVertex3f(-0.5, -0.5, 0.5);// Right faceglColor4f(1.0f,1.0f,0.0f,1.0f);glVertex3f( 0.5, -0.5, -0.5);glVertex3f( 0.5, 0.5, -0.5);glVertex3f( 0.5, 0.5, 0.5);glVertex3f( 0.5, -0.5, 0.5);// Left FaceglColor4f(1.0f,1.0f,1.0f,1.0f);glVertex3f(-0.5, -0.5, -0.5);glVertex3f(-0.5, -0.5, 0.5);glVertex3f(-0.5, 0.5, 0.5);glVertex3f(-0.5, 0.5, -0.5);glEnd();// 앞서 저장했던 화면 관련 값을 복구하고 FBO 사용 해제glPopAttrib();glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// 이제부터 그리는 것들은 스크린에 보여질 직접적인 것들glClearColor(0.0f, 0.0f, 0.2f, 0.5f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();// 여기서 FBO에 그려진 회전하는 규브 (색상 버퍼)를 바인딩한다glBindTexture(GL_TEXTURE_2D, img);// 여기서는 밉맵 옵션이 사용되지 않지만 만약 당신이 밉맵을 사용한다면 아래의 주석을 제거하고 텍스쳐 생성시에// glGenerateMipmapEXT() 함수를 호출하라.// glGenerateMipmapEXT(GL_TEXTURE_2D);glEnable(GL_TEXTURE_2D);glTranslatef(0.0f,0.0f,-2.0f);glRotatef(-xrot,1.0f,0.0f,0.0f);glRotatef(-yrot,0.0f,1.0f,0.0f);glColor4f(1.0f,1.0f,1.0f,1.0f);// 이제 FBO의 색상 버퍼를 텍스쳐로 사용하는 또다른 규브 그리기glBegin(GL_QUADS);// Front FaceglNormal3f( 0.0f, 0.0f, 1.0);glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, -0.5, 0.5);glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5, -0.5, 0.5);glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5, 0.5, 0.5);glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5, 0.5, 0.5);// Back FaceglNormal3f( 0.0f, 0.0f,-1.0);glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5, -0.5, -0.5);glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5, 0.5, -0.5);glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5, 0.5, -0.5);glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5, -0.5, -0.5);// Top FaceglNormal3f( 0.0f, 1.0, 0.0f);glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5, 0.5, -0.5);glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5, 0.5, 0.5);glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5, 0.5, 0.5);glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5, 0.5, -0.5);// Bottom FaceglNormal3f( 0.0f,-1.0, 0.0f);glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5, -0.5, -0.5);glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5, -0.5, -0.5);glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5, -0.5, 0.5);glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5, -0.5, 0.5);// Right faceglNormal3f( 1.0, 0.0f, 0.0f);glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5, -0.5, -0.5);glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5, 0.5, -0.5);glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5, 0.5, 0.5);glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5, -0.5, 0.5);// Left FaceglNormal3f(-1.0, 0.0f, 0.0f);glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5, -0.5, -0.5);glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5, -0.5, 0.5);glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5, 0.5, 0.5);glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5, 0.5, -0.5);glEnd();glDisable(GL_TEXTURE_2D);xrot+=xspeed;yrot+=yspeed;glutSwapBuffers ( );// 버퍼 스왑 (출력하기)}
6. 치우기
glDeleteFramebuffersEXT(1, &fbo);
glDeleteRenderbuffersEXT(1, &depthbuffer);
=======================
=======================
=======================
출처: https://www.khronos.org/opengl/wiki/Framebuffer_Object_Extension_Examples
This article needs proper formatting or improved descriptions. Further details can be found on the talk page. |
This page describes old functionality. You should use the core Framebuffer Object functionality if at all possible.RTT = render_to_textureThis page shows a few examples on how to setup a RTT and how to cleanup.The extension specification is at http://www.opengl.org/registry/specs/EXT/framebuffer_object.txtNote that this extension became core in GL 3.0 and at the same time they released the ARB version of the extensionhttp://www.opengl.org/registry/specs/ARB/framebuffer_object.txtGL_ARB_framebuffer_object brings together GL_EXT_framebuffer_object, GL_EXT_framebuffer_blit, GL_EXT_framebuffer_multisample, GL_EXT_packed_depth_stencil which are all folded into the core of GL 3.0.
Contents
[hide]- 1Quick example, render_to_texture (2D)
- 2Quick example, render_to_texture (2D), mipmaps
- 3Quick example, render_to_texture (Cubemap)
- 4Quick example, render_to_texture (2D Depth texture ONLY)
- 5Quick example, render_to_texture (2D), mipmaps, depth_stencil
- 6Quick example, render_to_buffer (p-buffer replacement)
- 7Limitations of GL_EXT_framebuffer_object
- 81 FBO or more
- 9The main framebuffer
- 10MSAA
- 11Color texture, Depth texture
- 12Depth only
- 13Color only
- 14Stencil
- 15MRT
- 16MRT and cubemaps
- 17glReadPixels
- 18Sampling and Rendering to the Same Texture
Quick example, render_to_texture (2D)
Let's assume we want to render to a texture and we also want depth testing to take place. We need to create a color texture and we need to attach it to the FBO. We need a depth buffer RenderBuffer and attach it to the FBO. Once you are done rendering to this texture, you can use it like any other texture. In this case, we don't care what happens to the depth values. If you want to access the depth (for example, from within your shader), you need to make a depth texture instead of a depth buffer RenderBuffer. Please look at the other examples. Also, keep in mind we are using the GL_RGBA8 format here which is a format supported by all GPUs.
//RGBA8 2D texture, 24 bit depth texture, 256x256 glGenTextures(1, &color_tex); glBindTexture(GL_TEXTURE_2D, color_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //NULL means reserve texture memory, but texels are undefined glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); //------------------------- glGenFramebuffersEXT(1, &fb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //Attach 2D texture to this FBO glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color_tex, 0); //------------------------- glGenRenderbuffersEXT(1, &depth_rb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256); //------------------------- //Attach depth buffer to FBO glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb); //------------------------- //Does the GPU support current FBO configuration? GLenum status; status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: cout<<"good"; default: HANDLE_THE_ERROR; } //------------------------- //and now you can render to GL_TEXTURE_2D glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); glClearColor(0.0, 0.0, 0.0, 0.0); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //------------------------- glViewport(0, 0, 256, 256); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 256.0, 0.0, 256.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //------------------------- glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); //------------------------- //************************** //RenderATriangle, {0.0, 0.0}, {256.0, 0.0}, {256.0, 256.0} //Read http://www.opengl.org/wiki/VBO_-_just_examples RenderATriangle(); //------------------------- GLubyte pixels[4*4*4]; glReadPixels(0, 0, 4, 4, GL_BGRA, GL_UNSIGNED_BYTE, pixels); //pixels 0, 1, 2 should be white //pixel 4 should be black //---------------- //Bind 0, which means render to back buffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
And in the end, cleanup
//Delete resources glDeleteTextures(1, &color_tex); glDeleteRenderbuffersEXT(1, &depth_rb); //Bind 0, which means render to back buffer, as a result, fb is unbound glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &fb);
Quick example, render_to_texture (2D), mipmaps
This example is nearly identical to the above sample code with one difference : glGenerateMipmapEXT is used to generate the mipmaps. You can use it to generate mipmaps whenever you want. Generally, you render to the texture, then unbind the FBO with glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0), then bind the texture with glBindTexture, then call glGenerateMipmapEXT. ALSO, notice that glGenerateMipmapEXT doesn't have an "s".
//RGBA8 2D texture, 24 bit depth texture, 256x256 glGenTextures(1, &color_tex); glBindTexture(GL_TEXTURE_2D, color_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //NULL means reserve texture memory, but texels are undefined //**** Tell OpenGL to reserve level 0 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); //You must reserve memory for other mipmaps levels as well either by making a series of calls to //glTexImage2D or use glGenerateMipmapEXT(GL_TEXTURE_2D). //Here, we'll use : glGenerateMipmapEXT(GL_TEXTURE_2D) //------------------------- glGenFramebuffersEXT(1, &fb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //Attach 2D texture to this FBO glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color_tex, 0); //------------------------- glGenRenderbuffersEXT(1, &depth_rb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256); //------------------------- //Attach depth buffer to FBO glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb); //------------------------- //Does the GPU support current FBO configuration? GLenum status; status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: cout<<"good"; default: HANDLE_THE_ERROR; } //------------------------- //and now you can render to GL_TEXTURE_2D glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //------------------------- glViewport(0, 0, 256, 256); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 256.0, 0.0, 256.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //------------------------- glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); //------------------------- //************************** //RenderATriangle, {0.0, 0.0}, {256.0, 0.0}, {256.0, 256.0} //Read http://www.opengl.org/wiki/VBO_-_just_examples RenderATriangle(); //------------------------- GLubyte pixels[4*4*4]; glReadPixels(0, 0, 4, 4, GL_BGRA, GL_UNSIGNED_BYTE, pixels); //pixels 0, 1, 2 should be white //pixel 4 should be black //---------------- //Bind 0, which means render to back buffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); //---------------- //**** Now that we rendered to level 0 of the texture, we must generate the mipmaps. //This should be quick since it is done on the GPU. glBindTexture(GL_TEXTURE_2D, color_tex); glGenerateMipmapEXT(GL_TEXTURE_2D)
And in the end, cleanup
//Delete resources glDeleteTextures(1, &color_tex); glDeleteRenderbuffersEXT(1, &depth_rb); //Bind 0, which means render to back buffer, as a result, fb is unbound glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &fb);
Quick example, render_to_texture (Cubemap)
In case you want to have dynamic reflections on a shiny object, you would want to do render to a cubemap.
The concept behind rendering to a cubemap is the following. Bind a cubemap face, then render to it. Bind another cubemap face, then render to it. There are 6 faces in total. You may think that rendering 6 times your scene will drag down performance and you are right. Don't update the cubemap often. You can update every 2 frames. Make your cubemap small, for example 256x256.
//RGBA8 Cubemap texture, 24 bit depth texture, 256x256 glGenTextures(1, &color_tex); glBindTexture(GL_TEXTURE_CUBE_MAP, color_tex); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //NULL means reserve texture memory, but texels are undefined glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+0, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+1, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+2, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+3, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+4, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+5, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); //------------------------- glGenFramebuffersEXT(1, &fb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //Attach one of the faces of the Cubemap texture to this FBO glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X, color_tex, 0); //------------------------- glGenRenderbuffersEXT(1, &depth_rb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256); //------------------------- //Attach depth buffer to FBO glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb); //------------------------- //Does the GPU support current FBO configuration? GLenum status; status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: cout<<"good"; default: HANDLE_THE_ERROR; } //------------------------- //and now you can render to GL_TEXTURE_CUBE_MAP_POSITIVE_X //In order to render to the other faces, do this : glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, color_tex, 0); //... now render glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, color_tex, 0); //... now render //... and so on
And in the end, cleanup
//Delete resources glDeleteTextures(1, &color_tex); glDeleteRenderbuffersEXT(1, &depth_rb); //Bind 0, which means render to back buffer, as a result, fb is unbound glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &fb);
Quick example, render_to_texture (2D Depth texture ONLY)
In this example, notice glDrawBuffer(GL_NONE) and glReadBuffer(GL_NONE). We don't need a color output so that is why we set them to GL_NONE. The important call is glDrawBuffer(GL_NONE). We do not want to render to a color buffer.
//32 bit depth texture, 256x256 glGenTextures(1, &depth_tex); glBindTexture(GL_TEXTURE_2D, depth_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); //NULL means reserve texture memory, but texels are undefined //You can also try GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24 for the internal format. //If GL_DEPTH24_STENCIL8_EXT, go ahead and use it (GL_EXT_packed_depth_stencil) glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, 256, 256, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); //------------------------- glGenFramebuffersEXT(1, &fb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //Attach glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0); //------------------------- //Does the GPU support current FBO configuration? //Before checking the configuration, you should call these 2 according to the spec. //At the very least, you need to call glDrawBuffer(GL_NONE) glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); GLenum status; status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: cout<<"good"; default: HANDLE_THE_ERROR; } //------------------------- //----and to render to it, don't forget to call //At the very least, you need to call glDrawBuffer(GL_NONE) glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); //------------------------- //If you want to render to the back buffer again, you must bind 0 AND THEN CALL glDrawBuffer(GL_BACK) //else GL_INVALID_OPERATION will be raised glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDrawBuffer(GL_BACK); glReadBuffer(GL_BACK);
And in the end, cleanup
//Delete resources glDeleteTextures(1, &depth_tex); //Bind 0, which means render to back buffer, as a result, fb is unbound glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &fb);
Quick example, render_to_texture (2D), mipmaps, depth_stencil
If GL_EXT_packed_depth_stencil is present, use it. Also called a D24S8 format. All common GPUs support this format.
http://www.opengl.org/registry/specs/EXT/packed_depth_stencil.txt
//RGBA8 2D texture, D24S8 depth/stencil texture, 256x256 glGenTextures(1, &color_tex); glBindTexture(GL_TEXTURE_2D, color_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); //NULL means reserve texture memory, but texels are undefined glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); //You must reserve memory for other mipmaps levels as well either by making a series of calls to //glTexImage2D or use glGenerateMipmapEXT(GL_TEXTURE_2D). //Here, we'll use : glGenerateMipmapEXT(GL_TEXTURE_2D); //------------------------- glGenFramebuffersEXT(1, &fb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //Attach 2D texture to this FBO glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color_tex, 0); //------------------------- glGenRenderbuffersEXT(1, &depth_stencil_rb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_stencil_rb); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, 256, 256); //------------------------- //Attach depth buffer to FBO glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_rb); //Also attach as a stencil glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_rb); //------------------------- //Does the GPU support current FBO configuration? GLenum status; status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: cout<<"good"; default: HANDLE_THE_ERROR; } //------------------------- //and now you can render to GL_TEXTURE_2D glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); glClearColor(0.0, 0.0, 0.0, 0.0); //It's always a good idea to clear the stencil at the same time as the depth when the format is D24S8. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //------------------------- glViewport(0, 0, 256, 256); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 256.0, 0.0, 256.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //------------------------- glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); //------------------------- //************************** //RenderATriangle, {0.0, 0.0}, {256.0, 0.0}, {256.0, 256.0} //Read http://www.opengl.org/wiki/VBO_-_just_examples RenderATriangle(); //------------------------- GLubyte pixels[4*4*4]; glReadPixels(0, 0, 4, 4, GL_BGRA, GL_UNSIGNED_BYTE, pixels); //pixels 0, 1, 2 should be white //pixel 4 should be black //---------------- //Bind 0, which means render to back buffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
And in the end, cleanup
//Delete resources glDeleteTextures(1, &color_tex); glDeleteRenderbuffersEXT(1, &depth_stencil_rb); //Bind 0, which means render to back buffer, as a result, fb is unbound glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &fb);
Quick example, render_to_buffer (p-buffer replacement)
Around 2000, the p-buffer extension was released which was used to do offscreen rendering. These days, it is best to use GL_EXT_framebuffer_object. This extension is much easier to use compared to p-buffer and best of all, it is cross platform. This example creates a RenderBuffer using 2 calls to glRenderbufferStorageEXT. The first call is for creating a color buffer and the second is used to create a depth buffer.
//RGBA8 RenderBuffer, 24 bit depth RenderBuffer, 256x256 glGenFramebuffersEXT(1, &fb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //Create and attach a color buffer glGenRenderbuffersEXT(1, &color_rb); //We must bind color_rb before we call glRenderbufferStorageEXT glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, color_rb); //The storage format is RGBA8 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, 256, 256); //Attach color buffer to FBO glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, color_rb); //------------------------- glGenRenderbuffersEXT(1, &depth_rb); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_rb); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256); //------------------------- //Attach depth buffer to FBO glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_rb); //------------------------- //Does the GPU support current FBO configuration? GLenum status; status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: cout<<"good"; default: HANDLE_THE_ERROR; } //------------------------- //and now you can render to the FBO (also called RenderBuffer) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //------------------------- glViewport(0, 0, 256, 256); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 256.0, 0.0, 256.0, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //------------------------- glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); //------------------------- //************************** //RenderATriangle, {0.0, 0.0}, {256.0, 0.0}, {256.0, 256.0} //Read http://www.opengl.org/wiki/VBO_-_just_examples RenderATriangle(); //------------------------- GLubyte pixels[4*4*4]; glReadPixels(0, 0, 4, 4, GL_BGRA, GL_UNSIGNED_BYTE, pixels); //pixels 0, 1, 2 should be white //pixel 4 should be black //---------------- //Bind 0, which means render to back buffer glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
And in the end, cleanup
//Delete resources glDeleteRenderbuffersEXT(1, &color_rb); glDeleteRenderbuffersEXT(1, &depth_rb); //Bind 0, which means render to back buffer, as a result, fb is unbound glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &fb);
Limitations of GL_EXT_framebuffer_object
One of the limitations of GL_EXT_framebuffer_object is that when you bind a color buffer and then you bind a depth buffer, both must have the same width and height or else the state of the FBO is considered invalid (incomplete). This means if you have 1 FBO that is 64x64, another which is 512x64, another that is 1024x1024, for each of those you have to allocate a separate depth buffer (if you need depth testing of course). This obviously wastes memory.
In GL 3.0, FBO became core and that limitation was removed.
You can create 1 depth buffer that is 1024x1024 and bind them to all 3 FBOs. Notice that the depth buffer is large enough for even the smaller textures like 64x64.
1 FBO or more
Is it better to make 1 FBO and bind your texture to it each time you need to render to the texture?
An FBO itself doesn't use much memory. It is a state vector object. In terms of performance, each time you bind, the driver needs to validate the state which costs CPU time. Logically, it would be better to have 1 FBO per Render_To_Texture (RTT).
However, it has been found that you get a speed boost if your textures is the same size and you use 1 FBO for them.
If you have 10 textures that are 64x64 and 10 textures that are 512x64, make 2 FBOs. One FBO for each group.
The main framebuffer
Can you bind the main framebuffer's depth buffer as a depth buffer for your FBO? No. You must create a depth texture or a depth Render Buffer.
Does GL 3.0 allow using the main depth buffer? No.
Can you do MRT (multiple render targets) and have the main color framebuffer as one of the targets? No, you can only target a texture or a Render Buffer. GL 3.0 doesn't support it either.
MSAA
Are multisample Render_To_Texture (RTT) supported?
Not directly. You need GL_EXT_framebuffer_multisample and you would have to copy the contents of the AA-FBO to a standard RTT.
Note that GL_EXT_framebuffer_multisample also became core in GL 3.0
See also http://www.opengl.org/wiki/GL_EXT_framebuffer_multisample
Color texture, Depth texture
In this example, we are attaching a color texture and also a depth texture and we'll render to both of them.
//RGBA8 2D texture, 24 bit depth texture, 256x256 glGenTextures(1, &color_tex); glBindTexture(GL_TEXTURE_2D, color_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //NULL means reserve texture memory, but texels are undefined glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); glGenTextures(1, &depth_tex); glBindTexture(GL_TEXTURE_2D, depth_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); //NULL means reserve texture memory, but texels are undefined glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 256, 256, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); //------------------------- glGenFramebuffersEXT(1, &fb); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); //Attach 2D texture to this FBO glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color_tex, 0/*mipmap level*/); //------------------------- //Attach depth texture to FBO glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_tex, 0/*mipmap level*/); //------------------------- //Does the GPU support current FBO configuration? GLenum status; status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); switch(status) { case GL_FRAMEBUFFER_COMPLETE_EXT: cout<<"good"; default: HANDLE_THE_ERROR; }
And in the end, cleanup
//Delete resources glDeleteTextures(1, &color_tex); glDeleteTextures(1, &depth_tex); //Bind 0, which means render to back buffer, as a result, fb is unbound glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &fb);
Depth only
This is similar to the case above (Color texture, Depth texture) except that since there is no color buffer, call glDrawBuffer(GL_NONE) before or after calling glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb) and then render. When you are done, call glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) to render to the main framebuffer. This is important, call glDrawBuffer(GL_BACK) after. If you call before glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0), a GL error will be raised.
As for your fragment shader, you should write to gl_FragColor or whatever your color output it. The GPU will automatically generate the depth value and write to gl_FragDepth. The color value is obviously dropped automatically by the GPU. Example
//[FRAGMENT SHADER] #version 110 void main() { gl_FragColor = vec4(1.0); }
Color only
Simply disable depth testing (glDisable(GL_DEPTH_TEST) and set the depth mask to FALSE (glDepthMask(GL_FALSE)) before you render to your RTT.
Stencil
NEVER EVER MAKE A STENCIL buffer. All GPUs and all drivers do not support an independent stencil buffer. If you need a stencil buffer, then you need to make a Depth=24, Stencil=8 buffer, also called D24S8. Please search for the example about GL_EXT_packed_depth_stencil on this page.
MRT
Talk about MRT
MRT and cubemaps
Talk about MRT and cubemaps
glReadPixels
Yes, you can bind a FBO and then render to it and then read with with a call to glReadPixels. It doesn't matter if what you have attached to the FBO is a RenderBuffer or a texture, glReadPixels will still read it and it will return the results.
For RTT (Render To Texture), if you will be using glGetTexImage, it is recommended that you unbind the FBO, make the texture current with a call to glActiveTexture and glBindTexture and use glGetTexImage. It is recommended that you avoid glGetTexImage and use the glReadPixels method since certain drivers don't do anything when you call glGetTexImage.
Sampling and Rendering to the Same Texture
You should read
http://www.opengl.org/wiki/Framebuffer_Objects#Feedback_Loops
http://www.opengl.org/wiki/GLSL_:_common_mistakes#Sampling_and_Rendering_to_the_Same_Texture
=======================
=======================
=======================
출처: http://yeomhyeonseop.blogspot.kr/2014/11/frame-buffer-object.html
Frame Buffer Object + Render to Texture
OpenGL의 최종 랜더링타깃은 FrameBuffer라고 불린다.
프레임버퍼에는 2D배열의 모음이나 OpenGL에서 사용되는것들이 저장된다.
(색상버퍼, 뎁스버퍼, 스텐실버퍼, etc)
기본적으로 OpenGL은 완전히 윈도우시스템이 만들고 관리하는 렌더링 타겟으로써 프레임버퍼를 사용한다. 이러한 디폴트 프레임버퍼를 Window System Privided FrameBuffer라 한다.
OpenGL의 glFrameBufferObject는 화면출력용이아닌 프레임버퍼 오브젝트를 생성할 수 있는 인터페이스이다.
이렇게 만들어진 프레임버퍼를 Application-created Framebuffer이라 불리운다.
Application created FBO를 사용함으로써 OpenGL프로그램은 랜더링 결과에 redirect 할 수 있게 된다.
window-system-provided framebuffer와 비슷하게, FBO는 색상, 뎁스, 스텐실버퍼와 같은 렌더링 결과물의 collection을 저장한다.
그와같이 FBO안의 논리버퍼들을 framebuffer-attachable images라고 하고 이것은 크게 텍스쳐이미지와 RenerBuffer Image가 있다.
만일 택스쳐이미지가 FBO에 붙어있을 경우 OpenGL은 render to texure를 수행한다.
또한 렌더버퍼오브젝트가 붙어있을경우 OpenGL은 offscreen rendering을 수행한다
FBO - GL_COLOR_ATTACHMENT0 : Texture Object(Image)
GL_COLOR_ATTACHMENT1 : null
.
.
.
GL_DEPTH_ATTACHMENT : Renderbuffer Object(Image)
GL_STENCIL_ATTACHMENT : null
위 그림과같이 Texture Object나 Renderbuffer Object는 어태치먼트포인트를 통하여 FBO와 연관지을 수 있다.
통상 n개의 색상 어태치먼트포인트와 1개의 뎁스, 1개의 스텐실어태치먼트포인트로 이루어져있다.
COLOR_ATTACHMENT의 갯수는 시스템의존적이기에 GL_MAX_COLOR_ATTACHMENTS를 이용하여 그 최대치를 알 수 있다.
FBO가 여러개의 COLOR_ATTACHMENT를 가지고있는것은 컬러버퍼를 여러 목적지에 동시에 랜더링하는것을 가능하게 해준다.
이러한 multiple render targets(MRT)는 glDrawBuffers 익스텐션으로 구현가능하다.
FBO 그 자신은 그자신은 아무런 배열(저장소)를 가지고있지않고 오로지 어태치먼트 포인트만들 가지고 있다.
FBO는유능한 스위칭 매커니즘을 가지고있다. (이전 framebuffer-attachable image를 FBO에서 디태치하고 다른 image를 FBO에 어태치.)
이는 FBO간에 스위칭하는것보다 빠르게 작동된다.
또한 이는 불필요한 데이터복사본으로인한 메모리소비를 아껴준다.
예를들어 하나의 택스쳐를 여러 FBO에 어태치하므로써 이 texture image는 여러 FBO에서 공요될 수 있다.
FBO는 glFramebufferTexture2D() 를이용하여 2D texture object를 스위칭할 수 있고 glFramebufferRenderbuffer()를 이용하여 렌더버퍼오브젝트를 스위칭 할 수 있게끔 해준다.
FBO는
void glGenFramebuffers(GLsizei n, GLuint* ids)
메소르도 생성되며
void glDeleteFramebuffers(GLsizei n, const GLuint* ids)
함수를 이용하여 삭제할 수 있다.
또한
void glBindFramebuffer(GLenum target, GLuint id)
의 target을 GL_FRAMEBUFFER로 함으로써 바인딩 할 수 있다.
한번 FBO를 바인딩하면 모든 OpenGL 명령은 현재 바운딩되어있는 프레임버퍼에 적용된다.
id 0은 이폴트 윈도우시스템 프레임버퍼를 사용하게된다.
RenderBuffer Object는 offscreen rendering을 위해 새로 채용되었다.
이것은 씬을 텍스쳐오브젝트에 렌더하는 대신에 다이렉트로 렌더버퍼오브젝트에 랜더링 할 수 있게 만들어준다.
렌더버퍼는 단순히 하나의 렌더링가능한 내부포멧 이미지를 포함한 데이터 저장 오브젝트이다.
이것은 스텐실버퍼나 뎁스버퍼와 같은 서로 일치하는 텍스쳐포멧을 가지 않는 OpenGL의 논리버퍼들을 저장하기 위해 사용된다.
void glGenRenderbuffers(GLsizei n, GLuint* ids)
로 생성 가능하며
void glDeleteRenderbuffers(GLsizei n, const Gluint* ids)
로 삭제할 수 있다.
void glBindRenderbuffer(GLenum target, GLuint id)
의 target을 GL_RENDERBUFFER로 지정하여 바인딩 할 수 있다.
랜더버퍼오브젝트(이하 RBO)를생성할시 저장소(버퍼)에 아무런 데이터도 가지고 있지 않다. 즉 우리는 이를위한 메모리영역을 가져야 한다.
이는
void glRenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
를 이용하여 수행될 수 있다.
target은 GL_RENDERBUFFER이어야 하고 internalFormat은
색상 (GL_RGB, GL_RGBA, etc), 또는
뎁스 (GL_DEPTH_COMPONENT), 또는
스텐실 (GL_STENCIL_INDEX)이다.
width와 height는 렌더버퍼이미지의 픽셀 수용크기이다.
width와 height는 GL_MAX_RENDERBUFFER_SIZE보다 작아야하고 그렇지않을시 GL_INVALID_VALUE에러를 내게 된다.
또한 우리는 현재 바운드된 RBO의 여러가지 파라미터를 얻을 수 있는데 이는
void glGetRenderbufferParameteriv(GLenum target, GLenum param, GLint* value)
를 이용한다.
target은 GL_RENDERBUFFER이어야 하며 param은 얻고싶은 파라미터의 이름이다(GL_RENDERBUFFER_WIDTH, GL_REDERBUFFER_RED_SIZE, GL_RENDERBUFFER_DEPTH_SIZE etc.)
value는 리턴값을 저장할 포인터이다.
상기한것처럼 FBO는 그자신은 아무런 이미지 저장소(버퍼)를 가지지 않는다.
대신 우리는 framebuffer-attachable images를 FBO에 어태치 할 수 있다.
2D택스쳐를 FBO에 어태치하는것은
glFramebufferTexture2D(GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint textureId, GLint level)
를 이용하여 수행할 수 있다.
targer은 GL_FRAMEBUFFER이어야 하며 attachmentPoint는 GL_COLOR_ATTACHMENTn, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT와같은 어태치먼트 포인트이다.
textureTarget은 대부분의경우 GL_TEXTURE_2D이며 4번째인자는 텍스쳐ID가 입력된다.
마지막 파라미터는 부탁될 텍스쳐의 밉맵 레벨이 입력된다.
만일textureID파라미터가 0으로 설정될경우, 텍스쳐이미지는 FBO에서부터 분리된다(detach).
만일 텍스쳐오브젝트가 FBO에 부탁된채로 삭제될경우, 택스쳐이미지는 자동적으로 분리된다. 그러나 텍스쳐오브젝트가 여러 FBO에 어태치되어있는상태에서 삭제될경우, 이것은 현재 바운딩되어있는FBO에서만 디테치될 것이다. (현재 바운딩되어있지않은 FBO상에서는 분리되지 않을것이다).
또한 RBO를 FBO에 부착하고싶을 경우
void glFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbufferId)
를 사용한다.
target과 attachmentPoint는 텍스쳐를 어태치할때와 같은 파라미터를 사용한다.
renderbufferTarget은 GL_RENDERBUFFER를 사용하며 마지막파라미터는 RBO의 ID를 넣는다.
renderbufferID가 0으로 설정되 경우 랜더버퍼이미지는 FBO로부터 분리될 것이다.
RBO의 삭제에관한 디테치는 택스쳐오브젝트와 동일하게 작동한다.
일단 어태처블 이미지가 FBO에 어태치되고, FBO명령을 실행하기 전에 반드시 FBO의 상태가 완료되었는지, 또는 아직 완료되지 않았는지를
GLenum glCheckFramebufferStatus(GLenum target)
를 이용하여 확인해봐야 한다. 만일 FBO가 완성되지 않았다면 glBegin, glCopyTexImage2D등의 드로잉, 리딩명령들은 실패하게 될 것이다.
위 체크함수는 현재 바운드되어있는 FBO의 모든 어태치되어있는 이미지와 프레임버퍼요소들을 확인한다. 또한 이 함수는 glBegin()/glEnd()쌍 안에서 사용될 수 없다.
target파라미터에는 GL_FRAMEBUFFER가 들어가야 하고 이것은 FBO를 체크한후 0이아닌 값을 리턴한다.
만일 모든 필요조건과 규칙을 만족한다면 이것은 GL_FRAMEBUFFER_COMPLETE를 리턴할 것이다.
그렇지않다면 그에 해당하는 에러값을 반환할 것이다.
FBO를 사용하기위해 끝나야하는 준비조건들은
1. 어태치된 이미지(RBO 나 텍스쳐이미지)의width와 height가 0이 아닐것.
2. 만일 이미지가 색상어태치먼트포인트에 부탁되었을경우 이미지는 반드시 랜더링이가능한 색상 내부포멧을 가지고 있어야 한다 (GL_RGBA, GL_DEPTH_COMPONENT, GL_LUMINANCE etc)
3. 만일 이미지가 GL_DEPTH_ATTACHMENT에 부탁되어있다면 이미지는 반드시 렌더링 가능한 뎁스 내부포멧을 가져야 한다(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24)
4. 만일 이미지가 GL_STENCIL_ATTACHMENT에 부탁되어있다면 이미지는 반드시 렌더링 가능한 스탠실 내부포멧을 가져야 한다(GL_STENCIL_INDEX, GL_STENCIL_INDEX8 etc)
5. FBO는 반드시 최소한 하나의 이미지가 부착되어있어야한다
6. FBO에 부착된 모든 이미지는 반드시 같은 width와 height를 가져야 한다
7. 모든 부탁되어있는 컬러어태치먼트들은 동일한 내부포멧을 사용하여야 한다.
만일이의모든 조건을 만족하여도 사용중인 OpenGL드라이버에서 지원하지않는 몇몇 내부포멧이나 인자조합을 사용중이거나 지원하지않는 특수한 기능을 사용할경우 위 체크함수는 GL_FRAMEBUFFER_UNSUPPORTED를 반환한다.
동적 텍스쳐링에 필요한 render to texture은 이제까지 glCopyTexSubImage2D()를 이용하여 프레임버퍼의 내용을 텍스쳐로 복사하므로써 구현되어왔다.
그러나 FBO를 사용하면 씬을 텍스쳐에 직접 렌더링 할 수 있다.
종래의 방법은 텍스쳐에 렌더링하고싶은 이미지가 윈도우 크기보다 클경우 차분이 짤려나가는 문제가있었으나 FBO를이용한 방법에서는 단순히 택스쳐에 렌더링하고싶은 전체화면을 충분히 수용할수 있을만큼 큰 이미지를 만드는것으로 이를 해소할 수 있다.
출처 : OpenGL Frame Buffer Object by http://www.songho.ca
=======================
=======================
=======================
출처: http://wanochoi.com/?p=1019
Framebuffer는 rendering의 최종 결과가 기록되는 buffer들의 집합이다.
OpenGL context가 생성되면서 기본적으로 하나의 framebuffer를 생성하여 사용하는데,
이러한 default framebuffer를 window-system-provided framebuffer라고 부른다.
반면, 필요 시 임의의 framebuffer를 동적으로 생성하여 사용하는 것이 가능한데,
이렇게 생성된 framebuffer를 application-created framebuffer라고 하며,
일반적으로 framebuffer object (FBO)라고 한다.
FBO는 display 외의 목적으로도 많이 사용된다.
Buffer란 OpenGL이 관리하는 memory 영역을 말한다. (buffer=array=image)
이러한 의미로 보면 FBO는 사실 엄밀히 말해서 buffer는 아니다.
(사실 aggregator의 개념에 더 가깝다.)
FBO는 하나 또는 다수의 buffer들이 attach되어 있는 형태로 존재한다.
(여러 개의 array들에 대한 pointer들을 member로 가지는 구조체(struct)와 같은 개념.)
Default framebuffer에는 color, depth, stencil, accumulation의 용도로 사용되는 buffer들이 attach될 수 있지만, FBO에는 accumulation을 제외한 color, depth, stencil의 용도로 사용되는 buffer들이 attach될 수 있다.
하나의 FBO에는 다수의 attachment point들이 존재하며, 각각의 attachment point마다 하나의 buffer가 attach될 수 있다.
하나의 FBO는 n개(system 마다 다름)의 color attachment points와 각각 한 개씩의 depth attachment point, stencil attachment point를 가진다.
(GL_COLOR_ATTACHMENT0, …, GL_COLOR_ATTACHMENTn, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT)
하나의 FBO에는 최소한 한 개의 color buffer가 attach되어야 한다.
여러 개의 color attachment points를 가지고 있는 이유는 동시에 여러 개의 color buffer에 rendering이 가능하기 때문인데, 이러한 기법을 multiple render targets (MRT)라고 부른다.
Framebuffer attachable buffer는 크게 두 가지 type이 있다.
1. texture object 2. renderbuffer object
Texture object가 render target으로 설정되어 rendering이 수행되는 것을 render-to-texture,
RBO가 render target으로 설정되어 rendering 작업이 수행되는 것을 offscreen rendering이라고 한다.
기본적으로 RBO에 rendering 작업이 완료되었다고 해도 GPU memory 상에만 존재할 뿐 화면에는 보여지지 않기 때문이다.
Texture란 보통의 경우 3D model의 표면을 장식해주는 image의 역할을 수행하지만, 이 외에도 다양한 data를 저장하기 위해 사용될 수 있다.
즉, texture는 GPU에서 사용되는 bulk data를 저장하는 용도로 쓰인다.
(bulk data란 여러 가지 용도로 사용되는 data를 말함.)
Texture는 1D, 2D, 3D 등의 형태로 사용이 가능하며, shader 내에서 값을 읽어서 사용하는 것이 가능하다.
Texture는 GPU memory 상에 독립적으로 동적 할당되어 자유롭게 사용이 가능하지만, RBO는 반드시 FBO에 attach되어 사용되어야 한다.
RBO는 texture와는 달리 반드시 2D 형태로만 사용되어야 하고, 단 한 개의 image 만을 가질 수 있다. (texture에서처럼 mipmaps 사용이 불가능함.)
RBO에 저장된 rendering 결과는 glReadPixels(), glDrawPixels(), glCopyPixels()와 같은 함수들을 이용해서 읽고 쓰는 것이 가능하긴 하지만, shader 내에서는 값을 읽어오는 것이 불가능하므로 texture source 등의 용도로 사용할 수 없다. 만약 shader 내에서 특정 image의 값을 읽어올 필요가 있다면 texture object로 만들어서 사용해야 한다.
만약 shader에서 값을 읽어서 사용하지 않는다면 성능상 texture object 보다는 RBO type을 사용하는 것이 더 좋다.
보통의 경우 depth test가 필요할 경우 depth buffer를 RBO type으로 생한한 후 해당 FBO의 GL_DEPTH_ATTACHMENT에 attach해서 사용하지만, 만약 fragment shader에서 post processing을 수행할 때 depth 값이 필요하다면 texture object type으로 생성한 후 해당 FBO의 GL_DEPTH_ATTACHMENT에 attach해서 사용해야 한다.
Texture object를 생성하는 방법은 일반적으로 texture를 사용하는 경우와 동일하다.
다만 image data를 load하여 연결해줄 필요가 없으므로 glTexImage2D() 함수에서 맨 마지막 인자에는 NULL을 써주면 된다.
다음은 FBO를 한 개 생성한 후, depth buffer로 사용될 texture object를 생성하여 attach하는 예제이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// framebuffer object GLuint fboId; glGenFramebuffers( 1, &fboId ); glBindFramebuffer( GL_FRAMEBUFFER, fboId ); // texture buffer object to be used for depth buffer GLuint depthTexId; glGenTextures( 1, &depthTexId ); glBindTexture( GL_TEXTURE_2D, depthTexId ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL ); // attachment glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE2D, depthTexId, 0 ); |
다음은 FBO를 한 개 생성한 후, depth buffer로 사용될 renderbuffer object를 생성하여 attach하는 예제이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// framebuffer object GLuint fboId; glGenFramebuffers( 1, &fboId ); glBindFramebuffer( GL_FRAMEBUFFER, fboId ); // renderbuffer object to be used for depth buffer GLuint depthRboId; glGenRenderbuffers( 1, &depthRboId ); glBindRenderBuffer( GL_RENDERBUFFER, depthRboId ); glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height ); // attachment glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRboId ); |
=======================
=======================
=======================
출처: http://blog.daum.net/aero2k/53
Framebuffer Object를 이용한 Render To Texture(RTT) 구현.
OpenGL ES 2.0 programming guide 12장 Framebuffer Objects 의 예제 코드는 좀 많이 부실 하다.
이에 iPhone 3D Programming 책의 6장 블렌딩과 증강현실 장의 6-8 오프-스크린 FBO를 사용한 앤티 에일리어싱 기법 을 참조하였다.
iPhone 3D Programming 책의 6-8 장 이전까지는 FBO를 Single Surface로 사용한다.
이 장 이후 부터의 예제에는 EGL의 Double buffer과 유사하게 사용할 수 있는 FBO Off-screen 기법이 응용 된다.
<FBO에 대해서 궁금하신 분은 바른 생활님의 페이지(http://cafe.naver.com/gld3d/130)를 참고하시면 도움이 될것 같습니다.>
<VBO에 대해서 궁금하신 분은 바른 생활님의 페이지(http://cafe.naver.com/gld3d/129)를 참고하시면 도움이 될것 같습니다.>
<RTT에 대해서 궁금하신 분은 바른 생활님의 페이지(http://cafe.naver.com/gld3d/181)를 참고하시면 도움이 될것 같습니다.>
OpenGL ES 에서는 기본적으로 double buffering을 지원하지 않는다.
그럼으로 Framebuffer object를 이용하여, on-off screen 생성한 후 double buffering 처럼 활용할 수 있다.
이번에 RTT 기능을 만들면서 책의 예제를 응용 하다 보니깐 아 glFramebufferTexture2D 함수를 이용해서,
색상 버퍼를 Texture 객체로 실시간 변환 되는 것을 확인할 수 있었다.
void glFramebufferTexture2D(GLenum target,
GLenum attachment,
GLenum textarget,
GLuint texture, GLint level);
FBO Texture 객체는 다른 텍스쳐 객체와 동일하게 만들어 진다.
glGenTexture() 명령으로 Identification을 생성하고 필터링과 래핑 모드를 갖고 있으며,
FBO 포맷과 일치하는 포맷을 가져야 한다.
FBO Texture 객체가 기존 Texture을 불러오기 위해서 이용했었던 glTexImage2D() 을 사용할때,
마지막 인자는 NULL 값인 zero가 들어가야하는 점을 기억해야한다.
GLuint RenderingEngine::CreateFboTexture(int w, int h) const
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
{
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);texture
return;
}
glTexImage2D의 마지막 인자를 zero(0)로 하는 이유는 아직 그릴 그림이 없기 때문이다.
나중에 반환되는 texture를 binding해서 off-screen FBO에서 주전자를 그린다.
off-screen FBO에는 주전자가 실시간으로 렌더링 될 것이며, on-screen FBO에서는 이 주전자 texture를 cube box에 그려 넣을 것이다.
첫 번째 그림은 바른 생활님의 구현하신 RTT 소스에 있는 뽀로로의 친구 에디를 텍스쳐로 해서 그림을 그렸다.
이는 NeHe 07 상자 그리기 소스를 응용하면 쉽게 그릴 수 있다.
두 번째 그럼은 주전자 wavefront obj 파일을 teapot.h로 변환 해서 VBO에 저장 한후, RTT로 그린 결과 이다.
이제 NeHe.iOS.07.RTT 소스내에서 어떻게 onoff-screen을 구현 하는지 보도록 하자.
On Screen Frame Buffer Object
// Create the onscreen color render buffer.
glGenRenderbuffers(1, &m_onscreen_colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_onscreen_colorRenderbuffer);
// Create the onscreen depth render buffer.
glGenRenderbuffers(1, &m_onscreen_depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_onscreen_depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
// Create the onscreen framebuffer object.
glGenFramebuffers(1, &m_onscreen_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_onscreen_framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
m_onscreen_colorRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
m_onscreen_depthRenderbuffer);
// Bind the color buffer for rendering.
glBindRenderbuffer(GL_RENDERBUFFER, m_onscreen_colorRenderbuffer);
Off Screen Frame Buffer Object
// Create the off screen color render buffer.
glGenRenderbuffers(1, &m_offscreen_colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_offscreen_colorRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, width, height);
// Create the off screen depth render buffer.
glGenRenderbuffers(1, &m_offscreen_depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_offscreen_depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
// Create the off screen frame render buffer.
glGenFramebuffers(1, &m_offscreen_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_offscreen_framebuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, m_offscreen_colorRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, m_offscreen_depthRenderbuffer);CreateFboTexture(width, height);
m_offscreen_texture =
On Screen FBO 와 Off Screen FBO 두 가지를 생성하였다.
위의 FBO가 정상적으로 생성 되었는지 확인하기 위해서 다음과 같은 함수를 제공한다.
GLenum glCheckFramebufferStatus(GLenum target);
다음과 같이 사용할 수 있다.
// Check the Framebuffer status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "FBO error:l" << status << "\r\n";
}
Render To Texture 를 하기 위해서 on Screen FBO에 렌더링 하기 전에 Off Screen FBO를 먼저 그려 주어야 한다.
다음과 같이 Render() 함수가 구성 하였다.
void RenderingEngine::RenderToTexture()
{(가)
glBindFramebuffer(GL_FRAMEBUFFER, m_offscreen_framebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_offscreen_colorRenderbuffer);
...}
void RenderingEngine::Render()
{
...
// RenderToTexture를 통해서 teapot texture를 얻는다.
RenderToTexture(); (가)
if (m_texMode == 1)
{
xyrot_texture += 1;
glBindTexture(GL_TEXTURE_2D, m_offscreen_texture);
(나)
} else {
/* Select A Texture Based on filter */
glBindTexture(GL_TEXTURE_2D, m_texture_ids[m_texFilter]);
}
glBindFramebuffer(GL_FRAMEBUFFER, m_onscreen_framebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_onscreen_colorRenderbuffer);}
On - Off Screen 상에 순서에 유의 하도록 하자.
(가)
RenderToTexture() 함수에서 m_offscreen_framebuffer 와 m_offscreen_colorRenderbuffer로 바인딩 한후, 주전자를 그린다.
(나) 렌더링된 주전자 color buffer는 m_offscreen_texture 객체로 변환이 되어 있음으로, m_onscreen_framebuffer 와
m_onscreen_colorbuffer를 다시 바인딩 한후, cube box를 그린다.
cube box에 그림을 그릴때는 기존의 뽀로로의 친구 에디가 아닌, 주전자(
m_offscreen_texture) 텍스쳐로 그린다.
teapot texture 는 (가)에서 이미 바인딩 하였다.
순서에 유의 하도록 하자.
Render To Texture 를 이용해서 텍스쳐를 처리할 경우에는 POT(Power Of Two;16x16, 32x16, 128x64 크기) 텍스쳐가 아니어도 가능하다.
아이폰 이나 안드로이드(2.2 이후)에서는 텍스쳐의 크기가 2의 배수인 POT 텍스쳐여야 한다.
NPOT 텍스쳐의 경우, RTT를 이용하여 이용할 수 있겠다.
iPhone 3D Programming 에서 언급 되었지만, NPOT 텍스쳐는 다음과 같은 방법으로도 사용할 수 있다.
bool isPOT(unsigned int n)
{
bool bRet = false;
int tmp = n;
tmp--;tmp |= tmp >> 1; tmp |= tmp >> 2;
tmp |= tmp >> 4; tmp |= tmp >> 8;
tmp |= tmp >> 16;
tmp++;if (tmp == n) {
bRet = true;
}return bRet;
}
unsigned int NextPot(unsigned int n)
{
n--;
n |= n >> 1; n |= n >> 2;
n |= n >> 4; n |= n >> 8;
n |= n >> 16;
n++;
return n;
}
if (isPOT(description.OriginalSize.x) && isPOT(description.OriginalSize.y)) {
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
} else {width = NextPot(description.OriginalSize.x);
height = NextPot(description.OriginalSize.y);
unsigned char* temp = new unsigned char[width * height * 4];
memset(temp, 0x00, width*height*4);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, description.OriginalSize.x, description.OriginalSize.y, format, type, data);
delete[] temp;}
마지막으로, OGLES 2.0과 OGLES 1.1 두 버전을 구현 하였으며 두가지 버전을 구현할려니 빡셨다 ㅠ ㅠ
공부라 생각하고 하는데 까지 두 가지 버전으로 가봐야 할 것 같다.
프로젝트의 기본 구성이 OGLES 2.0으로 되어 있기 때문에,
OGLES 1.1로 전환을 위해서는
GLView.mm
파일의 EAGLRenderingAPI를
kEAGLRenderingAPIOpenGLES1 으로 변경해 주면 된다.
예제는 Google Code(http://code.google.com/p/myastro/)의 Download 페이지에 올려 놓았습니다.
=======================
=======================
=======================
출처: http://www.songho.ca/opengl/gl_fbo.html
Related Topics: Pixel Buffer Object (PBO)
Download: fbo.zip, fboDepth.zip, fboStencil.zip, fboBlit.zip, fboMsaa.zip
- Overview
- Creating FBO
- Renderbuffer Object
- FBO with MSAA (Multi Sample Anti Aliasing)
- Checking FBO Status
- Example: Render To Texture
Update: Framebuffer object extension is promoted as a core feature of OpenGL version 3.0, and is approved by ARB combining the following extensions;
- EXT_framebuffer_object
- EXT_framebuffer_blit
- EXT_framebuffer_multisample
- EXT_packed_depth_stencil
Overview
In OpenGL rendering pipeline, the geometry data and textures are transformed and passed several tests, and then finally rendered onto a screen as 2D pixels. The final rendering destination of the OpenGL pipeline is called framebuffer. Framebuffer is a collection of 2D arrays or storages utilized by OpenGL; colour buffers, depth buffer, stencil buffer and accumulation buffer. By default, OpenGL uses the framebuffer as a rendering destination that is created and managed entirely by the window system. This default framebuffer is called window-system-provided framebuffer.
The OpenGL extension, GL_ARB_framebuffer_object provides an interface to create additional non-displayable framebuffer objects (FBO). This framebuffer is called application-created framebuffer in order to distinguish from the default window-system-provided framebuffer. By using framebuffer object (FBO), an OpenGL application can redirect the rendering output to the application-created framebuffer object (FBO) other than the traditional window-system-provided framebuffer. And, it is fully controlled by OpenGL.
Similar to window-system-provided framebuffer, a FBO contains a collection of rendering destinations; color, depth and stencil buffer. (Note that accumulation buffer is not defined in FBO.) These logical buffers in a FBO are called framebuffer-attachable images, which are 2D arrays of pixels that can be attached to a framebuffer object.
There are two types of framebuffer-attachable images; texture images and renderbuffer images. If an image of a texture object is attached to a framebuffer, OpenGL performs "render to texture". And if an image of a renderbuffer object is attached to a framebuffer, then OpenGL performs "offscreen rendering".
By the way, renderbuffer object is a new type of storage object defined in GL_ARB_framebuffer_object extension. It is used as a rendering destination for a single 2D image during rendering process.
The following diagram shows the connectivity among the framebuffer object, texture object and renderbuffer object. Multiple texture objects or renderbuffer objects can be attached to a framebuffer object through the attachment points.
There are multiple color attachment points (GL_COLOR_ATTACHMENT0,..., GL_COLOR_ATTACHMENTn), one depth attachment point (GL_DEPTH_ATTACHMENT), and one stencil attachment point (GL_STENCIL_ATTACHMENT) in a framebuffer object. The number of color attachment points is implementation dependent, but each FBO must have at least one color attachement point. You can query the maximum number of color attachement points with GL_MAX_COLOR_ATTACHMENTS, which are supported by a graphics card. The reason that a FBO has multiple color attachement points is to allow to render the color buffer to multiple destinations at the same time. This "multiple render targets" (MRT) can be accomplished by GL_ARB_draw_buffers extension. Notice that the framebuffer object itself does not have any image storage(array) in it, but, it has only multiple attachment points.
Framebuffer object (FBO) provides an efficient switching mechanism; detach the previous framebuffer-attachable image from a FBO, and attach a new framebuffer-attachable image to the FBO. Switching framebuffer-attachable images is much faster than switching between FBOs. FBO provides glFramebufferTexture2D() to switch 2D texture objects, and glFramebufferRenderbuffer() to switch renderbuffer objects.
Creating Frame Buffer Object (FBO)
Creating framebuffer objects is similar to generating vertex buffer objects (VBO).
glGenFramebuffers()
void glGenFramebuffers(GLsizei n, GLuint* ids) void glDeleteFramebuffers(GLsizei n, const GLuint* ids)
glGenFramebuffers() requires 2 parameters; the first one is the number of framebuffers to create, and the second parameter is the pointer to a GLuint variable or an array to store a single ID or multiple IDs. It returns the IDs of unused framebuffer objects. ID 0 means the default framebuffer, which is the window-system-provided framebuffer.
And, FBO may be deleted by calling glDeleteFramebuffers() when it is not used anymore.
glBindFramebuffer()
Once a FBO is created, it has to be bound before using it.
void glBindFramebuffer(GLenum target, GLuint id)
The first parameter, target, should be GL_FRAMEBUFFER, and the second parameter is the ID of a framebuffer object. Once a FBO is bound, all OpenGL operations affect onto the current bound framebuffer object. The object ID 0 is reserved for the default window-system provided framebuffer. Therefore, in order to unbind the current framebuffer (FBO), use ID 0 in glBindFramebuffer().
Renderbuffer Object
In addition, renderbuffer object is newly introduced for offscreen rendering. It allows to render a scene directly to a renderbuffer object, instead of rendering to a texture object. Renderbuffer is simply a data storage object containing a single image of a renderable internal format. It is used to store OpenGL logical buffers that do not have corresponding texture format, such as stencil or depth buffer.
glGenRenderbuffers()
void glGenRenderbuffers(GLsizei n, GLuint* ids) void glDeleteRenderbuffers(GLsizei n, const Gluint* ids)
Once a renderbuffer is created, it returns non-zero positive integer. ID 0 is reserved for OpenGL.
glBindRenderbuffer()
void glBindRenderbuffer(GLenum target, GLuint id)
Same as other OpenGL objects, you have to bind the current renderbuffer object before referencing it. The target parameter should be GL_RENDERBUFFER for renderbuffer object.
glRenderbufferStorage()
void glRenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
When a renderbuffer object is created, it does not have any data storage, so we have to allocate a memory space for it. This can be done by using glRenderbufferStorage(). The first parameter must be GL_RENDERBUFFER. The second parameter would be color-renderable (GL_RGB, GL_RGBA, etc.), depth-renderable (GL_DEPTH_COMPONENT), or stencil-renderable formats (GL_STENCIL_INDEX). The width and height are the dimension of the renderbuffer image in pixels.
The width and height should be less than GL_MAX_RENDERBUFFER_SIZE, otherwise, it generates GL_INVALID_VALUE error.
glGetRenderbufferParameteriv()
void glGetRenderbufferParameteriv(GLenum target, GLenum param, GLint* value)
You also get various parameters of the currently bound renderbuffer object. target should be GL_RENDERBUFFER, and the second parameter is the name of parameter. The last is the pointer to an integer variable to store the returned value. The available names of the renderbuffer parameters are;
GL_RENDERBUFFER_WIDTH GL_RENDERBUFFER_HEIGHT GL_RENDERBUFFER_INTERNAL_FORMAT GL_RENDERBUFFER_RED_SIZE GL_RENDERBUFFER_GREEN_SIZE GL_RENDERBUFFER_BLUE_SIZE GL_RENDERBUFFER_ALPHA_SIZE GL_RENDERBUFFER_DEPTH_SIZE GL_RENDERBUFFER_STENCIL_SIZE
Attaching images to FBO
FBO itself does not have any image storage(buffer) in it. Instead, we must attach framebuffer-attachable images (texture or renderbuffer objects) to the FBO. This mechanism allows that FBO quickly switch (detach and attach) the framebuffer-attachable images in a FBO. It is much faster to switch framebuffer-attachable images than to switch between FBOs. And, it saves unnecessary data copies and memory consumption. For example, a texture can be attached to multiple FBOs, and its image storage can be shared by multiple FBOs.
Attaching a 2D texture image to FBO
glFramebufferTexture2D(GLenum target, GLenum attachmentPoint, GLenum textureTarget, GLuint textureId, GLint level)
glFramebufferTexture2D() is to attach a 2D texture image to a FBO. The first parameter must be GL_FRAMEBUFFER, and the second parameter is the attachment point where to connect the texture image. A FBO has multiple color attachment points (GL_COLOR_ATTACHMENT0, ..., GL_COLOR_ATTACHMENTn), GL_DEPTH_ATTACHMENT, and GL_STENCIL_ATTACHMENT. The third parameter, "textureTarget" is GL_TEXTURE_2D in most cases. The fourth parameter is the identifier of the texture object. The last parameter is the mipmap level of the texture to be attached.
If the textureId parameter is set to 0, then, the texture image will be detached from the FBO. If a texture object is deleted while it is still attached to a FBO, then, the texture image will be automatically detached from the currently bound FBO. However, if it is attached to multiple FBOs and deleted, then it will be detached from only the bound FBO, but will not be detached from any other un-bound FBOs.
Attaching a Renderbuffer image to FBO
void glFramebufferRenderbuffer(GLenum target, GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbufferId)
A renderbuffer image can be attached by calling glFramebufferRenderbuffer(). The first and second parameters are same as glFramebufferTexture2D(). The third parameter must be GL_RENDERBUFFER, and the last parameter is the ID of the renderbuffer object.
If renderbufferId parameter is set to 0, the renderbuffer image will be detached from the attachment point in the FBO. If a renderbuffer object is deleted while it is still attached in a FBO, then it will be automatically detached from the bound FBO. However, it will not be detached from any other non-bound FBOs.
FBO with MSAA (Multi Sample Anti Aliasing)
When you render to a FBO, anti-aliasing is not automatically enabled even if you properly create a OpenGL rendering context with the multisampling attribute (SAMPLEBUFFERS_ARB) for window-system-provided framebuffer.
In order to activate multisample anti-aliasing mode for rendering to a FBO, you need to prepare and attach multisample images to a FBO's color and/or depth attachement points.
FBO extension provides glRenderbufferStorageMultisample() to create a renderbuffer image for multisample anti-aliasing rendering mode.
void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height)
It adds new parameter, samples on top of glRenderbufferStorage(), which is the number of multisamples for anti-aliased rendering mode. If it is 0, then no MSAA mode is enabled and glRenderbufferStorage() is called instead. You can query the maximum number of samples with GL_MAX_SAMPLES token in glGetIntegerv().
The following code is to create a FBO with multisample colorbuffer and depthbuffer images. Note that if multiple images are attached to a FBO, then all images must have the same number of multisamples. Otherwise, the FBO status is incomplete.
// create a 4x MSAA renderbuffer object for colorbuffer int msaa = 4; GLuint rboColorId; glGenRenderbuffers(1, &rboColorId); glBindRenderbuffer(GL_RENDERBUFFER, rboColorId); glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_RGB8, width, height); // create a 4x MSAA renderbuffer object for depthbuffer GLuint rboDepthId; glGenRenderbuffers(1, &rboDepthId); glBindRenderbuffer(GL_RENDERBUFFER, rboDepthId); glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_DEPTH_COMPONENT, width, height); // create a 4x MSAA framebuffer object GLuint fboMsaaId; glGenFramebuffers(1, &fboMsaaId); glBindFramebuffer(GL_FRAMEBUFFER, fboMsaaId); // attach colorbuffer image to FBO glFramebufferRenderbuffer(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER GL_COLOR_ATTACHMENT0, // 2. color attachment point GL_RENDERBUFFER, // 3. rbo target: GL_RENDERBUFFER rboColorId); // 4. rbo ID // attach depthbuffer image to FBO glFramebufferRenderbuffer(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER GL_DEPTH_ATTACHMENT, // 2. depth attachment point GL_RENDERBUFFER, // 3. rbo target: GL_RENDERBUFFER rboDepthId); // 4. rbo ID // check FBO status GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status != GL_FRAMEBUFFER_COMPLETE) fboUsed = false;
It is important to know that glRenderbufferStorageMultisample() only enables MSAA rendering to FBO. However, you cannot directly use the result from MSAA FBO. If you need to transfer the result to a texture or other non-multisampled framebuffer, you have to convert (downsample) the result to single-sample image using glBlitFramebuffer().
void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, // source rectangle GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, // destination rect GLbitfield mask, GLenum filter)
glBlitFramebuffer() copies a rectangle of images from the source (GL_READ_BUFFER) to the destination framebuffer (GL_DRAW_BUFFER). The "mask" parameter is to specify which buffers are copied, GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT and/or GL_STENCIL_BUFFER_BIT. The last parameter, "filter" is to specify the interpolation mode if the source and destination rectangles are not same dimension. It is either GL_NEAREST or GL_LINEAR.
The following code is to transfer a multisampled image from a FBO to another non-multisampled FBO. Notice it requires an additional FBO to get the result of MSAA rendering. Please see fboMsaa.zip for details to perform render-to-texture with MSAA.
// copy rendered image from MSAA (multi-sample) to normal (single-sample) // NOTE: The multi samples at a pixel in read buffer will be converted // to a single sample at the target pixel in draw buffer. glBindFramebuffer(GL_READ_FRAMEBUFFER, fboMsaaId); // src FBO (multi-sample) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId); // dst FBO (single-sample) glBlitFramebuffer(0, 0, width, height, // src rect 0, 0, width, height, // dst rect GL_COLOR_BUFFER_BIT, // buffer mask GL_LINEAR); // scale filter
Checking FBO Status
Once attachable images (textures and renderbuffers) are attached to a FBO and before performing FBO operation, you must validate if the FBO status is complete or incomplete by using glCheckFramebufferStatus(). If the FBO is not complete, then any drawing and reading command (glBegin(), glCopyTexImage2D(), etc) will be failed.
GLenum glCheckFramebufferStatus(GLenum target)
glCheckFramebufferStatus() validates all its attached images and framebuffer parameters on the currently bound FBO. And, this function cannot be called within glBegin()/glEnd() pair. The target parameter should be GL_FRAMEBUFFER. It returns non-zero value after checking the FBO. If all requirements and rules are satisfied, then it returns GL_FRAMEBUFFER_COMPLETE. Otherwise, it returns a relevant error value, which tells what rule is violated.
The rules of FBO completeness are:
- The width and height of framebuffer-attachable image must be not zero.
- If an image is attached to a color attachment point, then the image must have a color-renderable internal format. (GL_RGBA, GL_DEPTH_COMPONENT, GL_LUMINANCE, etc)
- If an image is attached to GL_DEPTH_ATTACHMENT, then the image must have a depth-renderable internal format. (GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT24, etc)
- If an image is attached to GL_STENCIL_ATTACHMENT, then the image must have a stencil-renderable internal format. (GL_STENCIL_INDEX, GL_STENCIL_INDEX8, etc)
- FBO must have at least one image attached.
- All images attached a FBO must have the same width and height.
- All images attached the color attachment points must have the same internal format.
Note that even though all of the above conditions are satisfied, your OpenGL driver may not support some combinations of internal formats and parameters. If a particular implementation is not supported by OpenGL driver, then glCheckFramebufferStatus() returns GL_FRAMEBUFFER_UNSUPPORTED.
The sample code provides some utility functions to report the information of the current FBO; printFramebufferInfo() and checkFramebufferStatus().
Example: Render To Texture
Download the source and binary: fbo.zip (Updated: 2016-11-14)
Extras:
- Rendering to the depth buffer only: fboDepth.zip
- Rendering the outlines of an object using stencil buffer: fboStencil.zip
- Bliting between 2 FBOs using glBlitFramebuffer(): fboBlit.zip
- Rendering to texture with MSAA: fboMsaa.zip
Sometimes, you need to generate dynamic textures on the fly. The most common examples are generating mirroring/reflection effects, dynamic cube/environment maps and shadow maps. Dynamic texturing can be accomplished by rendering the scene to a texture. A traditional way of render-to-texture is to draw a scene to the framebuffer as normal, and then copy the framebuffer image to a texture by using glCopyTexSubImage2D().
Using FBO, we can render a scene directly onto a texture, so we don't have to use the window-system-provided framebuffer at all. Further more, we can eliminate an additional data copy (from framebuffer to texture).
This demo program performs render to texture operation with/without FBO, and compares the performance difference. Other than performance gain, there is another advantage of using FBO. If the texture resolution is larger than the size of the rendering window in traditional render-to-texture mode (without FBO), then the area out of the window region will be clipped. However, FBO does not suffer from this clipping problem. You can create a framebuffer-renderable image larger than the display window.
The following codes is to setup a FBO and framebuffer-attachable images before the rendering loop is started. Note that not only a texture image is attached to the FBO, but also, a renderbuffer image is attached to the depth attachment point of the FBO. We do not actually use this depth buffer, however, the FBO itself needs it for depth test. If we don't attach this depth renderable image to the FBO, then the rendering output will be corrupted because of missing depth test. If stencil test is also required during FBO rendering, then additional renderbuffer image should be attached to GL_STENCIL_ATTACHMENT.
... // create a texture object GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); // create a renderbuffer object to store depth info GLuint rboId; glGenRenderbuffers(1, &rboId); glBindRenderbuffer(GL_RENDERBUFFER, rboId); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, TEXTURE_WIDTH, TEXTURE_HEIGHT); glBindRenderbuffer(GL_RENDERBUFFER, 0); // create a framebuffer object GLuint fboId; glGenFramebuffers(1, &fboId); glBindFramebuffer(GL_FRAMEBUFFER, fboId); // attach the texture to FBO color attachment point glFramebufferTexture2D(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER GL_COLOR_ATTACHMENT0, // 2. attachment point GL_TEXTURE_2D, // 3. tex target: GL_TEXTURE_2D textureId, // 4. tex ID 0); // 5. mipmap level: 0(base) // attach the renderbuffer to depth attachment point glFramebufferRenderbuffer(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER GL_DEPTH_ATTACHMENT, // 2. attachment point GL_RENDERBUFFER, // 3. rbo target: GL_RENDERBUFFER rboId); // 4. rbo ID // check FBO status GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status != GL_FRAMEBUFFER_COMPLETE) fboUsed = false; // switch back to window-system-provided framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); ...
The rendering procedure of render-to-texture is almost same as normal drawing. We only need to switch the rendering destination from the window-system-provided to the non-displayable, application-created framebuffer (FBO).
... // set rendering destination to FBO glBindFramebuffer(GL_FRAMEBUFFER, fboId); // clear buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw a scene to a texture directly draw(); // unbind FBO glBindFramebuffer(GL_FRAMEBUFFER, 0); // trigger mipmaps generation explicitly // NOTE: If GL_GENERATE_MIPMAP is set to GL_TRUE, then glCopyTexSubImage2D() // triggers mipmap generation automatically. However, the texture attached // onto a FBO should generate mipmaps manually via glGenerateMipmap(). glBindTexture(GL_TEXTURE_2D, textureId); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); ...
Note that glGenerateMipma
=======================
=======================
=======================
OpenGL FBO 링크
http://dogfoottech.tistory.com/61
1.
http://wanochoi.com/?p=1019
2.
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/
3
FBO를 이용한 Render To Texture 구현
http://blog.daum.net/aero2k/53
4.
네이버 3D카페
http://cafe.naver.com/gld3d/181
5.
glPixelRead Example
http://www.lighthouse3d.com/tutorials/opengl-selection-tutorial/
6.
glPixelRead
https://www.khronos.org/opengles/sdk/docs/man3/html/glReadPixels.xhtml
출처: http://dogfoottech.tistory.com/61 [sweetzLab 기술블로그]
=======================
=======================
=======================
'프로그래밍 관련 > 3D,2D DRAW 관련' 카테고리의 다른 글
OpenGL Viewing - Viewing, Modeling, Projection, Viewport transformation (0) | 2017.08.18 |
---|---|
OpenGL 블렌딩 (0) | 2017.08.18 |
OpenGL MFC, WIN32 배경투명하게 transparent, glClearColor, Clear 하기 (0) | 2017.07.14 |
3D구현 - 2D 물체 겹침 표현하기 관련 (0) | 2017.07.12 |
OpenGL 스텐실 테스트, 그림판 지우기 Painter Eraser 구현 관련 (0) | 2017.07.12 |
댓글 영역