title: COLOR_ATTACHMENT's - How to render to multiple textures as color attachments inside a Framebuffer Object?
body: <p>I am trying to render to multiple textures as <code>COLOR_ATTACHMENT</code>s without success. All I get from displaying them is a black screen (with a red clear fill) meaning my texture is read but is 'empty'.</p>
  
  <p>My pseudo code is : attach 3 textures to an FBO with texture indexes 1, 2 and 3 and color attachments 0, 1 and 2 respectively. As a test case, I tried to render my scene to the 3 color attachments so they are supposed to hold the same exact data. Then read either of those textures at shader pass 2 (with a 2Dsampler) and display them on a quad.</p>
  
  <p>My original intent for those 2 extra color attachments is to use them as random data buffers using the GPU ping-pong technique. So far I just use them as texture clones for testing purpose.</p>
  
  <p>When trying to read from <code>GL_TEXTURE1</code> (<code>COLOR_ATTACHMENT0</code>) things go fine but not from the other 2 (black screen).</p>
  
  <p>The code :</p>
  
  <pre><code>// Texture indices - inside a 'myGlut' struct
  GLenum skyboxTextureIndex = GL_TEXTURE0;
  GLenum colorTextureIndex = GL_TEXTURE1;
  unsigned int colorTextureIndexInt = 1;
  GLenum depthTexture1Index = GL_TEXTURE2;
  unsigned int depthTexture1IndexInt = 2;
  GLenum depthTexture2Index = GL_TEXTURE3;
  unsigned int depthTexture2IndexInt = 3;
  
  //** Below is inside 'main()' **//
  
  // Create frame buffer
  myGlut.frameBuffer = glutils::createFrameBuffer();
  
  // Create texture to hold color buffer
  glActiveTexture(myGlut.colorTextureIndex);
  glBindTexture(GL_TEXTURE_2D, myGlut.colorTexture);
  myGlut.colorTexture = glutils::createTextureAttachment(myGlut.camera -&gt; getRenderResizedWidthPx(), myGlut.camera -&gt; getRenderResizedHeightPx());
  glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT0, myGlut.colorTexture);
  
  // Create 1st texture to hold depth buffer wannabe :&gt;
  glActiveTexture(myGlut.depthTexture1Index);
  glBindTexture(GL_TEXTURE_2D, myGlut.depthTexture1);
  myGlut.depthTexture1 = glutils::createTextureAttachment(myGlut.camera -&gt; getRenderResizedWidthPx(), myGlut.camera -&gt; getRenderResizedHeightPx());
  glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT1, myGlut.depthTexture1);
  
  // Create 2nd texture to hold depth buffer wannabe :&gt;
  glActiveTexture(myGlut.depthTexture2Index);
  glBindTexture(GL_TEXTURE_2D, myGlut.depthTexture2);
  myGlut.depthTexture2 = glutils::createTextureAttachment(myGlut.camera -&gt; getRenderResizedWidthPx(), myGlut.camera -&gt; getRenderResizedHeightPx());
  glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT2, myGlut.depthTexture2);
  
  // Check FBO
  if (!glutils::checkFBOStatus()) return 0;
  </code></pre>
  
  <p>With <code>glutils::</code> functions</p>
  
  <pre><code>// Clear screen
  void glutils::clearScreen (float r, float g, float b, float a) {
      glClearColor(r, g, b, a);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  }
  
  // Bind select framebuffer
  void glutils::bindFrameBuffer(int frameBuffer, int width, int height) {
      glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
      glViewport(0, 0, width, height);
  }
  
  // Create frame buffer
  GLuint glutils::createFrameBuffer() {
      GLuint frameBuffer;
      glGenFramebuffers(1, &amp;frameBuffer);
      glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
      return frameBuffer;
  }
  
  // Create a texture attachment
  GLuint glutils::createTextureAttachment(int width, int height) {
      GLuint texture;
      glGenTextures(1, &amp;texture);
      glBindTexture(GL_TEXTURE_2D, texture);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      return texture;
  }
  
  // Bind a texture attachment to select framebuffer
  void glutils::bindTextureAttachment (GLenum colorAttachment, GLuint texture) {
      glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachment, GL_TEXTURE_2D, texture, 0);
  }
  
  // Check current frame buffer status
  bool glutils::checkFBOStatus () {
      if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
          std::cerr &lt;&lt; "##### ERROR : Frambuffer not complete... #####" &lt;&lt; std::endl;
          return false;
      }
      else return true;
  }
  </code></pre>
  
  <p>Then the glut display func :</p>
  
  <pre><code>// Clear screen
  glutils::clearScreen(1.f, 0.f, 0.f, 1.f);
  
  // Bind to custom framebuffer
  glutils::bindFrameBuffer(myGlut.frameBuffer, myGlut.camera -&gt; getScreenWidthPx(), myGlut.camera -&gt; getScreenHeightPx());
  
  // Set draw context
  GLuint drawBuffers[2];
  if (myGlut.depthTextureSwitch) {    drawBuffers[0] = GL_COLOR_ATTACHMENT0;
                                      drawBuffers[1] = GL_COLOR_ATTACHMENT2;
  } else {                            drawBuffers[0] = GL_COLOR_ATTACHMENT0;
                                      drawBuffers[1] = GL_COLOR_ATTACHMENT1;
  } glDrawBuffers(2, drawBuffers);
  
  // Use main program and bind uniforms
  glUseProgram(myGlut.theProgram);
  myGlut.refreshUniformsPass_1();
  
  // Draw quad to sample
  glutils::drawQuad();
  
  // Unbind custom framebuffer -&gt; use default (screen)
  glutils::unbindCurrentFrameBuffer(myGlut.camera -&gt; getScreenWidthPx(), myGlut.camera -&gt; getScreenHeightPx());
  
  // Use secondary program and bind uniforms
  glUseProgram(myGlut.theProgram2);
  myGlut.refreshUniformsPass_2();
  
  // Draw quad to apply texture to
  glutils::drawQuad();
  
  // Switch
  myGlut.depthTextureSwitch = !myGlut.depthTextureSwitch;
  
  // Display &amp; loop
  glutSwapBuffers();
  glutPostRedisplay();
  </code></pre>
  
  <p>Relevant uniform bindings -> pass 1</p>
  
  <pre><code>glUniform1i(glGetUniformLocation(myGlut.theProgram, "depthTexture"), !myGlut.depthTextureSwitch ? myGlut.depthTexture2IndexInt : myGlut.depthTexture1IndexInt);
  </code></pre>
  
  <p>Relevant shader code -> Pass 1</p>
  
  <pre><code>layout (location = 0) out vec4 outputColor;
  layout (location = 1) out vec4 outputDepth1;
  layout (location = 2) out vec4 outputDepth2;
  uniform sampler2D depthTexture;
  
  void main() {
      // ...
      outputColor = someColor;
      outputDepth1 = someColor;
      outputDepth2 = someColor;
  }
  </code></pre>
  
  <p>Relevant uniform bindings -> pass 2</p>
  
  <pre><code>glUniform1i(glGetUniformLocation(myGlut.theProgram2, "texFramebuffer"), myGlut.depthTextureSwitch ? myGlut.depthTexture1IndexInt : myGlut.depthTexture2IndexInt);
  </code></pre>
  
  <p>With relevant shader code -> pass 2</p>
  
  <pre><code>uniform sampler2D texFramebuffer;
  out vec4 outputColor;
  // ...
  void main() {
      outputColor = texture(texFramebuffer, vec2(gl_FragCoord.x / screenWidthPx * resRatio, gl_FragCoord.y / screenHeightPx * resRatio));
  }
  </code></pre>
  
  <p>In a nutshell : my <code>GL_TEXTURE0</code> holds the scene while <code>GL_TEXTURE1</code> and <code>GL_TEXTURE2</code> are black. Why ?</p>