如何捕获使用opentk绘制的图像

时间:2014-08-07 02:23:48

标签: c# graphics opentk

我的目标是在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图像数据。

2 个答案:

答案 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倍,所以如果有人有其他想法,请发帖。