关于c#:在游戏中使用正确的多线程 | 珊瑚贝

Using correct multithreading in a game


我目前正在开发一款模拟可变形 3D 对象的 3D 游戏。对于可变形,我的意思是 3D 对象的几何形状在逐帧变化。游戏中有一个渲染循环,应该尽可能频繁地执行(至少 30 次/秒)以获得下降的帧速率。但我还在这个渲染循环中做另外两件事:计算新几何和计算轴对齐边界框层次结构 (AABVH)。我需要 AABVH 进行碰撞检测。在渲染 3D 对象之前完成几何和 AABVH 计算非常重要。计算新几何和 AABVH 是一项耗时的任务,因此我的帧速率迅速下降。因此,我的想法是在单独的线程中计算 AABVH。
这看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
Thread t;
public void Render(Object3D o) // renders 3D object
{
  if (t != null) // wait until the new geometry got calculated
  {
     t.Join();
  }
  o.RenderGeometry();
  t = new Thread(() => o.CalcAABVH());
  t.Start();
}

我不是 C# 并行编程方面的专家,但我确信这不是一个好的解决方案。每一帧,都会创建、执行和销毁一个新线程,这会导致很大的开销。在我的情况下,一个好的解决方案会是什么样子?

  • 这是在什么平台上的? OpenGL?直连 11?你能在 GPU 上的着色器中进行几何修改吗?您能否简化变形网格以使其更合理并与 GPU 合作,例如使用蒙皮网格?多线程是非常复杂的,你真的想避免它,直到它是绝对必要的。现代 DX 使这变得更容易,因为您可以从多个线程等访问 DX 资源,但它仍然相当困难。如果您确实需要多线程,Gusdor 的建议是避免大多数复杂性的好方法。
  • 当心;多线程不一定会提高应用程序的性能。只有当您有多个 CPU 内核并确保您的线程被安排在不同的内核上时,才能实现显着的性能提升。显然,硬件图形加速器是实现这一目标的好方法。 :-)
  • @Luaan:它在 Windows 上的 OpenGL。你说得对,要做到这一点既昂贵又复杂。问题是我不仅要计算新几何图形,还要计算新几何图形的轴对齐边界框层次结构。我不能为此使用几何着色器。
  • @MikeofSST:绝对正确!硬件图形加速器?从来没有听说过。这是什么?
  • 对不起,我不够精确。我实际上在计算两件事:新几何和包围体层次结构。我已经编辑了我的问题。


您不应在几何图形更新时阻止下一帧的渲染。您也可以同步运行计算。阻止渲染会增加每一帧的总渲染时间,并对帧速率产生负面影响——这是您特别要避免的影响!

相反,使用一个标志来指示新几何图形的计算是否正在进行,如果是,则渲染旧几何图形。现在您需要 2 个几何体集 – 就像使用帧缓冲区一样,您在新几何体完成时交换它们。

最终结果是,某些帧可能没有您希望的最新几何图形可用。这在几何体计算时间较长的对象上会更加明显。无论如何,大多数游戏的图形编程都是烟雾缭绕的,所以不用担心。

执行

请为这些更新操作使用线程池线程,因为创建成本较低。理想情况下,使用任务并行库。作为奖励,Task 对象会为您跟踪其运行状态!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    using System.Threading.Tasks;

   

    Task t;
    public void Render(Object3D o) // renders 3D object
    {
        if(t != null && t.Status == System.Threading.Tasks.TaskStatus.Running)
        {
            //render old geometry
        }
        else
        {
            t = Task.Factory.StartNew(o.CalcNewGeometry())
                    .ContinueWith(p => o.UpdateGeometry); //swap the new geometry in
        }
    }

您需要在此处进行一些同步,以确保在渲染旧几何图形时不会交换新几何图形。我将把它留给你。

  • 如果 OP 想要一个固定步长的模拟例如一个弹跳球。尽管如此,这至少允许他使用线程池来安排工作,并在需要时甚至在最后一帧开始处理之前实际安排工作,这可能会显着降低延迟。
  • @Luaan 可以说,如果你想要一个固定的步骤模拟,你同步地做你的步骤:Calculate physics -> calculate geometry -> render。精度比帧率更重要。对我来说,这看起来像是基于实体的游戏编程,我坚持这个主题。
  • 是的,这将是通常的方式。但是,如果您在 Update 步骤中更早地开始处理,您可以轻松减少一到两毫秒的延迟,这对 FPS 有很大帮助。毕竟,OPs 解决方案已经落后于任何输入一帧——他在渲染最后一个几何图形后计算下一个几何图形。
  • 如前所述,我不是多线程专家。但我确信我会在你的解决方案中得到一个 NullReferenceException,因为当第一次到达 if 子句时 t 为空。所以我必须事先创建一个任务,而不是在 else 子句中,对吧?
  • @NMO 将强制几何图形绘制每个通道。我编辑了一个修复程序。
  • 感谢您的努力。我是这样实现的。效果很好。


游戏中的多线程主要(取决于类型、功能……)以这种方式使用:

  • 1 线程 – 渲染

  • 1..x 线程 – 物理(你的变形所属的地方)

  • x 线程 – 人工智能

渲染对象的实际状态,在物理线程中将其变形为副本。
按照 Gusdor 的建议在变形后切换对象。

我建议您使用类似 ConcurrentQueue 类的东西来对应该由物理线程计算的对象进行排队。这样你就不需要每次都重新创建线程。让他们空闲并在有东西进入队列的那一刻进行计算。


来源:https://www.codenong.com/25761226/

微信公众号
手机浏览(小程序)

Warning: get_headers(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57

Warning: get_headers(): Failed to enable crypto in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57

Warning: get_headers(https://static.shanhubei.com/qrcode/qrcode_viewid_9472.jpg): failed to open stream: operation failed in /mydata/web/wwwshanhubei/web/wp-content/themes/shanhuke/single.php on line 57
0
分享到:
没有账号? 忘记密码?