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

本文关键字:绘制 图像 opentk 何捕捉 | 更新日期: 2023-09-27 18:16:55

我的目标是用c#中的opentk在GL_Control (gui控件)上绘制东西,并在每次调用paint事件时将其保存为位图对象。我有这样的代码:

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事件中,在交换缓冲区后,我截取了屏幕截图。问题是,捕获的图像是绘制之前的状态。这意味着如果我想捕获图像,我需要运行两次paint事件。我试过gl, flush, finish和swapbuffer。有人知道如何克服这个问题吗?还请注意,我曾尝试使用异步方式,但失败了,因为您无法从另一个线程访问opentk图像数据。

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

我有完全相同的问题,这是我如何解决它。当你调用glControl1.Invalidate()来刷新图像时,OpenTK实际上在VERY END这样做。所以,如果你在那个时间点抓取截图,缓冲区将不会被更新,直到下一个周期。

您需要做的是强制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

谢谢。你的想法奏效了。我希望能尽可能地提高效率。下面是一个改进的版本:

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