代码示例:使用 Unity* 进行并行处理的一种方法

文件:

在 GitHub* 上下载:
许可:英特尔示例源代码许可协议
面向……优化 
操作系统:Windows® 10(64 位)
硬件:需要 GPU
软件:
(编程语言、工具、IDE、框架)
Microsoft Visual Studio* 2017、Unity* 5.6、C#
前提条件:熟悉 Microsoft Visual Studio、Unity* API、3D 图形、并行处理。
教程:使用 Unity* 进行并行处理的一种方法

简介

该项目的理念是展示如何使用 Unity* 在游戏中进行并行处理,以及如何使用游戏引擎执行与游戏相关的物理。在这个领域内,现实感是成功的一个重要标志。为了模拟真实世界,许多动作需要同时发生,这需要并行处理。创建两个不同的应用,然后将它们与在单个内核上运行的单线程应用进行比较。代码和随附的文章(参见下面的参考文献)介绍了群集算法的开发,并通过两个应用以鱼群的形式展示该算法。第一个应用在多线程 CPU 上运行,第二个应用在 GPU 上执行物理计算。

  1. 群集算法的实施
  2. 编码差异:CPU 对比 GPU

入门教程

群集算法的实施

在本示例中,一个群集被定义为一群鱼。算法需要考虑每个成员的聚集、队列和分离。如果每条鱼都与鱼群中的其他鱼保持一定的距离,经过计算得出,该鱼在一个鱼群里“游动”。鱼群的成员只能以群集成员的身份行动,不得单独行动,它们拥有相同的参数,如速度和方向。

该群集算法的复杂度为 O(n2),其中,n 为鱼的数量。为了更新单条鱼的移动,算法需要查看环境中的所有其他 n 条鱼,以确定鱼是否可以 1) 留在鱼群;2) 离开鱼群;或者 3) 加入新鱼群。单条鱼可能单独“游”一段时间,并有机会加入新鱼群。这需要针对每条鱼执行 n 次。

算法可以被简化为:

对于每条鱼 (n)

查看所有其他的鱼 (n)

如果鱼之间的距离足够近

应用规则:聚集、队列和分离

数据被存储于两个缓冲区内,以表示每条鱼的状态。交替使用这两个缓冲区进行读写。需要这两个缓冲区在内存中维持每条鱼之前的状态。然后,使用该信息计算每条鱼的下一个状态。在每一帧前,读取当前读取缓冲,以更新场景。

该应用的基本流程为:

  1. 初始化场景。
  2. 针对每一帧更新场景
    1. 读取当前的读取缓冲
    2. 计算场景
    3. 渲染场景
    4. 写入当前的写入缓冲
    5. 交换缓冲

编码差异:CPU 对比 GPU

单线程和多线程应用的主要编码区别体现在如何调用群集计算上。请记住,每一帧都会调用 n 次该计算。单线程应用使用常规的 for 循环,而多线程应用使用 Parallel.For 类。

为了得到最佳性能,将物理计算的任务转移至 GPU。为此,在 GPU上使用并执行“着色器”。使用着色器为场景添加图形效果。本项目使用了“计算着色器”。通过 HLSL(高级着色器语言)编写计算着色器。计算着色器复制 Calc 函数的行为(如速度、位置、方向等),但是无需计算旋转。

使用 Parallel.For 函数的 CPU 调用面向每条鱼的 UpdateStates 函数,以便在绘制每条鱼前,计算其旋转并创建 TRS 矩阵。使用“四元数”类的 Unity 函数 Slerp 计算鱼的旋转。

请注意,随附的文章指出了使用 GPU 时需要考虑的其他方面:

  • GPU 上的随机数生成
  • 在 GPU 和 CPU 之间交换与共享数据
  • CPU 优于 GPU 的案例

参考资料

Jeremy Servoz,Integrated Computing Solutions 公司,《使用 Unity 进行并行处理的一种方法》https://software.intel.com/zh-cn/articles/an-approach-to-parallel-processing-with-unity,2018

更新日志

创建于 2018 年 3 月 20 日

有关编译器优化的更完整信息,请参阅优化通知