基于多核平台的实时动态体积云模拟

来源:互联网 发布:commvault备份软件 编辑:程序博客网 时间:2024/05/24 04:39
 

郭胜,吴晓昶,卢卷彬

英特尔公司软件与服务事业部

1.    介绍

云是户外场景的主要组成部分,没有云的户外场景是不真实的。当前,大多数游戏主要使用2D照片纹理贴到天空盒的方式渲染云,这种方法适合于视点接近地面的场景,当视点接近或穿透云层时--比如在山顶上或从飞行器中观察云景--上述方法无法提供真实的视觉体验。在飞行模拟类游戏中,玩家需要能从各种角度看到立体的、外形可动态变化的和具有自然光照效果的云朵,当飞行器接近和穿越云层时,要求获得真实的视觉体验。实现这些特征要用体积云技术对云进行3D建模、光照和渲染。然而,体积云算法本质上是计算密集的,这对它们在游戏中的应用提出了巨大挑战。虽然已有一些云系统能支持在游戏中实时渲染大范围体积云,但出于性能考虑,这些系统不得不或多或少放弃一些体积云在运行时的真实的动态特征。

当前,多核处理器平台已经成为PC市场的主流,现代处理器的架构将向更多核的趋势发展。然而,由于传统的游戏架构并没有基于多核系统设计,大部分运行在多核处理器上的游戏并不能有效使用所有的CPU核的资源。这为在游戏中生成逼真的体积云提供了额外的性能空间。

本文提出了一种能在主流多核平台上的游戏中使用的渲染动态体积云的方案。我们的方案基于已存在的算法,重点在改进算法的实现,以及使用多线程框架和SSE指令优化性能。我们开发了演示程序LuckyCloud用于实现和评估我们的方案。演示程序的性能测试表明我们的方案在多核平台上有良好的性能伸缩性。与先前的静态云系统相比,我们的方案实现了云的实时动态模拟和光照,并且没有增加游戏主体更多的性能负担。

•2.    背景

过去几十年中,计算机图形学的研究领域中已经出现大量模拟、光照和渲染体积云的技术。这些技术大部分需要消耗大量的计算资源,其中一些技术在早期平台上甚至属于脱机渲染方法。这使在游戏中引入体积云极具挑战性。与生成单独的体积云图像的应用不同,游戏需要实时处理游戏逻辑和渲染场景的各种对象,因此留给生成体积云的性能空间非常有限。为了保证游戏的性能,一些游戏中的云系统不得不脱机预处理一些复杂的计算--如建模、着色(shading)等,这失去了某些云的动态特征,比如基于物理规律的形状演化、可变的自然散射光照,以及逼真的飞入效果等。

我们的方案主要受到Harris【2】和Dobashi【1】的启发。Harris提出了一种能在飞行模拟游戏中使用的云系统。该系统使用粒子系统建模和渲染体积云。通过用imposter简化远距离的云的渲染,该系统在生成大规模云景时依然具有很高的实时性能。Harris使用一种简化Rayleigh散射模型实现了云对光线的各向异性的多次散射,使不同角度能观察到云的不同颜色。为了加速云的光照计算,Harris通过显卡计算每个云粒子的入射光照强度。然而,这种方法要求依次把每个云粒子的入射颜色值从帧缓冲中读回到CPU,作为下一趟渲染时使用。这种读回操作的开销很大。通常场景中有成百上千个云粒子,频繁的显卡读回操作甚至有可能抵消显卡加速带来的好处,反而使性能更差。为了保证实时的体积云渲染,Harris的云系统预先脱机计算每个场景的云粒子的颜色,在运行时仅渲染云粒子。因此在Harris的方法中,光线的强度和方向都是固定的。我们的方案采用了Harris的光照模型,但使用了不同的实现方法,能够支持运行时的动态的光照计算。

Harris的方法仅能渲染静态的云。为了模拟云的动态演化,我们的方案采用了Dobashi的云模拟方法。该方法采用单元自动控制法。云的模拟空间使用一个三维网格表示,网格中的每个单元都有三个二元状态:分别是水汽(hum),相变因子(act)和云(cld);每个状态的值不是0就是1。如图1所示,通过在每个时间步应用一组状态转换规则,可以模拟云的形态的演化,包括云的形成,消散以及随风飘动。根据每个网格单元是否有云,可以插值计算出模拟空间的密度分布,被后续云的光照和渲染过程使用。相对于其他模拟方法来说,Dobashi的方法计算开销较小,却能产生的逼真的体积云的动画。这是我们选择此方法的主要原因。

