我将复杂的 2D 场景绘制到 OpenGL 窗口。我希望用户能够截取场景的屏幕截图并将其保存为 JPG。但是,我希望他们能够指定可以将场景绘制得比他们的屏幕大(这将使他们能够看到更多细节等)。
当他们指定大于适合他们屏幕的视口的数字时,他们不可见的所有内容都不会被绘制到位图上。我觉得我对其中一些我无法追踪的 OpenGL 函数的行为有错误的理解。
当renderSize
小于我启动程序的默认视口时,下面的代码工作得很好。如果renderSize
更大,则会创建适当大小的 JPG,但超出屏幕可见区域的右侧/顶部部分只是空白。如果我在第二个显示器上单击并拖动视口,则会绘制更多图片,但如果renderSize
比两个显示器都大,则仍然不是全部。我怎样才能使这个绘图独立于屏幕上显示的视口是什么?
(我可以验证renderLocation
并renderSize
在调用此函数时正确设置,renderSize
并且数字很大,例如 7000 x 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
}