system: [SYSTEM]

user: 3. 基于GPU加速的改进型高流速尾焰仿真算法 针对传统方法的不足之处，本文提出了一种基于GPU加速的改进型算法。主要从几个方面进行改进：首先是构建了有利于渲染结果做进一步图像处理的粒子系统，这样方便对火焰在多气象条件下进行融合仿真。其次是简化了火焰粒子的控制方程，使其在高速喷射状态下不会呈现撕裂现象，并使用高斯噪声扰动火焰，使其真实感进一步提高。最后是改进了粒子的渲染算法，根据发动机的燃烧特性设计了热值衰变函数，使得尾焰的焰色贴近于真实发动机尾焰的焰色。接下来将对这三个方面进行详细阐述。 3.1. 使用GPU加速的粒子系统 在CPU中实现的粒子系统的一般思想是，首先设计单个粒子的数据结构，然后用额外的数据结构来组织管理这些粒子。每个粒子具有自己的属性诸如位置、速度、加速度、生命周期等等。在CPU中实现粒子系统有着鲜明的优缺点。优点是可以方便地实现常用的数据结构，如链表、树、散列表等等。因为在CPU中往往是串行执行运算程序，在更新粒子的时候一般也不用考虑并行带来的数据同步问题，缺点则是串行执行带来的效率过低问题。对于粒子系统而言，每个粒子在不考虑与其他粒子互相作用的前提下是具有高度并行特性的，因此为SIMD (单指令流多数据流)架构而设计的GPU是非常适合于实现粒子系统的。 CUDA是Nvidia公司于2006年推出的通用并行计算架构。目前已经广泛地应用于科学计算，粒子特效，流体模拟，通用计算加速等等领域 [ 7 ] 。CUDA可以方便地处理常见并行计算问题。CUDA的推出是因为使用传统的GPU加速计算的方法限制太大，必须将问题伪装成图形学问题以加入图形绘制管线进行并行计算，且输入输出的形式为纹理缓存，这大大限制了可用于GPU加速的问题域。但是本文所涉及的算法并没有以上限制，所以可以方便地使用传统图形绘制管线进行并行计算，且这样带来的好处是可以不用将硬件局限于Nvidia的显卡，从而减小了对硬件的要求。 实现本文中粒子系统的原理是将图形学中的“顶点”这一概念表示一个粒子。顶点上可以设置包括坐标、多重纹理坐标、颜色等属性，这些属性可以被用于保存粒子所需要的值。通过粒子运动计算管线得到一张纹理缓存用于保存粒子的位置信息。在渲染绘制管线中取到每个粒子的位置信息进行坐标转换，再对每个像素点进行渲染计算。 本文将粒子系统中的粒子转化为图形绘制管线中的“顶点”，所以预先定义好所需数目的顶点。然后初始化粒子的各个属性。把顶点的顶点坐标设置为对应纹理缓存的二维纹理坐标。这样做的目的是使得RTT (渲染到纹理)过程中，让每个顶点最后能输出到纹理缓存的对应位置。本文将顶点–几何–片元着色器这一绘制流程称为一个绘制流。在粒子运动计算这个过程交替执行两个相同算法的绘制流，这是因为用于保存粒子属性的纹理缓存既作为输入又作为输出，这在一些显卡中可能会导致不可预知的错误，因此使用两个绘制流轮流输出粒子属性纹理缓存。整个粒子系统的处理流程图如图1所示。 图1. 粒子系统的GPU并行计算过程 在CPU程序中会每一帧切换绘制流的输入纹理，即第n帧采用Textrue-Ping作为输入，第n + 1帧采用Texture-Pong作为输入。并将输出的颜色值保存到名为Scene Color Buffer的纹理对象中。因此这个尾焰的渲染结果将和场景渲染结果一起生成整个场景的图像，可以将尾焰的渲染结果和场景的渲染结果进行统一的图像处理，这样就保证了在使用一些基于图像处理的天气模拟算法(如雾、沙尘暴、雪、雨等)之后，尾焰的渲染效果能和场景保持一致。 本文将顶点坐标设置为纹理空间中的纹理坐标，这样做的原因是，为了保证粒子经过一个绘制流之后能将当前粒子的输出数据准确无误地保存到对应的纹理缓冲区中。下一个绘制流在对这个纹理进行纹理取样的时候就能取到对应粒子的数据。与此同时在多重纹理坐标中保存粒子的某些属性值，例如粒子的初始位置、生命周期等信息。 3.2. 尾焰粒子的喷射运动控制 除发动机尾部气体喷射的初始状态可以被近似地认为是层流而不是湍流。在尾焰的尾部一段距离后，由于周边气流的扰动，发动机尾部气流会快速形成湍流 [ 8 ] ，但是这部分湍流一般是不可见的，因此只需要模拟出可见部分的层流即可。 模拟层流意味着不需要复杂的粒子运动控制方程，粒子从发动机口线性运动到尾焰末端。为了模拟出发动机高速喷射的效果，本文使用高斯白噪声来扰动尾焰。因为高斯白噪声是一种理想的加性噪声，发动机尾焰的长度(FlameLength)总体上是在一个稳定的值附近无规则的上下波动，故可以使用高斯白噪声来扰动预设好的尾焰长度，让它每帧都产生随机变化。最后观测到的火焰喷射的效果实际上是由FlameLength每一帧的变化导致的，所有粒子之间的相对位置并没有变化，粒子的绝对位置会随着当前帧的FlameLength来进行调整。粒子的空间排列如图2所示。 图2. 粒子空间分布 一种快速生成高斯随机噪声的方法为：先在一定范围随机生成一个随机数，然后查找高斯分布映射表，以生成一组高斯噪声随机数 [ 9 ] 。本文中将使用一种更为便捷快速的方法。高斯白噪声的本质是一组均值为0且噪声幅值的概率满足正态分布(高斯分布)，因此只要生成一组随机数，使得这组随机数值的概率满足正态分布。在C++11中引入了正态分布模板类，它的本质是在计算一个随机变量x，在均值为μ，方差为σ情况下的概率密度函数。公式如下： P ( x | μ ， σ ) = 1 σ 2 π ⋅ e − ( x − μ ) 2 2 σ 2 (2) 在程序中只需要给定预设好的方差，并把均值设为0，配合使用C++标准库中的随机数生成器就可以方便的生成这样一组数据。对这组数据的采样过程不需要放到GPU中来进行，因为这个值对于所有粒子来说是统一的，所以只在CPU中每帧对这组数据逐次取样，最后将取样得到的值以uniform值的形式传给GPU。 3.3. 火焰粒子的渲染 本文渲染火焰粒子的方法为：在顶点着色器中对Ping-Pong Flow中输出的纹理进行采样，粒子坐标纹理采样值经过相机坐标系坐标变换和投影变换即得到用于输出的坐标。在几何着色器中将图元展开成一个四边形，以便于在片元着色器对这个张开的粒子进行贴图。纹理贴图如图3所示。 图3. 粒子纹理图 对这个纹理采样得到一个四维向量，只需要使用该向量的第四个分量，即颜色的透明度α值。在当前的片元着色器中，需要最终输出该像素的颜色值。尾焰从喷口到消失这一过程颜色变化主要体现在颜色的纯度变化，因此使用颜色值的透明度α的变化来体现尾焰温度的变化。可以近似地认为，透明度与火焰热度正相关。即温度越高，透明度α值越高，也即焰色纯度越高。 本文根据热流热度与距离函数图像的数值关系以及在实验中通过实验结果反复调整 [ 10 ] ，最终确定了α的计算函数，α的计算公式如下： α = k ⋅ P a r t i c a l T e x ⋅ ( 1 − D i s / F l a m e L e n g t h ) n (3) Dis是粒子和发动机喷口间的距离，FlameLength为尾焰长度，ParticleTex为粒子纹理图采样值。k和n为调节参数，该公式计算出来的α值总体上符合热值距离函数。由于粒子采样图是一个类似高斯函数的图像，这就意味着当前粒子最终α的空间函数图像虽然形状和其他粒子类似，但形状会越来越尖锐，体现在实验结果中的现象是火焰的尾部越来越尖，这也与热流密度关于平面位置的函数图像相契合。 在计算完α值之后，还需要计算颜色的RGB值，本文设计了一种色值衰变函数，在发动机喷口的火焰与焰尾的区别不只是透明度的差别，颜色也在改变。在喷口出火焰温度最高，颜色接近于白色，然后渐变成火焰的常态焰色。这个衰变过程与α的衰变过程略微不同。 a = c − ( c − b ) ⋅ ( 1 − D i s / F l a m e L e n g t h ) n (4) 发动机尾焰的颜色主要由燃料成分、发动机燃烧效率和喷口材质等因素有关。向量b为发动机预设的尾焰末端焰色值，c为最高温度颜色值，向量a为计算出来的当前像素点最终焰色。