繁体   English   中英

C# 中的非阻塞 OpenGL (OpenTK) 游戏循环

[英]Non-blocking OpenGL (OpenTK) Game Loop in C#

我正在尝试将游戏嵌入到编辑器中,并使用界面让两者相互交谈。 这一切都很好,除了现在,我必须为游戏停靠在编辑器中时制作一个自定义游戏循环。

该游戏是 Windows 控制台应用程序,并使用 OpenTK。

  • 当游戏自行运行时(作为独立应用程序),OpenTK 创建一个GameWindow ,它在内部处理其游戏循环(您调用window.Run(updateSpeed, renderSpeed)并启动循环,仍然轮询和处理 window 中的消息过程。
  • 当游戏由编辑器运行时,游戏会获得对编辑器GLControl的引用,并处理来自控件的各种事件。

编辑器是同一解决方案中的一个单独项目。 它是一个 WPF 应用程序,并使用包含用于游戏的GLControlWindowsFormsHost ,它在 window 中拥有一个空间,以及用于各种编辑器控件的面板。

问题是,我需要能够从游戏本身运行游戏循环,并让该循环能够使用 OpenGL 进行渲染。 我对线程/任务的概念了解一些,但我也知道 OpenGL 上下文不能跨线程工作。 因此,如果我在游戏中运行标准循环(在编辑器中运行它时),该循环将阻塞编辑器并锁定整个 window。 我不能创建一个异步循环,因为它不能调用渲染 function,因为 GL 上下文没有在该线程上设置,所以它引发:

AccessViolationException

...一旦进行任何 GL 调用(例如清除颜色缓冲区)。

就这一切在代码中的工作方式而言,游戏 class 有一些私有变量来确定它是否嵌入在编辑器中。 正常运行时,这些为 false/null,游戏创建 window 并正常运行(这一切正常)。 运行编辑器时,编辑器初始化GLControl ,然后在游戏中调用 function 设置引用,并告诉游戏它在编辑器中。 Then once all the WPF components are initialised, a "play" button calls the game's Run() function (this is the same function called by the entry-point when running as a standalone application; it just decides what to do based on the condition的编辑器变量不是假/空)。 WPF 编辑器还有一个“停止”按钮,它将调用游戏的Shutdown() function。 我想最终实现一种在编辑器运行的情况下热重新加载游戏代码的方法(也许我会让游戏成为DLL并以这种方式加载 - 这现在并不重要,可能不会发生,取决于这是否在 realm 的可能性中;如果您认为可以做到,请随意加入)。 游戏运行后,它需要能够更新和渲染(最好以不同的速度进行 - 我需要每秒进行 30 次更新并以每秒 60 次的速度渲染(当然,这最终会考虑到 V-Sync )),而不会阻塞编辑器的 UI。

我怎么能 go 关于这样做? 我想线程将是绝对必须的,所以我需要一种能够从单独的线程中访问 GL 上下文的方法(大概)。 任何帮助将不胜感激。 如果有人需要代码,请告诉我您需要哪些部分,因为数量很多,我认为在这里发布所有内容并不是一个好主意。 希望您不需要任何东西,因为项目设置已在此处描述,并且目前游戏本身并不包含太多; 它现在只是在视口中间渲染一个白色四边形,直到我从旧版本的项目中移植我的代码; 但首先我需要启动并运行基础知识)。

休息半天后,我回到项目中再次尝试,我似乎已经开始工作了(大致可以接受的程度)。

我做了什么:

  • 首先,我从使用Task更改为使用Thread
  • 其次,在创建线程之前,我存储了Thread.CurrentThread的值。
  • 然后,在新创建的游戏循环线程中,我有一个while (Running)循环。 每次进入循环时,我都会调用游戏的更新和渲染函数,以及GLControlSwapBuffers() function 从调用中调用: Dispatcher.FromThread(mainThread).Invoke(( ) => {... });

这从主线程运行这些函数。 我不确定幕后到底发生了什么来完成这项工作,而且我几乎可以肯定有更好的方法来做到这一点,但是......它确实可以完美地满足我的需求。

这是游戏循环线程代码,希望这对将来的某人有所帮助(如果这是糟糕的代码(我敢打赌),请告诉我为什么,以及如何改进它)

游戏循环线程代码:

Thread mainThread = Thread.CurrentThread;
new Thread(() =>
{
    Dispatcher.FromThread(mainThread).Invoke(() =>
    {
        Debug.LogInfo("Game loop thread started!", EditorTextColour.Green);
    });

    while (Running)
    {
        if (IsInitialized)
        {
            Dispatcher.FromThread(mainThread).Invoke(() =>
            {
                Update();
                Render();
                if (Embedded)
                {
                    EmbeddedControl.SwapBuffers();
                }
            });
        }
        Thread.Sleep(200); // TODO: Tune this using actual timing values!!
    }
}).Start();

结果:

引擎运行游戏,告诉它它嵌入在编辑器中,并调用游戏的Run() function。 游戏注意到它是嵌入的,并选择不创建 window,而是启动上面显示的代码(在调用Initialize() function 以确保在使用它们之前可以设置任何需要的值之后)。 游戏循环线程通过Dispatcher从主线程调用游戏的Update()Render()函数,并在每个循环后休眠。 Et Voilá,我们有一个游戏在它自己的 WPF 编辑器中运行,非常整洁,适合学习练习!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM