多种渲染目标:MRT - MartinRGB/GLES30_ProgrammingGuide_NDK GitHub Wiki

多重渲染目标

MRT 允许应用一次渲染到多个 颜色缓冲区,应用到高级渲染算法中,例如延迟着色和快速环境这比估算。

方法:

1.glGenFramebuffers 和 glBindFramebuffer 初始化 FBO

2.glGenTextures 和 glBindTexure 初始化纹理

3.glFramebufferTexture2D 将纹理绑定到 FBO

int InitFBO ( ESContext *esContext )
{
   UserData *userData = esContext->userData;
   int i;
   GLint defaultFramebuffer = 0;
   const GLenum attachments[4] = 
   { 
      GL_COLOR_ATTACHMENT0,
      GL_COLOR_ATTACHMENT1,
      GL_COLOR_ATTACHMENT2,
      GL_COLOR_ATTACHMENT3 
   };

   glGetIntegerv ( GL_FRAMEBUFFER_BINDING, &defaultFramebuffer );

   // Setup fbo
   glGenFramebuffers ( 1, &userData->fbo );
   glBindFramebuffer ( GL_FRAMEBUFFER, userData->fbo );

   // Setup four output buffers and attach to fbo
   userData->textureHeight = userData->textureWidth = 400;
   glGenTextures ( 4, &userData->colorTexId[0] );
   for (i = 0; i < 4; ++i)
   {
      glBindTexture ( GL_TEXTURE_2D, userData->colorTexId[i] );

      glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 
                     userData->textureWidth, userData->textureHeight, 
                     0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );

      // Set the filtering mode
      glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
      glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

      glFramebufferTexture2D ( GL_DRAW_FRAMEBUFFER, attachments[i], 
                               GL_TEXTURE_2D, userData->colorTexId[i], 0 );
   }

   glDrawBuffers ( 4, attachments );

   if ( GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus ( GL_FRAMEBUFFER ) )
   {
      return FALSE;
   }

   // Restore the original framebuffer
   glBindFramebuffer ( GL_FRAMEBUFFER, defaultFramebuffer );

   return TRUE;
}

4.glDrawBuffers 为渲染指定颜色附着

///
// Copy MRT output buffers to screen
//
void BlitTextures ( ESContext *esContext )
{
   UserData *userData = esContext->userData;

   // set the fbo for reading
   glBindFramebuffer ( GL_READ_FRAMEBUFFER, userData->fbo );
 
   // Copy the output red buffer to lower left quadrant
   glReadBuffer ( GL_COLOR_ATTACHMENT0 );
   glBlitFramebuffer ( 0, 0, userData->textureWidth, userData->textureHeight,
                       0, 0, esContext->width/2, esContext->height/2, 
                       GL_COLOR_BUFFER_BIT, GL_LINEAR );

   // Copy the output green buffer to lower right quadrant
   glReadBuffer ( GL_COLOR_ATTACHMENT1 );
   glBlitFramebuffer ( 0, 0, userData->textureWidth, userData->textureHeight,
                       esContext->width/2, 0, esContext->width, esContext->height/2, 
                       GL_COLOR_BUFFER_BIT, GL_LINEAR );

   // Copy the output blue buffer to upper left quadrant
   glReadBuffer ( GL_COLOR_ATTACHMENT2 );
   glBlitFramebuffer ( 0, 0, userData->textureWidth, userData->textureHeight,
                       0, esContext->height/2, esContext->width/2, esContext->height, 
                       GL_COLOR_BUFFER_BIT, GL_LINEAR );

   // Copy the output gray buffer to upper right quadrant
   glReadBuffer ( GL_COLOR_ATTACHMENT3 );
   glBlitFramebuffer ( 0, 0, userData->textureWidth, userData->textureHeight,
                       esContext->width/2, esContext->height/2, esContext->width, esContext->height, 
                       GL_COLOR_BUFFER_BIT, GL_LINEAR );
}

///
// Render to MRTs and screen
//
void Draw ( ESContext *esContext )
{
   UserData *userData = esContext->userData;
   GLint defaultFramebuffer = 0;
   const GLenum attachments[4] = 
   { 
      GL_COLOR_ATTACHMENT0,
      GL_COLOR_ATTACHMENT1,
      GL_COLOR_ATTACHMENT2,
      GL_COLOR_ATTACHMENT3 
   };
   
   glGetIntegerv ( GL_FRAMEBUFFER_BINDING, &defaultFramebuffer );

   // FIRST: use MRTs to output four colors to four buffers
   glBindFramebuffer ( GL_FRAMEBUFFER, userData->fbo );
   glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
   glDrawBuffers ( 4, attachments );
   DrawGeometry ( esContext );

   // SECOND: copy the four output buffers into four window quadrants
   // with framebuffer blits

   // Restore the default framebuffer
   glBindFramebuffer ( GL_DRAW_FRAMEBUFFER, defaultFramebuffer );
   BlitTextures ( esContext );
}

5.fragment中声明和使用多个着色器输出 例如 fragData0 ~ fragData3 分别复制到绘图缓冲区 0 ~ 3

   char fShaderStr[] =
       "#version 300 es                                     \n"
       "precision mediump float;                            \n"
       "layout(location = 0) out vec4 fragData0;            \n"
       "layout(location = 1) out vec4 fragData1;            \n"
       "layout(location = 2) out vec4 fragData2;            \n"
       "layout(location = 3) out vec4 fragData3;            \n"
       "void main()                                         \n"
       "{                                                   \n"
       "  // first buffer will contain red color            \n"
       "  fragData0 = vec4 ( 1, 0, 0, 1 );                  \n"
       "                                                    \n"
       "  // second buffer will contain green color         \n"
       "  fragData1 = vec4 ( 0, 1, 0, 1 );                  \n"
       "                                                    \n"
       "  // third buffer will contain blue color           \n"
       "  fragData2 = vec4 ( 0, 0, 1, 1 );                  \n"
       "                                                    \n"
       "  // fourth buffer will contain gray color          \n"            
       "  fragData3 = vec4 ( 0.5, 0.5, 0.5, 1 );            \n"
       "}