我想为边缘检测算法做两个后处理步骤: 1.通过Sobel-Edge检测算法查找边缘 2.通过形态细化使边缘变薄
所以我想要实现的是将整个场景渲染成一个单独的帧缓冲区,对创建的纹理进行采样以找到所有边缘,最后再次采样新生成的纹理以使边缘变细。
所以我假设我需要三个帧缓冲区(一个用于边缘检测,一个用于细化和默认帧缓冲)来完成此任务。 第一个附加帧缓冲使用三种纹理,即颜色,法线和深度。第二个额外的帧缓冲区应该使用第一个帧缓冲区生成的图像进行细化并再次输出。
如果我使用两个帧缓冲区(默认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);
因此输出由帧缓冲区生成的颜色纹理,深度纹理或普通纹理效果很好,但是如果我输出帧缓冲区2生成的纹理,我会得到一个黑屏。我在使用edgeBuffer时也尝试使用TextureUnit.Texture4,但这也不起作用。
当我想做2个后处理步骤时,这是否是正确的方法?
答案 0 :(得分:0)
嗯,答案是将场景渲染到四边形,尽管它不是应该输出到显示器的最终图像。
执行多重后期处理的步骤如下:
-> 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)
所以上面的代码是正确的,只有第一个帧缓冲区丢失后的四边形图(以防万一其他人也需要它)。