How to save an OpenGL rendering to disk - jeske/opentk GitHub Wiki

You can use the following code to read back an OpenGL rendering to a System.Drawing.Bitmap. You can then use the Save method to save this to disk.

Hints:

  • Don't forget to call Dispose on the returned Bitmap once you are done with it. Otherwise, you will run out of memory rapidly. If you wish to save a video, rather than a single screenshot, consider modifying this method to reuse the same Bitmap.
  • Call GrabScreenshot from your main rendering thread, i.e. the thread which contains your GraphicsContext.
  • Make sure you have bound the correct framebuffer object before calling GrabScreenshot.
  • You can improve performance significantly by removing the bmp.RotateFlip call and saving the resulting image as a BMP rather than a PNG file. This is especially important if you wish to record a video - it is the difference between a real-time recording and a slideshow.
  • This code can record 720p/30Hz video relatively easily, given suitable hardware and a little optimization (as outlined above). There are many programs that can encode a stream of consecutive BMP files into a high definition video.
using System;
using System.Drawing;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
 
static class GraphicsHelpers {

        // Returns a System.Drawing.Bitmap with the contents of the current framebuffer
        public static Bitmap GrabScreenshot() {
        
            if (GraphicsContext.CurrentContext == null) {
                throw new GraphicsContextMissingException;
            }
 
            Bitmap bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
            System.Drawing.Imaging.BitmapData data =
                bmp.LockBits(this.ClientRectangle, 
                             System.Drawing.Imaging.ImageLockMode.WriteOnly,
                             System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            GL.ReadPixels(0, 0, this.ClientSize.Width, this.ClientSize.Height, 
                          PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
            bmp.UnlockBits(data);
 
            bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
            return bmp;
       }
 }