使用glControl而不是Gamewindow。但是如何在另一个线程中自动渲染?

时间:2018-07-15 06:16:20

标签: c# multithreading opentk

感谢您阅读此问题!

我以前使用的程序具有主窗口形式。当我单击按钮时,另一个线程将创建Gamewindow表单,该表单显示来自Camera的帧数据。 OnUpdateFrame()OnRenderFrame()被自动调用,并在创建的窗口中处理数据和渲染。

我正在研究此软件的更新愿景,该软件的主窗口形式为glControl

是的,我使用的是glControl而不是Gamewindow。但是问题是..

由于“主窗口”表单需要处理用户输入,因此我必须在另一个线程中控制glControl,该线程不断更新和呈现Frame数据。但是glControl以创建并显示的主窗口形式显示。在另一个线程中操作的glControl不会应用于主窗口形式。 (我只能在其他线程代码中使用glControl.Swapbuffers().invalidate()
我发现一条信息,指出glControl仅在一个线程中受到控制。因此,如何在使用glControl表单时自动在Mainwindow上渲染帧数据。

我尝试过GL。函数使用timer来更新渲染帧数据,但该计时器也是另一个线程,因此更改不会应用于Main表单中的glControl

并且我尝试在另一个线程中新建并创建glControl,但是在使用GL时它显示了异常。函数(:调用线程中没有GraphicsContext)

我该如何解决这个问题?

==========

这是我尝试的一种方法,发现它不起作用。.计时器线程调用的RenderFrame()不能在glControl1上显示任何内容,即使以为glcontrol1.Invalidate()也会定期调用。

实际上,在以前使用gamewindow时,OnRenderFrame()会定期出现并在窗口中显示对象。但是我该如何在主窗口窗体的glControl上执行此操作。主线程可以定期调用RenderFrame()吗?看来计时器也是一个线程,所以计时器线程调用的RenderFrame()无法正常工作。

public partial class MainWindowForm : Form
{
System.Timers.Timer glControlTimer;
...
    private void InitializeComponent()
    {
        glcontrol1 = new OpenTK.GLControl();
    ...
    }

    private void btShowLive2_Click(object sender, EventArgs e)
    {   
    ...
            oHandleGLControl = new HandleGLControl(glcontrol1);
            glControlTimer = new System.Timers.Timer(300); 
            glControlTimer.Elapsed += TimerElapsed;
            glControlTimer.Start();
    }


    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        oHandleGLControl.UpdateFrame();   //processing frame data
        oHandleGLControl.RenderFrame(); //rendering
        glcontrol1.Invalidate();
    ...
    }
}

public class HandleGLControl
{
    public void UpdateFrame()
    {...
    }

    public void RenderFrame()
    {
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        GL.PushMatrix();

        GL.MatrixMode(MatrixMode.Modelview);
        GL.Translate(-cameraPosition[0], -cameraPosition[1], -cameraPosition[2]);
        GL.Rotate(g_pitch, 1.0f, 0.0f, 0.0f);
        GL.Rotate(g_heading, 0.0f, 0.0f, 1.0f);
    ....
     }
...
}

1 个答案:

答案 0 :(得分:1)

前一阵子,我遇到了同样的问题,而您面临的问题与OpenGL上下文有关,特别是OpenGL上下文只能绑定到一个线程这一事实。

但是,尽管大家普遍认为,该线程不必一定是主窗口线程,它可以是您想要的任何线程。

这个过程很简单但很精致:

  • 首先,从主线程取消绑定OpenGL上下文
  • 然后启动您的线程并在那里绑定OpenGL上下文

在OpenTK中,这是我的操作方式:

private void glcontrol1_Load(object sender, EventArgs e){
    glcontrol1.Context.MakeCurrent(null); //Unbinds the context from the current thread.
    Thread renderThread = new Thread(() => {
        glcontrol1.Context.MakeCurrent(glcontrol1.WindowInfo); //Bimds the OpenGL context to this new thread
        while(DoRender) { RenderFrame(); }
    }
    renderThread.Start();
}

您也可以将glcontrol1.SwapBuffers()调用放入RenderFrame()方法中,到目前为止,它没有给我带来任何问题。

作为建议,我将在不同的线程上运行UpdateFrame()和RenderFrame()方法,以免将更新逻辑限制为程序的帧速率。