【问题标题】:OpenGL/OpenTK - Multiple FramebuffersOpenGL/OpenTK - 多个帧缓冲区
【发布时间】:2016-08-04 04:09:13
【问题描述】:

我想为我的边缘检测算法执行两个后处理步骤: 1.通过Sobel-Edge检测算法找到边缘 2. 通过形态细化来细化边缘

所以我想要实现的是将整个场景渲染到一个单独的帧缓冲区中,对创建的纹理进行采样以找到所有边缘,最后再次对新生成的纹理进行采样以细化边缘。

所以我假设我需要三个帧缓冲区(一个用于边缘检测,一个用于细化和默认帧缓冲区)来完成这项任务。 第一个额外的帧缓冲区使用三个纹理,即颜色、法线和深度。第二个附加帧缓冲区应该使用第一个帧缓冲区生成的图像进行细化并再次输出。

如果我使用两个帧缓冲区(默认 fb 和边缘检测 fb),一切正常。但是一旦我添加了一个额外的第三个 fb,这个第三个帧缓冲区生成的纹理就不会显示出来。而是显示一个黑色窗口。

所以这里是第一个framebuffer的初始化代码:

private void GenerateFramebuffer()
    {
        //Generate framebuffer
        framebuffer = GL.GenFramebuffer();
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebuffer);

        // create a RGBA color texture
        GL.GenTextures(1, out textureColorBuffer);
        GL.BindTexture(TextureTarget.Texture2D, textureColorBuffer);
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
                            glControl1.Width, glControl1.Height,
                            0, (PixelFormat)PixelInternalFormat.Rgba, PixelType.UnsignedByte,
                            IntPtr.Zero);

        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Linear);
        GL.BindTexture(TextureTarget.Texture2D, 0);

        // create a RGBA color texture for normals
        ... generated like texture above

        // create a depth texture
        ... generated like texture above

        ////Create color attachment texture
        GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, textureColorBuffer, 0);
        GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment1, normalBuffer, 0);
        GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, depthBuffer, 0);

        DrawBuffersEnum[] bufs = new DrawBuffersEnum[2] { (DrawBuffersEnum)FramebufferAttachment.ColorAttachment0, (DrawBuffersEnum)FramebufferAttachment.ColorAttachment1 };
        GL.DrawBuffers(bufs.Length, bufs);

        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
    }

一切正常,没有出现任何问题。第二个帧缓冲区是同样创建的,除了我只需要一个颜色附件:

  private void GenerateFramebuffer2()
    {
        //Generate framebuffer
        framebuffer2 = GL.GenFramebuffer();
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebuffer2);

        // create a RGBA color texture
        GL.GenTextures(1, out edgeBuffer);
        GL.BindTexture(TextureTarget.Texture2D, edgeBuffer);
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
                            glControl1.Width, glControl1.Height,
                            0, (PixelFormat)PixelInternalFormat.Rgba, PixelType.UnsignedByte,
                            IntPtr.Zero);

        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Linear);
        GL.BindTexture(TextureTarget.Texture2D, 0);

        ////Create color attachment texture
        GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, edgeBuffer, 0);

        DrawBuffersEnum[] bufs = new DrawBuffersEnum[1] { (DrawBuffersEnum)FramebufferAttachment.ColorAttachment0};
        GL.DrawBuffers(bufs.Length, bufs);

        //No need for renderbuffer object since we don't need stencil buffer yet

        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
    }

现在是渲染部分: 首先我绑定第一个帧缓冲区并使用片段着色器将法线和颜色值输出到两个附件:

  GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebuffer);

  GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); // We're not using stencil buffer so why bother with clearing?            

  GL.Enable(EnableCap.DepthTest);
  Shader.Use();
  Model.Draw();
  GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);

