Search code examples
c#openglopentk

OpenGL - Access RGB pixel data in a stored Texture2D


I've rendered the scene as solid colours to an FBO and stored it in a texture 2D, shown below.

enter image description here

Now I need to access the RGB values of a particular pixel co-ordinate, or texture-co-ordinate, either is helpful.

I understand I need to use GL.ReadPixels but have only succeeded creating a bitmap first and doing this every frame creates performance issues.

GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, FBO);
GL.Ext.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, Texture.GetTextureID("FBOtexture"), 0);

Bitmap b = new Bitmap(Width, Height);
var bits = b.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GL.ReadPixels(0, 0, Width, Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);
GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
b.UnlockBits(bits);

How can I access the data directly?


Solution

  • For now, this is working

    int pixelData = 0;
    
    GL.ReadPixels (fboWidth / 2, fboHeight / 2, 1, 1, OpenTK.Graphics.OpenGL.PixelFormat.Rgb, PixelType.UnsignedByte, ref pixelData);
    
    int red = Color.FromArgb(pixelData).R;
    int green = Color.FromArgb(pixelData).G;
    int blue = Color.FromArgb(pixelData).B;
    

    But there are notable drawbacks.

    As described in the PBO article linked by j-p, glReadPixels() blocks the pipeline and waits until all pixel data is transferred, only then returning control to the application. In my program, and on my machine, that stall is noticeable.

    The long term solution seems to be the Pixel Buffer Object which reduces the overhead by providing asynchronous data transfer between GL and the client. I'll amend this answer when I have something to show.