pic1.GIF

图 1: Dobashi的单元自动控制模拟法【1】

•3.    我们的方案(solution)

我们的方案中,实时生成云图像的过程包括三个主要阶段:模拟,光照和渲染。模拟和光照在CPU上执行,渲染主要由GPU完成。模拟阶段采用Dobashi的单元自控法建模动态云,并产生云介质的密度分布;光照阶段计算光线透过云密度空间时云粒子的散射色。我们使用了Harris的光照模型,但在CPU而不是在GPU上实现相关算法;渲染阶段与Dobashi和Harris的实现类似,使用传统的公告板泼溅法渲染着色后的云粒子,合成最终的体积云。

我们基于以下考虑,建议使用基于CPU的方法实现模拟和光照:

•1.       在CPU上执行光照可避免Harris的方法中频繁地读回帧缓冲像素导致的性能瓶颈。

•2.       基于CPU的实现能减少云的渲染占用的GPU资源,降低了游戏对GPU的功能和性能要求,使PC游戏能兼容更广泛的显卡。

•3.       当前,多核平台是PC游戏运行的主流平台。但大多数游戏往往不能充分利用多核处理器中所有核的能力。那些游戏未使用的计算资源可被用于来处理和加速云的模拟和光照,从而尽可能降低云的渲染对游戏性能的影响。

图2显示了基于CPU的光照实现方法:

•1.       从太阳投射一条光线到云粒子上,沿着光线方向在云模拟空间产生几个采样点。

•2.       基于Harris的光照方程【2】一次计算每个采样点的入射光线强度,直到获得云粒子的入射光强度。在这个过程中,每个采样点的密度由它周围的网格单元的密度插值而成。

•3.       基于Harris的光照方程计算云粒子向视点方向散射的光线强度,把它作为渲染云粒子的颜色。

pic+2.GIF

图 2: 我们的光照实现方法

在实现了动态体积云的所有相关算法后,我们采用一种多线程框架渲染整个云景,并使用SSE指令优化单个云的模拟和光照性能。

•3.1多线程框架

我们的多线程框架分为两个层次。高层进行任务分解(task decomposition)。为了尽可能减少云对游戏性能的影响,我们把云景的模拟和光照阶段从游戏循环的主线程中分离出来,放到一个独立的云景线程中执行。云景的渲染保留在主线程中,和游戏场景的其他部分一起渲染,因为D3D并不建议把渲染任务放到不同的线程中执行。由于游戏中,云和光线的动态变化比较缓慢,因此云的模拟和光照并不需要每帧更新,也就说,主线程不需要每帧等待云景线程产生最新的数据,它可以反复使用先前计算好的数据进行渲染,然后在适当的同步时间获得新的数据。在这种方式下,云景线程的执行可以跨多个帧。主线程和云景线程之间的数据同步可以有多种方式,比如每隔几帧、几秒、或者当云景线程完成一次更新任务后再同步。最后一种方式又称为自由同步模式,这使主线程在执行过程中不会被云景线程中断,因此可以使主线程的性能接近渲染静态云时的性能。我们的方案缺省情况下使用这种同步方法。多线程框架的低层是在云景线程中采用Fork-Join的模式进行数据分解。由于游戏中的云景通常由多片云组成,每片云的模拟和光照计算是独立的,因此可以把每个云实例的更新任务作为一个分解的粒度,分别由不同的子线程并行执行。数据分解可进一步提高多核处理器的利用率,加快云景的更新速度。

我们的多线程框架使用一个基于Intel TBB(Threading Building Blocks)【6】的任务管理器和TBB的parallel_for结构来实现。TBB提供了用于并行编程的C++模板,使开发者能把注意力放在计算任务而不是线程细节上。多线程框架的伪代码如下图所示。

bool bSubmitNewTask = false;

if ( bFreeStepMode ){

bSubmitNewTask = pTaskManager->isJobDone();

}

else{

pTaskManager->waitUntilDone();

bSubmitNewTask = true;

}

if (bSubmitNewTask){

GetNewDataFromCloudScapeThread ();

pTaskManager->submitJob(CloudScapeThreadFunction);

}

