воскресенье, 22 января 2012 г.

Рендер в текстуру на основе opengl fbo

Разнообразие вендоров железа "обогатило" в прекрасном смысле этого слова рендеринг в текстуру. Какая только экзотика не была ( p-buffer ). На данный момент есть вменяемый вариант RTT через расширение EXT_framebuffer_object.  Вся идея данного расширения сводится к добавлению нового объекта FBO ( frame buffer object ). К этому объекту можно сделать привязку различных объектов, будь то буфер цвета, глубины, трафарет или RBO (renderbuffer object).

Приступим к написанию кода

Для начала проверяем поддержку данного расширения 

  1. - (BOOL) initFBO  
  2. {  
  3.     // check extension  
  4.     const GLubyte* extensions = glGetString ( GL_EXTENSIONS );  
  5.     if ( extensions )  
  6.     {     
  7.       if(gluCheckExtension((GLubyte*)("GL_EXT_framebuffer_object"), extensions))  
  8.         return YES;  
  9.     }  
  10.     return NO;  
  11. }  

Создаем текстуру в которую будем рендерить

  1. GLuint textureId      
  2. glGenTextures ( 1, &textureId );  
  3. glBindTexture ( GL_TEXTURE_2D, textureId );  
  4. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );  
  5. glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );  
  6. glTexImage2D ( GL_TEXTURE_2D, 0, 4, TextureWidth, TextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );  

Создаем FBO объект

  1. GLuint frameBufferId;  
  2.   
  3. glGenFramebuffersEXT ( 1, &frameBufferId ); // 0 - это главный буфер, очевидно что id > 0  
  4. glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, frameBufferId );  
  5. glFramebufferTexture2DEXT ( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,  
  6.  GL_TEXTURE_2D, textureId, 0 ); //привязываем тексту к фрэймбуфер  
  7.   
  8. // проверяем буфер ( код ниже )  
  9. // ...  
  10.   
  11. glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, 0 ); // восстанавливаем главный буфер  

Проверка буфера

  1. GLenum status = glCheckFramebufferStatusEXT ( GL_FRAMEBUFFER_EXT );  
  2. if ( status != GL_FRAMEBUFFER_COMPLETE_EXT )  
  3. {  
  4.     switch ( status )  
  5.     {  
  6.         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:  
  7.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT");  
  8.             break;  
  9.         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:  
  10.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT");  
  11.             break;  
  12.         case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:  
  13.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");  
  14.             break;  
  15.         case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:  
  16.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");  
  17.             break;  
  18.         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:  
  19.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");                            
  20.             break;  
  21.         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:  
  22.             NSLog(@"FBO GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");  
  23.             break;  
  24.         case GL_FRAMEBUFFER_UNSUPPORTED_EXT:  
  25.             NSLog(@"FBO GL_FRAMEBUFFER_UNSUPPORTED_EXT");  
  26.             break;  
  27.         default:  
  28.             NSLog(@"FBO Unknown error");  
  29.               
  30.             break;  
  31.     }  
  32.         
  33.     return NO;  
  34. }  

Разумеется можно еще добавить создание буфера глубины или трафарета, сделать привязку к данному FBO. Если все успешно создалось то можно рендерить в текстуру.

  1. glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, frameBufferId ); // выставляем нужный нам буфер  
  2.   
  3. glClearColor ( 0.0f, 0.0f, 1.0f, 1.0f );   
  4. glClear ( GL_COLOR_BUFFER_BIT );  
  5.   
  6. // что-то рисуем в текстуру ( корректируем все матрицы )
  7. // ...  
  8.   
  9. glBindFramebufferEXT ( GL_FRAMEBUFFER_EXT, 0 );      // восстанавливаем буфера окна  

Теперь у нас в текстуре которая была привязана к данному framebuffer объекту находится то что нам нужно. Можем с ней работать как с обычной текстурой. Отрисовать всю сцену в текстуру и применить эфффект блюра.  И конечно не забывайте удалять текстуры и буфера ;-)

Example OpenGL FBO (github) готовый пример показывает наглядно как с этим работать


1 комментарий:

Анонимный комментирует...

Спасибо! А можно ли рендерить из текстуры в текстуру, не выводя на экран?