c# - 在游戏中使用正确的多线程

标签 c# multithreading

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

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# 并行编程方面的专家,但我确信这不是一个好的解决方案。每一帧,都会创建、执行和销毁一个新线程,这会导致很大的开销。在我的案例中,一个好的解决方案会是什么样子?

最佳答案

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

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

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

实现

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

    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
        }
    }

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

关于c# - 在游戏中使用正确的多线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25761226/

相关文章:

java - 线程不同时执行

c# - 在 C# 中将数据传递到回调方法(通过 BeginInvoke)

c# - 使用 Task.Factory.StartNew 传递方法参数

c# - 如何避免为 WCF 中值为 Nothing 的属性创建 xml 标记?

C# - 这种技术如何称呼?

ios - endBackgroundTask 不带后台标识符

c# - 在不对数据库连接执行查询的情况下解析 SQL Server 查询

c# - 继续在 dotnet highchart 上画线

Java集群,只运行一次任务

c# - 为什么我在使用线程的并发 HTTP 连接上受限