......

for(int i=0; i< uNumClouds; i++ )

cloudArray[i].render();

图3: 主线程(游戏循环)中的伪代码

TaskManager管理云景线程和实现任务并行(图3)。模拟和光照计算包含在线程函数CloudScapeThreadFunction中,在适当的同步点被提交到云景线程执行。

tbb::parallel_for ( tbb::blocked_range<int>( 0, uNumClouds, uNumClouds/uNumThreads),

*pForLoopToUpdateClouds );

图 4: 云景线程函数中的TBB Parallel_for 结构

云景线程函数中的parallel_for结构实现了数据并行(图4)。这个结构把一个for循环的迭代平均划分到几个子线程中。for循环结构pForLoopToUpdateClouds包含实际的每个云的模拟和光照计算(图5)。

for(int i=range.begin(); i!= range.end(); i++ )

{

cloudArray[i].simulation();

cloudArray[i].illumination();

}

 

图 5: for循环结构中的云的模拟和光照

•3.2 SSE优化

体积云的模拟和光照计算是在一个三维网格表示的模拟空间中进行。计算模拟空间中的每个网格单元或采样点相关的属性值大多相互独立且具有相同的运算规则,因此这些采用点可以并行处理。我们已经在云的粒度上使用多线程进行优化,在采样点的粒度上,我们尝试使用SSE指令进行优化,这样能进一步利用处理器核的向量指令和几个128位的SSE寄存器的能力。

SSE指令可以改进媒体、图像和3D负载中向量计算的性能。开发者可以通过编译器intrinsics函数调用SSE指令。 本文中的所有SSE指令都以intrinsics的形式编码并使用Intel C++ Compiler 10.1进行编译,这样能使用最新的英特尔CPU的SSE指令。

我们首先使用VTune【4】找到热点函数,它们主要是光照函数以及它调用的密度求解函数。这些函数通过循环计算每个采样点的相关属性值:如密度、透明度、光强等。我们通过SSE的_mm_load_ss和_mm_insert_ps把4个采样点的相同属性打包到一些128位的SSE变量__m128中(图6)。比如,每个采样点的坐标属性有X/Y/Z三个分量,我们可以把每4个采样点的X分量打包到一个128位的SSE变量中(图6)。然后在这些打包的变量上进行一系列向量化操作:如_mm_mullo_epi32等;最后用_mm_extract_epi32和_mm_store_ps把变量中的结果存回到每个采用点中。SSE优化的细节请参见演示程序的源代码。SSE指令的使用说明请参Intel IA-32 开发者手册和Intel SSE4白皮书【5】。

pic6.GIF
图 6: 把每4个采样点的X属性打包到一个变量中

•4.    性能分析

为了实现和评估我们的方案,我们基于DirectX9开发了Luckycloud演示程序(图7)。演示程序显示了云景实时的演化过程。你可以使用方向键和鼠标移动摄像机,体验穿过云层的效果,和从不同的视角观察云的不同的散射颜色。

pic3.jpg

图 7: Luckycloud演示程序的截图

为了测试性能,场景中放置了16朵云覆盖天空,总计大约有6万云粒子被光照和渲染。我们在英特尔Core i7平台上测试,该平台有4个CPU核,每个核都支持SMT,因此我们能在操作系统上看到总共8个逻辑核。

我们首先比较了渲染静态云和渲染动态云的性能。我们通过演示程序界面的"暂停"控件关闭云的模拟和光照阶段,这样可以模拟静态云的渲染。我们发现,关闭和打开模拟和光照的情况下,帧速率都在90左右。这意味着在相同的渲染方法下,使用我们的方法渲染动态云能获得与渲染静态云近似的性能。其主要原因是:在我们的方案中,动态云的模拟和光照计算并不与游戏的主循环竞争CPU和GPU资源;相反,它利用了游戏没有使用到的多核资源来处理这些负载。

pic7.GIF
图 8: 多线程性能伸缩性以及锁步模式下的SSE优化性能

