OpenGL zu Bitmap rendern

    • VB.NET
    • .NET (FX) 4.5–4.8

      OpenGL zu Bitmap rendern

      Ich stand kürzlich vor dem Problem dass ich von meiner OpenGL Form einem "Screenshot" machen wollte und ich habe im Internet nichts wirklich brauchbares Gefunden, bis auf dass Man GL.ReadPixels verwenden kann.

      Also habe ich so lange hin und her gebastelt bis ich zu folgendem Ergebnis gekommen bin. Das möchte ich hier präsentieren damit du nicht so lange suchen und probieren musst wie ich.

      Start:
      Wir brauchen also eine OpenGL-Control GLMain und eine Picturebox PBScreenshot.
      Das OpenGL-Fenster muss funktionieren und alle entsprechenden Imports müssen vorhanden sein.

      Zunächst die Paint-Routine unserer OpenGL-Form in meinem Fall GlMain.Paint.

      VB.NET-Quellcode

      1. Private Sub GlMain_Paint(sender As Object, e As PaintEventArgs) Handles GlMain.Paint
      2. '... hier steht dein Code der in jedem Frame für das Zeichen des Bildes verwendet wird
      3. End Sub


      Wie die Objekte gezeichnet werden ist für den Screenshot irrelevant. Die Funktion kann am einfachsten getestet werden indem man den Hintergrun zum Beispiel Rot färbt.

      VB.NET-Quellcode

      1. GL.ClearColor(Color.Red)





      Der eigentliche "Screenshot":

      Wichtig! Diese Einträge müssen ganz ans Ende der Paint-Routine damit auch alles in der Aufnahme enthalten ist!

      Wir brauchen zunächst ein Bitmap Objekt der selben Größe wie das GL-Control.

      VB.NET-Quellcode

      1. Dim bmp As New Bitmap(GlMain.ClientSize.Width, GlMain.ClientSize.Height)


      Dann brauchen wir ein Objekt das die BitmapData an sich enthält in der Größe des GL-Control und im Pixelformat das wir gerne haben möchten.

      VB.NET-Quellcode

      1. Dim Data As Imaging.BitmapData = bmp.LockBits(GlMain.ClientRectangle, Imaging.ImageLockMode.WriteOnly, Imaging.PixelFormat.Format24bppRgb)


      Jetzt kommt schon das ReadPixel startend in der obenren linken Ecke bei Punkt(0,0) wieder in der Größe des GL-Controls.
      Dazu wird in OpenGL das Pixelformat BGR verwendet, UnsignedByte erlären sich von selbst und am Schluss Ein Pointer auf das Objekt Data in das wir die Pixelinformationen speichern wollen.

      VB.NET-Quellcode

      1. GL.ReadPixels(0, 0, GlMain.ClientSize.Width, GlMain.ClientSize.Height, PixelFormat.Bgr, PixelType.UnsignedByte, Data.Scan0)


      Nun einfach die Bits aus dem Datenobjekt ziehen.

      VB.NET-Quellcode

      1. bmp.UnlockBits(Data)


      Damit das Bild nicht auf dem Kopf steht müssen wir es ein Mal entlang der V-Achse (hier Y) flippen.
      (Wer einen Spiegelungseffekt erreichen will kann das Bild hier schon entlang der U-Achse (hier X) Spiegeln)

      VB.NET-Quellcode

      1. bmp.RotateFlip(RotateFlipType.RotateNoneFlipY)


      Und schon ist unsere Bitmap fertig um verwendet zu werden, hier in einer einfachen Picturebox.

      VB.NET-Quellcode

      1. PBTexture.Image = bmp


      Da der "Screenshot" hier ja schon aufgenommen wurde kann innerhalb dieses Frames die Scene noch verändert werden, was dann keinen Einfluss auf das aufgenommene Bild hat.




      Und jetzt nochmal alles zusammengefasst:

      VB.NET-Quellcode

      1. Private Sub GlMain_Paint(sender As Object, e As PaintEventArgs) Handles GlMain.Paint
      2. '... Code für das Zeichen der 3D-Objekte
      3. Dim bmp As New Bitmap(GlMain.ClientSize.Width, GlMain.ClientSize.Height)
      4. Dim Data As Imaging.BitmapData = bmp.LockBits(GlMain.ClientRectangle, Imaging.ImageLockMode.WriteOnly, Imaging.PixelFormat.Format24bppRgb)
      5. GL.ReadPixels(0, 0, GlMain.ClientSize.Width, GlMain.ClientSize.Height, PixelFormat.Bgr, PixelType.UnsignedByte, Data.Scan0)
      6. bmp.UnlockBits(Data)
      7. bmp.RotateFlip(RotateFlipType.RotateNoneFlipY)
      8. PBTexture.Image = bmp
      9. End Sub




      Und so sieht das dann bei mir aus mit einem einfachen Gitter:


      Jetzt bin ich gespannt auf eure Fragen und Anregungen :)

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()