onRenderFrame和onUpdateFrame在OpenTK中有什么区别?

8

我正在使用OpenTK框架和OpenGL在C#中编写一个跳跃游戏。

OpenTK提供了一些预设函数,例如GameWindow.Run();GameWindow.onUpdateFrame();onRenderFrame();

就我所思考的而言,所有绘制OpenGL元素或基元的操作都应该放在onRenderFrame中,而像玩家移动这样的游戏事件应该在onUpdateFrame中执行,这样可以在渲染新帧之前提前计算这些操作。

我的想法对吗?如果在onRenderFrame方法中执行所有操作会有什么不同吗?OpenTK建议不要重写这些方法,而是订阅它们的事件(onRenderFrameEvent)。

http://www.opentk.com/files/doc/class_open_t_k_1_1_game_window.html#abc3e3a8c21a36d226c9d899f094152a4]

什么是订阅,如何订阅事件而不是重写方法?

protected override void OnUpdateFrame(FrameEventArgs e)
{
    base.OnUpdateFrame(e);

    this.gameObjects.moveObjects();

    this.player.Move();
    if (this.player.jumpstate == true) this.player.Jump();
}

protected override void OnRenderFrame(FrameEventArgs e)
{
    base.OnRenderFrame(e);

    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

    Matrix4 modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY);
    GL.MatrixMode(MatrixMode.Modelview);
    GL.LoadMatrix(ref modelview);

    GL.LoadIdentity();
    GL.Translate(0.0f, 0.0f, -3.5f);

    this.gameObjects.drawObjects();
    this.player.Draw();

    SwapBuffers();
}

2
我认为updateFrame是用来更新几何和矩阵的,而renderFrame则是用来实际绘制所有内容的。 - ratchet freak
renderFrame 是主循环,尽可能频繁地处理(如果禁用垂直同步),而 updateFrame 则在固定间隔内触发,该间隔由上下文创建中的参数定义(通常为每秒 30 或 60 次)。 - j-p
尽快触发渲染是为了整体性能的提升(据我们所知),因为人眼的帧率感知限制。如果您的更新函数不会使该过程低于该限制,则可以在任何时候触发帧计算。 - j-p
1个回答

10

基本上就像评论所说的那样:在 UpdateFrame 事件中更新你的世界,在 RenderFrame 中渲染它。

当你意识到你的游戏将在各种不同的硬件上运行时,这就有意义了。有些电脑可能只能以15fps的速度渲染你的游戏,而其他电脑则可以实现稳定的60fps。拥有120Hz显示器的玩家希望你的游戏以120fps的速度运行,以享受其系统的全部潜力。

在所有这些情况下,你都希望你的游戏逻辑以 相同的速度 运行并给出 相同的结果

实现这一点最简单的方法是在 GameWindow.Run() 中设置固定的 UpdateFrame 帧率:

using (var game = new GameWindow())
{
     game.VSync = VSyncMode.Adaptive;
     game.Run(60.0, 0.0);
}

这段代码片段指示OpenTK每秒引发60个UpdateFrame事件和尽可能多的RenderFrame事件,最高不超过显示器的刷新率。在较慢的系统上运行时,OpenTK将放弃RenderFrame事件以确保每秒有60个稳定的UpdateFrame事件。这通常称为“固定时间步进”。

请参见修复您的时间步进!了解为什么这是可取的。

请参见Quake 3了解为什么不应该在RenderFrame事件中执行世界更新(简短版本:在Quake 3中,高帧率的数值不准确会导致玩家跳得更高并获得竞争优势)。

编辑:有关您问题的第二部分,请参见理解C#事件。例如:

using (var game = new GameWindow())
{
    game.RenderFrame += (sender, e) =>
    {
        GL.Clear(ClearBufferMask.ColorBufferBit);
        game.SwapBuffers();
    };
}

订阅 GameWindow.RenderFrame 没有比继承 GameWindow 并重载它的 OnRenderFrame 方法更多的内在优势。选择哪种方法更适合您的代码结构。


感谢您深入的回答。这确实帮助了我,因为我第一次使用OpenTk。 - user3605638

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接