2016-08-03 11 views
0

ich für meine Kantenerkennungsalgorithmus zwei Postbearbeitungsschritte tun: 1. Kanten finden über Sobel-Kantenerkennungsalgorithmus 2. Dünne die Kanten über morphologische AusdünnungOpenGL/OpenTK - Multiple Framebuffer

Was Ich möchte erreichen, dass die gesamte Szene in einen separaten Framebuffer gerendert wird, die erzeugte Textur abgetastet wird, um alle Kanten zu finden und schließlich die neu erzeugte Textur wieder abzutasten, um die Kanten zu verdünnen.

Also nahm ich an, dass ich drei Framebuffer (eine für Kantenerkennung, eine für Ausdünnung und den Standard Framebuffer) benötigt, um diese Aufgabe zu erfüllen. Der erste zusätzliche Framebuffer verwendet drei Texturen, nämlich für Farbe, Normale und Tiefe. Der zweite zusätzliche Framebuffer sollte die erzeugten Bilder des ersten Framebuffers verwenden, um die Ausdünnung durchzuführen und sie erneut auszugeben.

Wenn ich zwei framebuffers (Standard fb und Kantenerkennung fb) verwenden, funktioniert alles gut. Aber sobald ich ein zusätzliches drittes fb hinzufüge, wird die Textur, die von diesem dritten Framebuffer erzeugt wird, nicht angezeigt. Stattdessen wird ein schwarzes Fenster angezeigt.

Also hier der Code für die Initialisierung des ersten Framebuffer ist:

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

Alles funktioniert gut, erscheinen keine Probleme. Der zweite Bildpuffer ist gleich geschaffen, mit der Ausnahme, dass ich nur eine Farbe Befestigung benötigen:

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

und kommt nun der Rendering-Teil: Zuerst hat ich den ersten Bildpuffer binden und die Fragment-Shader auszugeben Normale und Farbwerte auf die Verwendung zwei Aufsätze:

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

binden dann ich die zweite fb und die Texturen verwenden, die die vorherigen Bildpuffer erzeugt:

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

Und schließlich binde ich auf den Standardframebuffer wieder und die generierten Texturen auf eine einfache Quad ziehen:

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

Farbtextur So ausgibt, Tiefe Textur oder normale Textur von Framebuffer erzeugt ein großes bearbeitet, aber wenn ich Ausgang der Textur generiert von Framebuffer zwei, bekomme ich einen schwarzen Bildschirm. Ich habe es auch mit TextureUnit.Texture4 bei der Verwendung von edgeBuffer versucht, aber das funktioniert auch nicht.

Ist das überhaupt der richtige Ansatz, wenn ich 2 Nachbearbeitungsschritte machen möchte?

Antwort

0

Nun, die Antwort ist, die Szene auf das Quad zu rendern, obwohl es nicht das letzte Bild ist, das auf dem Display ausgegeben werden soll.

So werden die Schritte für multipe Nachbereitungen durchführen, sind:

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

So ist der obige Code korrekt ist, nur die Zeichnung auf dem Quad nach dem ersten Framebuffer (Post processing and resulting texture sehen) fehlt (nur falls jemand anderes das auch braucht).