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

时间:2014-09-10 08:56:11

标签: 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 个答案:

答案 0 :(得分:3)

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

相反,使用标志指示新几何图形的计算是否正在进行,如果是,则渲染旧几何图形。现在您需要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
        }
    }

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

答案 1 :(得分:2)

游戏中的多线程主要是(取决于流派,功能......)以这种方式使用:

  • 1个主题 - 渲染

  • 1..x线程 - 物理(你的变形属于哪里)

  • x Threads - AI

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

我建议你使用类似ConcurrentQueue类的东西来排队应该由物理线程计算的对象。这样你就不需要每次都重新创建线程。只是让他们闲着,然后计算出什么东西进入队列。