簡體   English   中英

如何將 OpenGL 渲染保存到磁盤

[英]How to save an OpenGL rendering to disk

我正在使用這個庫來呈現 STL:

在此處輸入圖像描述

我們如何將這個 STL 轉換成 BITMAP 或 IMAGE?

這個方法負責生成STL:

private void ReadSelectedFile(string fileName)
{
    STLReader stlReader = new STLReader(fileName);
    TriangleMesh[] meshArray = stlReader.ReadFile();
    modelVAO = new Batu_GL.VAO_TRIANGLES();
    modelVAO.parameterArray = STLExport.Get_Mesh_Vertices(meshArray);
    modelVAO.normalArray = STLExport.Get_Mesh_Normals(meshArray);
    modelVAO.color = Color.Crimson;

    minPos = stlReader.GetMinMeshPosition(meshArray);
    maxPos = stlReader.GetMaxMeshPosition(meshArray);
    orb.Reset_Orientation();
    orb.Reset_Pan();
    orb.Reset_Scale();

    if (stlReader.Get_Process_Error())
    { 
        modelVAO = null;
        /* if there is an error, deinitialize the gl monitor to clear the screen */
        Batu_GL.Configure(GL_Monitor, Batu_GL.Ortho_Mode.CENTER);
        GL_Monitor.SwapBuffers();
    }
}

如何生成圖像/位圖並保存?

我偶然發現了這個,特別是這個方法:

// 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;
}

但是,我遇到了這個問題:

System.Runtime.InteropServices.ExternalException
  HResult=0x80004005
  Message=A generic error occurred in GDI+.
  Source=System.Drawing
  StackTrace:
   at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
   at System.Drawing.Image.Save(String filename, ImageFormat format)
   at System.Drawing.Image.Save(String filename)
   at STLViewer.AppMainForm.ReadSelectedFile(String fileName) in C:\Users\alexg\Source\Repos\STL-Viewer\STL-Viewer\AppMainForm.cs:line 152
   at STLViewer.AppMainForm.FileMenuImportBt_Click(Object sender, EventArgs e) in C:\Users\alexg\Source\Repos\STL-Viewer\STL-Viewer\AppMainForm.cs:line 162
   at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key, EventArgs e)
   at System.Windows.Forms.ToolStripMenuItem.OnClick(EventArgs e)
   at System.Windows.Forms.ToolStripItem.HandleClick(EventArgs e)
   at System.Windows.Forms.ToolStripItem.HandleMouseUp(MouseEventArgs e)
   at System.Windows.Forms.ToolStripItem.FireEventInteractive(EventArgs e, ToolStripItemEventType met)
   at System.Windows.Forms.ToolStripItem.FireEvent(EventArgs e, ToolStripItemEventType met)
   at System.Windows.Forms.ToolStrip.OnMouseUp(MouseEventArgs mea)
   at System.Windows.Forms.ToolStripDropDown.OnMouseUp(MouseEventArgs mea)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   at System.Windows.Forms.ToolStrip.WndProc(Message& m)
   at System.Windows.Forms.ToolStripDropDown.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at STLViewer.Program.Main() in C:\Users\alexg\Source\Repos\STL-Viewer\STL-Viewer\Program.cs:line 19

好的,我剛剛搞定了這個小的 C++/OpenGL/VCL 示例:

void gl_save_bmp(AnsiString name,int xs,int ys)
    {
    int hnd;
    // header extracted from 24bit uncompressed BMP image
    DWORD hdr[54>>2]={0x3ACE4D42,0x0,0x360000,0x280000,0x640000,0x320000,0x10000,0x18,0x3A980000,0x0,0x0,0x0,0x0};
    // chnage resolution
    ((DWORD*)(((BYTE*)hdr)+0x12))[0]=xs;
    ((DWORD*)(((BYTE*)hdr)+0x16))[0]=ys;
    // read pixel data from OpenGL into memory
    BYTE *dat=new BYTE[xs*ys*3];
    glReadPixels(0,0,xs,ys,GL_BGR,GL_UNSIGNED_BYTE,dat);
    // save header
    hnd=FileCreate(name);
    FileWrite(hnd,hdr,54);
    // save pixel data
    FileWrite(hnd,dat,xs*ys*3);
    // free up stuff
    FileClose(hnd);
    delete[] dat;
    }

在渲染場景后簡單地調用它,提供文件名和分辨率 OpenGL window...

只需將其移植到 C# 並將文件訪問權限更改為您可以隨意使用的任何內容。 header 是從 MS Paint 中創建的未壓縮的 24 位 BMP中提取的(win7 x64 和大於 1x1 的尺寸,因為它們具有不同的編碼,上帝知道是什么原因)......並且只是根據BMP 格式規范更改了分辨率

這是它產生的樣本 output:

輸出

請注意:

  • 對於不能被 4 整除的分辨率,它可能需要一些對齊調整(我懶得檢查它)......
  • 使用二進制文件訪問模式或函數
  • 在具有不同字節順序(高/低字節順序)的平台上,您需要按字節存儲xs,ys (或在存儲到hdr[]之前反轉字節順序)

使用您在問題中提供的方法,我剛剛使用此 Click 事件處理程序代碼向文件菜單添加了一個 SaveFileDialog 和一個 Save Bitmap 項,它似乎工作得很好:

private void saveBitmapToolStripMenuItem_Click(object sender, EventArgs e){
    if(saveFileDialog1.ShowDialog(this) != DialogResult.OK) return;
    var bmp = GrabScreenshot();
    bmp.Save(saveFileDialog1.FileName, ImageFormat.Bmp);
}
Bitmap GrabScreenshot(){
    if(GraphicsContext.CurrentContext == null) throw new GraphicsContextMissingException();
    var bmp = new Bitmap(ClientSize.Width, ClientSize.Height);
    var data = bmp.LockBits(ClientRectangle, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
    GL.ReadPixels(0, 0, ClientSize.Width, ClientSize.Height, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
    bmp.UnlockBits(data);
    bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
    return bmp;
}

在ReadSelectedFile方法中,可以使用GrabScreenshot方法生成一個Bitmap的當前framebuffer。 然后,您可以使用 Bitmap class 的 Save 方法將此 Bitmap 保存到文件中

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM