我的目标是在GL_Control(gui控件)上使用c#中的opentk绘制内容,并且每次调用paint事件时都将其保存到Bitmap对象。 我有这段代码:
private void glControl1_Paint(object sender, PaintEventArgs e)
{
// do lots of drawing here
GL.Finish();
GL.Flush();
glControl1.SwapBuffers();
gl_image = TakeScreenshot();
}
public Bitmap TakeScreenshot()
{
if (GraphicsContext.CurrentContext == null)
throw new GraphicsContextMissingException();
int w = glControl1.ClientSize.Width;
int h = glControl1.ClientSize.Height;
Bitmap bmp = new Bitmap(w, h);
System.Drawing.Imaging.BitmapData data =
bmp.LockBits(glControl1.ClientRectangle, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
GL.ReadPixels(0, 0, w, h, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
bmp.UnlockBits(data);
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
return bmp;
}
所以在交换缓冲区后的paint事件中,我采取了schreenshot。 问题是捕获的图像处于绘图之前的状态。这意味着如果我想捕获图像,我需要运行两次paint事件。 我已经尝试过GL.flush并完成和swapbuffer。 有没有人知道如何克服这个问题。 另请注意,我尝试使用异步方式,但失败了,因为您无法从另一个线程访问opentk图像数据。
答案 0 :(得分:2)
我遇到了同样的问题,这是我如何解决它的问题。
当您调用glControl1.Invalidate()
来刷新图像时,OpenTK实际上是在非常结束时执行此操作。因此,如果您在该滴答期间抓取屏幕截图,则缓冲区将不会更新,直到下一个周期。
您需要做的是强制glControl1
刷新,这是代码。
public void GLrefresh()
{
glControl1.Invalidate();
glControl1.Update();
glControl1.Refresh();
}
在获取屏幕截图之前调用此功能
GLrefresh();
Image I = TakeScreenshot();
//Now Image I should be the image of the current buffer
答案 1 :(得分:0)
克里斯。谢谢。你的想法有效。我希望尽可能高效。 这是一个改进版本:
bool must_redraw = true;
private void glControl1_Paint(object sender, PaintEventArgs e){
must_redraw = !must_redraw;
// ...
}
private void timer1_Tick(object sender, EventArgs e)
{
if (must_redraw)
{
glControl1.Refresh();// redraws and updates
gl_image = TakeScreenshot();
}
}
然而,它确实使绘画操作加倍,使绘图速度减慢了2倍,所以如果有人有其他想法,请发帖。