2013-02-19 60 views
2

我將複雜的2D場景繪製到OpenGL窗口。我希望用戶能夠截取場景並將其保存爲JPG格式。但是,我希望他們能夠指定場景可以比他們的屏幕更大(這將允許他們看到更多細節等)。向C#位圖繪製一個OpenGL場景;屏幕截屏

當它們指定大於符合其屏幕的視口的數字時,它們無法看到的所有內容都不會被繪製到位圖上。我覺得我對這些OpenGL函數的行爲有些誤解,而這些函數是我無法追蹤的。

下面的代碼在renderSize小於默認視口,我開始使用該程序時完全正常。如果renderSize較大,則會創建適當大小的JPG,但是通過屏幕可見區域的右側/頂部僅爲空白。如果我在第二臺顯示器上點擊並拖動我的視口,那麼更多的圖片會被繪製,但如果renderSize比兩臺顯示器都大,仍然不是全部。我怎樣才能使這個繪圖獨立於顯示在屏幕上的視口?

(我可以驗證renderLocationrenderSize設置是否正確時,這個函數被調用,以renderSize是一些大的數字,比如7000×2000個)

public Bitmap renderToBitmap(RenderMode mode) 
    { 
     // load a specific ortho projection that will contain the entire graph 
     GL.MatrixMode(MatrixMode.Projection); 
     GL.PushMatrix(); 
     GL.LoadIdentity(); 

     GL.Ortho(0, renderSize.Width, 0, renderSize.Height, -1, 1); 
     GL.Viewport(0, 0, renderSize.Width, renderSize.Height); 

     GL.MatrixMode(MatrixMode.Modelview); 
     GL.PushMatrix(); 
     GL.LoadIdentity(); 


     // move the graph so it starts drawing at 0, 0 and fills the entire viewport 
     GL.Translate(-renderLocation.X, -renderLocation.Y, 0); 

     GL.ClearColor(Color.White); 
     GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); 

     // render the graph 
     this.render(mode); 

     // set up bitmap we will save to 
     Bitmap bitmap = new Bitmap(renderSize.Width, renderSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 
     BitmapData bData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat); 

     // read the data directly into the bitmap's buffer (bitmap is stored in BGRA) 
     GL.ReadPixels(0, 0, renderSize.Width, renderSize.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bData.Scan0); 

     bitmap.UnlockBits(bData); 
     bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); // compensate for openGL/GDI y-coordinates being flipped 

     // revert the stuff about openGL we changed 
     GL.MatrixMode(MatrixMode.Projection); 
     GL.PopMatrix(); 
     GL.MatrixMode(MatrixMode.Modelview); 
     GL.PopMatrix(); 

     return bitmap; 
    } 

這裏就是我如何初始化我的GL窗口中,案例發揮作用。

private void initGL() 
    { 
     GL.ClearColor(Color.AntiqueWhite); 
     GL.Disable(EnableCap.Lighting); 

     GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); 

     resetCamera(); 
    } 

    private void resetCamera() 
    { 
     offsetX = offsetY = 0; // Bottom-left corner pixel has coordinate (0, 0) 
     zoomFactor = 1; 
     setupViewport(); 
     glWindow.Invalidate(); 
    } 

    private void setupViewport() 
    { 
     int w = glWindow.Width; 
     int h = glWindow.Height; 
     GL.MatrixMode(MatrixMode.Projection); 
     GL.LoadIdentity(); 
     GL.Ortho(0 + offsetX, w + offsetX, 0 + offsetY, h + offsetY, -1, 1); 
     GL.Viewport(0, 0, w, h); // Use all of the glControl painting area 
    } 

回答

1

聽起來你正在運行到一個pixel ownership問題:

14.070爲什麼我沒有得到有效的像素數據的重疊區域,當我打電話glReadPixels()的窗口,其中一部分被另一個 窗口重疊?

這是由於部分OpenGL規範稱爲像素 所有權測試。如果一個窗口被另一個窗口遮擋,那麼 不得不存儲被遮蔽區域的像素數據。因此,glReadPixels()調用可以爲遮蔽區域返回未定義的數據。

像素所有權測試從一個OpenGL實現到下一個 。某些OpenGL實現會將窗口的遮擋區域(即整個窗口)存儲在屏幕外的緩衝區中。這種實現 可以爲隱蔽窗口返回有效像素數據。然而,許多OpenGL實現將屏幕上的像素一一映射到 幀緩衝存儲位置,並且不存儲(並且不能返回)用於窗口遮擋區域的像素 數據。

一種策略是指示窗口系統將窗口 向前移動到窗口堆棧頂部,渲染,然後執行glReadPixels()調用 。但是,這種方法仍有可能掩蓋源窗口的用戶干預風險。

可能適用於某些應用程序的方法是將其呈現爲不可見窗口,例如X Windows下的Pixmap。這種類型的 繪圖表面不能被用戶遮擋,其內容應該始終通過像素所有權測試 。從這樣的圖形 表面讀取應該總是產生有效的像素數據。不幸的是,將 渲染到這樣的繪圖表面通常不會被圖形 硬件加速。

查看FBOs或PBuffers進行大於窗口和/或離屏渲染。如果你不能/不會使用FBO或PBuffers,也有libtr

+1

謝謝,這似乎是問題。我編寫了我自己的平鋪算法(類似於libtr)來克服這個問題,將場景渲染成多個視口大小的位圖,然後將它們全部繪製成一個大的位圖。 – XenoScholar 2013-02-20 20:34:10