首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >绘制到帧缓冲区,然后显示在屏幕上

绘制到帧缓冲区,然后显示在屏幕上
EN

Stack Overflow用户
提问于 2020-12-08 21:27:52
回答 1查看 421关注 0票数 0

我想在帧缓冲区中绘制多个图像,然后在屏幕上绘制帧缓冲区。我也想从帧缓冲区ReadPixels来存储磁盘上的图像。

是否有一些教程或示例如何在OpenTK中使用帧缓冲区。我找到了一个示例,但不在C# openTK https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/minimalfbo/minimalfbo.c

目前,我的代码使应用程序崩溃,并且ReadPixels返回一个空图像。

代码语言:javascript
运行
复制
namespace test
{
    class Class1
    {
        int FramebufferName = -1;
        int depthrenderbuffer;
        int fbo_width = 0;
        int fbo_height = 0;
        public bool createImage = false;

        DirectBitmap masterBitmap = null;
        object masterBitmapSync = new object();
        public int renderedTexture = 0;

        public override void OnRender()
        {
            //https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/minimalfbo/minimalfbo.c
            calculateMasterBitmapSize();

            #region init
            if (FramebufferName == -1)
            {
                //do this only once

                //Framebuffer
                GL.GenFramebuffers(1, out FramebufferName);
                GL.BindFramebuffer(FramebufferTarget.Framebuffer, FramebufferName);
                checkGlError();

                //Color renderbuffer.
                lock (masterBitmapSync)
                {
                    if (masterBitmap != null)
                        createTexture();
                }
                if (renderedTexture <= 0 || FramebufferName < 0)
                {
                    Console.WriteLine("ERROR:");
                }

                checkGlError();
                GL.BindTexture(TextureTarget.Texture2D, renderedTexture);
                checkGlError();
                //GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderedTexture);
                //checkGlError();

                /* Storage must be one of: */
                /* GL_RGBA4, GL_RGB565, GL_RGB5_A1, GL_DEPTH_COMPONENT16, GL_STENCIL_INDEX8. */
                //GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent16, fbo_width, fbo_height);
                //checkGlError();
                //GL.FramebufferRenderbuffer(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, renderedTexture);
                //checkGlError();

                /* Depth renderbuffer. */
                GL.GenRenderbuffers(1, out depthrenderbuffer);
                GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, depthrenderbuffer);
                GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent16, fbo_width, fbo_height);
                GL.FramebufferRenderbuffer(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, depthrenderbuffer);
                checkGlError();

                GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
                checkGlError();

                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, fbo_width, fbo_height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);

                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
                GL.FramebufferTexture2D(FramebufferTarget.DrawFramebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, renderedTexture, 0); //original texture 1280x720

