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?