[英]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:
請注意:
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.