                checkGlError();
                FramebufferErrorCode errorCode = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
                if (errorCode != FramebufferErrorCode.FramebufferComplete)
                {
                    if (errorCode == FramebufferErrorCode.FramebufferUnsupported)
                        Console.WriteLine("FramebufferUnsupported");
                    GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
                    GL.DeleteFramebuffers(1, ref FramebufferName);
                    GL.DeleteFramebuffers(1, ref depthrenderbuffer);
                    return;
                }
                checkGlError();
            }
            #endregion

            #region drawInFramebuffer
            checkGlError();
            lock (masterBitmapSync)
            {
                if (masterBitmap != null)
                    createTexture();
            }

            checkGlError();
            GL.BindTexture(TextureTarget.Texture2D, 0);
            GL.Enable(EnableCap.Texture2D);
            GL.BindFramebuffer(FramebufferTarget.Framebuffer, FramebufferName);
            checkGlError();

            //GL.ColorMask(true, true, true, true);
            GL.ClearColor(0, 0, 0, 0);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            checkGlError();

            GL.Enable(EnableCap.Texture2D);
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.BindTexture(TextureTarget.Texture2D, renderedTexture);
            checkGlError();

            GL.Begin(PrimitiveType.Quads);
            {
                GL.TexCoord2(0.0f, 0.0f); GL.Vertex2(LocalPoints[0].X, LocalPoints[0].Y);
                GL.TexCoord2(1.0f, 0.0f); GL.Vertex2(LocalPoints[1].X, LocalPoints[1].Y);
                GL.TexCoord2(1.0f, 1.0f); GL.Vertex2(LocalPoints[2].X, LocalPoints[2].Y);
                GL.TexCoord2(0.0f, 1.0f); GL.Vertex2(LocalPoints[3].X, LocalPoints[3].Y);
            }
            GL.End();
            GL.Disable(EnableCap.Texture2D);

            //TODO draw multipla images
            //loop over all images and calling OnRender2()

            if (createImage)
            {
                createImage = false;
                GPoint p = new GPoint(0, 0); //TODO get correct x,y
                using (Bitmap bitmap = new Bitmap(fbo_width, fbo_height))
                {
                    BitmapData bits = bitmap.LockBits(new Rectangle(0, 0, fbo_width, fbo_height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                    checkGlError();
                    GL.ReadPixels((int)p.X, (int)p.Y, fbo_width, fbo_height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);
                    checkGlError();
                    bitmap.UnlockBits(bits);
                    bitmap.RotateFlip(RotateFlipType.Rotate180FlipX);
                    bitmap.Save(@"c:\Downloads\aaa\ReadPixels_" + DateTime.Now.ToString("HHmmss_fff") + ".png", ImageFormat.Png);
                }
            }

            checkGlError();
            //does command in next line, draw framebuffer on the screen?
            GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); //would draw to the default framebuffer again, basically finishing the drawing to the other framebuffer(the backbuffer which will be brought to front by SwapBuffers)
            checkGlError();
            #endregion
        }

        private void calculateMasterBitmapSize()
        {
            //for test example
            fbo_width = 256;
            fbo_height = 256 * 2;

            DirectBitmap newBitmap = new DirectBitmap(fbo_width, fbo_height);
            newBitmap.Bitmap.MakeTransparent();
            setBitmap(newBitmap);
        }

        public void setBitmap(DirectBitmap bmp)
        {
            lock (masterBitmapSync)
            {
                if (masterBitmap != null)
                    masterBitmap.Dispose();
                masterBitmap = bmp;
                if (masterBitmap == null)
                    deleteTexture();
            }
        }

        void deleteTexture()
        {
            if (renderedTexture > 0)
            {
                GL.DeleteTexture(renderedTexture);
                renderedTexture = 0;
            }
        }

        public void createTexture()
        {
            if (masterBitmap == null)
                return;

            int t = GL.GenTexture();
            GL.BindTexture(TextureTarget.Texture2D, t);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, masterBitmap.Width, masterBitmap.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);

            Rectangle rect = new Rectangle(0, 0, masterBitmap.Width, masterBitmap.Height);
            System.Drawing.Imaging.BitmapData data = masterBitmap.Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            GL.BindTexture(TextureTarget.Texture2D, t);
            GL.TexSubImage2D(TextureTarget.Texture2D, 0, rect.X, rect.Y, rect.Width, rect.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);

            masterBitmap.Bitmap.UnlockBits(data);
            masterBitmap.Dispose();
            masterBitmap = null;

            if (renderedTexture > 0)
                GL.DeleteTexture(renderedTexture);
            renderedTexture = t;
        }

        private void checkGlError()
        {
            ErrorCode errorCode = GL.GetError();
            if (errorCode != ErrorCode.NoError)
            {
                Console.WriteLine("ERROR: " + errorCode);
            }
        }

        public void OnRender2()
        {
            /*
            //this is example only
            lock (bitmapSync)
            {
                if (bitmap != null)
                    createTexture();
            }

            GL.Enable(EnableCap.Texture2D);
            GL.BindTexture(TextureTarget.Texture2D, texture);

            GL.Begin(PrimitiveType.Quads);
            {
                GL.TexCoord4(texCoords[0]); GL.Vertex4(LocalPoints[0].X, LocalPoints[0].Y, 1, 1); //UL
                GL.TexCoord4(texCoords[1]); GL.Vertex4(LocalPoints[1].X, LocalPoints[1].Y, 1, 1); //UR
                GL.TexCoord4(texCoords[2]); GL.Vertex4(LocalPoints[2].X, LocalPoints[2].Y, 1, 1); //LR
                GL.TexCoord4(texCoords[3]); GL.Vertex4(LocalPoints[3].X, LocalPoints[3].Y, 1, 1); //LL
            }

            GL.End();
            GL.Disable(EnableCap.Texture2D);
            */
        }
    }
}
EN

回答 1

Stack Overflow用户

发布于 2020-12-09 19:04:39

“帧缓冲区”通常是指图形设备上用于最终输出到屏幕的内存。这通常很难从c#访问。

如果您只是想合并多个图像,并且没有任何严格的性能要求,那么使用常规缓冲区进行合并,然后将此缓冲区绘制到屏幕上会简单得多。传统的做法是使用GDI图形对象进行绘制。

使用GDI和winforms的示例

代码语言:javascript
运行
复制
public class BitmapPaint : Control
{
    private Bitmap buffer;

    public BitmapPaint()
    {
        // Find out how large you want the output image to be
        // This example does not handle disposal or resizing etc
        buffer = new Bitmap(this.Width, this.Height);
    }

    public void Compose(IEnumerable<Bitmap> images)
    {
        using (var g = Graphics.FromImage(buffer))
        {
            foreach (var img in images)
            {
                // Adjust position etc if you need to
                g.DrawImageUnscaled(img, 0, 0);
            }
        }
        buffer.Save(@"c:\myFilename.bmp");
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        // Draw the buffer to the screen
        e.Graphics.DrawImageUnscaled(buffer, 0, 0);
    }
}

如果你想要更高的性能,可能更合适的是寻找像2D游戏引擎这样的东西,它可以管理blitting和更内部的东西。执行低级缓冲区操作不太适合.Net,因为它通常涉及原始指针和资源管理,而这些通常更容易在C/C++中进行管理。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65199847

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档