如何捕捉使用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图像数据。
我有完全相同的问题,这是我如何解决它。当你调用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倍,所以如果有人有其他想法,请发布。