2016-08-03 44 views
0

我想要做我的边缘检测算法两位内线的处理步骤: 1.找到通过的Sobel边缘检测算法 2.薄边通过形态学细化边缘的OpenGL/OpenTK - 多帧缓存

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

因此,我假设我需要三个帧缓冲区(一个用于边缘检测,一个用于细化和默认帧缓冲区)来实现此任务。 第一个附加帧缓存使用三种纹理,即颜色,法线和深度。第二个附加帧缓冲区应使用第一帧缓冲区的生成图像进行细化并再次输出。

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

因此,这里是第一帧缓冲区的初始化代码:

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); 

所以输出颜色纹理,深度纹理或帧缓冲一个伟大的工程产生的法线贴图,但如果我输出的质感由framebuffer生成两个,我得到一个黑屏。我在使用edgeBuffer时也尝试过使用TextureUnit.Texture4,但这也不起作用。

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

回答

0

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

所以对于执行multipe后期处理步骤是:

-> 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

所以上面的代码是正确的,只有图纸到第一帧缓冲后的四缺失(只以防其他人也需要这个)。