我目前正在开发一款可以模拟可变形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#中并行编程的专家,但我确信这不是一个好的解决方案。每一帧,一个新的线程被创建,执行和销毁,这会导致很大的开销。在我的案例中,一个好的解决方案会怎样?
答案 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线程 - 物理(你的变形属于哪里)
渲染对象的实际状态,在物理线程中的副本中对其进行变形。 按照 Gusdor 的建议,在变形后切换对象。
我建议你使用类似ConcurrentQueue类的东西来排队应该由物理线程计算的对象。这样你就不需要每次都重新创建线程。只是让他们闲着,然后计算出什么东西进入队列。