我将一个复杂的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
}
答案 0 :(得分:1)
听起来你遇到了pixel ownership问题:
14.070当我调用glReadPixels()时,为什么我没有获得重叠区域的有效像素数据,其中窗口的一部分与另一个窗口重叠 窗口吗
这是由于OpenGL规范的一部分称为Pixel 所有权测试。如果窗口被另一个窗口遮挡,则不会 必须存储模糊区域的像素数据。因此,一个 glReadPixels()调用可以为模糊区域返回未定义的数据。
Pixel Ownership测试因OpenGL实现而异 下一个。一些OpenGL实现存储窗口的模糊区域, 或者整个窗口,在屏幕外的缓冲区中。这样的实现 可以返回模糊窗口的有效像素数据。但是很多 OpenGL实现将屏幕上的像素一对一映射到 framebuffer存储位置并且不存储(并且不能返回)像素 窗口模糊区域的数据。
一种策略是指示窗口系统带窗口 转发到窗口堆栈的顶部,渲染,然后执行 glReadPixels()调用。但是,这种方法仍然存在用户风险 干预可能会掩盖源窗口。
可能适用于某些应用程序的方法是渲染到 非可见窗口,例如X Windows下的Pixmap。这类 绘图表面不能被用户遮挡,其内容应该是 总是通过像素所有权测试。从这样的图纸中读取 surface应始终生成有效的像素数据。不幸的是,渲染 这种绘图表面通常不会被图形加速 硬件
查看FBOs或PBuffers是否有大于窗口和/或屏幕外渲染。
如果您不能/不会使用FBO或PBuffers,还有libtr
。