为了测试多核处理器上的云景更新任务的性能伸缩性,我们在锁步模式下(通过设置图3中 bFreeStepMode = false )运行演示程序,锁步模式每帧都会更新云景,因此帧速率能度量云景更新的频率。我们通过调整图4中parallel_for结构中的线程数,以及打开和关闭SSE代码测试程序的帧速率。图8中的测试结果显示:当线程数不多于CPU的核数时,我们的方案有良好的性能伸缩性。然而,SMT(8线程比4线程)的性能提升在我们的程序中并不明显,这意味着我们的方案无法从SMT中获得太多性能好处。对于SSE优化,测试结构显示在所有线程数下具有10%的稳定的性能提升。

•5.    总结和未来工作

本文提出了一种在游戏中生成动态体积云的方案。该方案在多核CPU端计算云模拟和光照,并使用多线程和SSE指令优化。该方案的好处能充分利用多核资源,使引入动态体积云对游戏性能的影响降到最低。在使用相同渲染方法的前提下,渲染动态云可达到与静态云接近的性能。从我们的方案中也可以得到一些启示:

•l  首先,多线程是多核平台上提高游戏性能的最佳方案。

•l  其次,可以利用多核CPU来实现游戏中的高级效果,特别对一些不需要每帧更新的复杂的计算任务,可以通过我们介绍的多线程方法利用游戏没有使用的多余计算资源来处理,而不会对游戏性能产生太多副作用。

未来的工作包括进一步优化渲染性能和实现更真实的体积云算法。目前,笔记本平台的发展非常迅速,将来很多玩家会在多核笔记本平台上玩游戏。为笔记本平台的集成显卡改进体积云渲染的负载是必要的。当前基于公告板泼溅法的渲染的主要问题是像素填充率很高,当游戏场景中有成千上万云粒子时,显卡填充率是主要瓶颈。Harris等使用imposter降低填充率,其他方法包括:使用可见性裁剪和LOD等技术,减少不必要的云粒子的渲染。采用基于光线投射(ray casting)的体积渲染术也能降低像素填充率,且能获得更精细的云结构,但这种技术会增加显卡着色器的负载,适用于支持3D纹理的性能较强的显卡。当未来处理器具有更多核时,我们方案中的体积云模拟和光照阶段可以用更复杂的算法替换--比如使用基于流体物理的模拟方法【3】和使用精度更高的散射模型的光照算法--用于渲染更真实的体积云图像。随着处理器核数的增加,我们的方法能模拟更精确和更真实的动态云。

参考资料

[1] Y. Dobashi, K. Kaneda, H. Yamashita, T. Okita, and T. Nishita. "A Simple, Efficient Method for Realistic Animation of Clouds".SIGGRAPH 2000, pp. 19-28

[2] M Harris and A Lastra. Real-time cloud rendering. InComputer Graphics Forum, volume 20, pages 76-84. Blackwell Publishers, 2001.

[3] Multi-Threaded Fluid Simulation for Games,http://software.intel.com/en-us/articles/multi-threaded-fluid-simulation-for-games/

[4] Intel VTune Performance Analyzer,http://www3.intel.com/cd/software/products/asmo-na/eng/239144.htm

[5] Intel SSE4 Whitepapers, 45nm Next Generation Intel® CoreT 2 Processor Family (Penryn) and Intel® Streaming SIMD Extensions 4 (Intel® SSE4)

[6] Threading Building Blocks,http://www.threadingbuildingblocks.org/

作者简介

郭胜 英特尔开发者关系部门的应用工程师,主要负责为游戏独立软件开发商(ISV)提供英特尔技术咨询和性能优化服务。他拥有南京大学计算机硕士学位,擅长实时 3D 图形应用的软件设计、编程以及性能优化。

吴晓昶

吴晓昶是英特尔软件与服务集团开发者关系部的应用工程师。他毕业于厦门大学计算机系,具有计算机科学硕士学位。于2006年加入英特尔,当前致力于利用最新的英特尔技术开发和优化创新的应用程序,同时面向独立软件开发商提供针对英特尔平台的性能优化技术咨询和解决方案。主要技术方向为多核技术,数字内容创建,多媒体和3D图形渲染的开发和优化技术。

卢卷彬 Cage Lu

Cage Lu joined Intel from 2005 as an Application Engineer in Developer Relations Division (DRD) under Intel Software and Services Group (SSG). He is working closely with software partners to introduce Intel new technologies, provide technical support and trainings. Cage has several years of software optimization experience, especially on online game clients. Cage graduated from Shanghai JiaoTong University in 2001 and got a Bachelor degree in Biomedical Engineering.