然后我绑定第二个 fb 并使用前一个帧缓冲区生成的纹理:

 GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebuffer2);
 GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); // We're not using stencil buffer so why bother with clearing?  
 //Find edges and put them in separate texture (colors not needed here)
 edgeDetectionShader.Use();
 GL.ActiveTexture(TextureUnit.Texture1);
 GL.BindTexture(TextureTarget.Texture2D, normalBuffer);
 GL.Uniform1(GL.GetUniformLocation(edgeDetectionShader.program, "normalTexture"), 1);
 GL.ActiveTexture(TextureUnit.Texture2);
 GL.BindTexture(TextureTarget.Texture2D, depthBuffer);
 GL.Uniform1(GL.GetUniformLocation(edgeDetectionShader.program, "depthTexture"), 2);

最后我再次绑定到默认帧缓冲区并将生成的纹理绘制到一个简单的四边形上:

 /////////////////////////////////////////////////////
 // Bind to default framebuffer again and draw the 
 // quad plane with attched screen texture.
 // //////////////////////////////////////////////////
 GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
 // Clear all relevant buffers
 GL.ClearColor(1, 1, 1, 1); // Set clear color to white 
 GL.Clear(ClearBufferMask.ColorBufferBit);
 GL.Disable(EnableCap.DepthTest); // We don't care about depth information when rendering a single quad

 //Combine edges with color values
 finalImageProzessingShader.Use();
 GL.BindVertexArray(quadVAO);

 //Testing purpose: Send color texture to the shader
 GL.ActiveTexture(TextureUnit.Texture0);
 GL.BindTexture(TextureTarget.Texture2D, textureColorBuffer);
 GL.Uniform1(GL.GetUniformLocation(finalImageProzessingShader.program, "screenTexture"), 0);

 //Testing purpose: Send normal texture to the shader
 GL.ActiveTexture(TextureUnit.Texture1);
 GL.BindTexture(TextureTarget.Texture2D, normalBuffer);
 GL.Uniform1(GL.GetUniformLocation(finalImageProzessingShader.program, "normalTexture"), 1);

//Testing purpose: Send depth texture to the shader
GL.ActiveTexture(TextureUnit.Texture3);
GL.BindTexture(TextureTarget.Texture2D, depthBuffer);
GL.Uniform1(GL.GetUniformLocation(finalImageProzessingShader.program, "depthTexture"), 2);

//Send the texture of fb2 to shader (generates black screen)
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, edgeBuffer);
GL.Uniform1(GL.GetUniformLocation(finalImageProzessingShader.program, "depthTexture"), 3);

GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
GL.BindVertexArray(0);

所以输出帧缓冲区一生成的颜色纹理、深度纹理或法线纹理效果很好,但是如果我输出帧缓冲区二生成的纹理,我会得到一个黑屏。在使用 edgeBuffer 时,我也尝试使用 TextureUnit.Texture4,但这也不起作用。

当我想要进行 2 个后处理步骤时,这甚至是正确的方法吗?

【问题讨论】:

    标签: opengl opentk


    【解决方案1】:

    嗯,答案是将场景渲染到四边形,尽管它不是应该输出到显示器的最终图像。

    所以执行多重后期处理的步骤是:

    -> Bind 1st render texture
    -> Draw scene
    
    -> Bind 2nd render texture
    -> Feed 1st render texture to a shader and draw quad
    
    -> Bind 1st render texture
    -> Feed 2nd render texture to another shader and draw quad
    
    -> Bind 2nd render texture
    -> Feed 1st render texture to a third shader and draw quad
    
    ...
    -> Unbind
    -> Draw quad
    

    (见Post processing and resulting texture

    所以上面的代码是正确的,只有在第一个帧缓冲区之后绘制到四边形的东西丢失了(以防万一其他人也需要这个)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-26
      • 1970-01-01
      • 2012-07-26
      • 2013-12-19
      • 2012-03-13
      • 2013-01-30
      • 1970-01-01
      • 2012-12-24
      相关资源
      最近更新 更多