2016-08-03 67 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

所以上面的代碼是正確的,只有圖紙到第一幀緩衝後的四缺失(只以防其他人也需要這個)。