改进粒子系统-GPU实现

原创 2006年06月14日 23:02:00

改进粒子系统-GPU实现

作者:fannyfish

Bloghttp://blog.csdn.net/fannyfish

amma@zsws.org

介绍

       即时粒子系统的性能主要受两个因素制约:填充率(fillrate)、CPU-GPU之间的数据传输。填充率即GPU每帧可以渲染的象素数,当粒子很大并且出现好多粒子重叠在一起的情况时会明显影响性能(比如用粒子模拟大面积水雾,烟尘)。通常的做法是先在CPU上进行粒子的物理运算,然后将运算结果传输给GPU渲染。当粒子数目巨大时(如100000个),运算时间和CPU-GPU的传输时间,对即时演算来说都难以接受(比如用粒子模拟大面积雨雪)。

       我做的项目中使用了大量粒子:场景特效、打击特效、甚至界面特效,无处不在。目前的粒子系统使用CPU进行物理运算。再加上物理引擎、骨骼融合、游戏逻辑,CPU成为了系统瓶颈,游戏中每帧GPU都要等待一短时间,显卡越好CPU越差越明显。如何将CPU的物理物理运算转移到GPU上,达到负载均衡是优化的关键。

设计

状态无关(Stateless vs 状态相关(State-preserving

       1,状态无关是指粒子的数据运算,都只根据初始的位置,速度等属性来计算。

       2,状态相关是指粒子的数据运算,可以根据上个状态的位置,速度等属性来计算。

       GPU上处理状态相关的粒子系统,需要多张纹理存储粒子状态,对显卡的要求很高。

相反,状态无关的粒子系统对显卡要求低,实现相对简单,所以首先考虑实现这种粒子系统。

与原有粒子系统的关系

       使用原有的粒子系统分为如下几个步骤:

1,  美术通过编辑器创建粒子

2,  在编辑器中指定粒子的渲染器,发射器,效果器。其中渲染器负责创建删除粒子对应的渲染数据(Billboard,模型),并维护渲染相关的状态。包括Billboard渲染器, 模型渲染器, Billboard拖尾渲染器, 模型拖尾渲染器。

3,  客户端使用,反馈给美术调整。

GPU上处理粒子系统,将使用不同的渲染数据和状态,因此派生一个新的渲染器:Shader渲染器。这样上面的步骤不会变化,美术只需要熟悉渲染器的新参数。

渲染数据和状态

       在没有使用到的纹理坐标和颜色VertexBuffer上存储顶点的初始属性。包括位置,颜色,在一个粒子quad上的位置(UpOffset, LeftOffset),速度,生存期。

       设置常量寄存器,包括world-view-proj矩阵,眼睛的Right向量Up向量(用来和UpOffset, LeftOffset计算不同的面向摄像机方式),时间,加速度,颜色变化量。

实现

引擎渲染代码段:

const static D3DVERTEXELEMENT9 g_VertexElements[] =

{

       { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_POSITION, 0},

       { 1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD, 0},

       { 2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD, 1},

       { 3, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD, 2},     

       { 4, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_TEXCOORD, 3},     

       { 5, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,  D3DDECLUSAGE_COLOR,   0},

       D3DDECL_END()

};      

….

       m_pPositionVB = pDevice->CreateVertexBuffer( sizeof(v3dxVector3)*m_iVertexSize, m_pParent->m_dwVBUsage, m_pParent->m_Pool );

       m_pDiffuseVB = pDevice->CreateVertexBuffer( sizeof(DWORD)*m_iVertexSize, m_pParent->m_dwVBUsage, m_pParent->m_Pool );

       m_pTexCoordVB = pDevice->CreateVertexBuffer( sizeof(V3UV2)*m_iVertexSize, m_pParent->m_dwVBUsage, m_pParent->m_Pool );

       m_pTexCoordVB2 = pDevice->CreateVertexBuffer( sizeof(V3UV2)*m_iVertexSize, m_pParent->m_dwVBUsage, m_pParent->m_Pool );

       m_pTexCoordVB3 = pDevice->CreateVertexBuffer( sizeof(v3dxVector3)*m_iVertexSize, m_pParent->m_dwVBUsage, m_pParent->m_Pool );

       m_pIndexBuffer = pDevice->CreateIndexBuffer( sizeof(WORD)*m_iIndexSize, m_pParent->m_dwIBUsage, false, m_pParent->m_Pool );

填充粒子初始状态数据

 

       // 设置HLSL里的常量

       pEffect->SetMatrix("matWorldViewProj", (D3DXMATRIX *)&matTransformation);

       pEffect->SetVector("rightVector", &rightVector);

       pEffect->SetVector("upVector", &upVector);

       pEffect->SetVector("time_colour", &timeVec );

       pEffect->SetVector("acceleration", &acceleration );

       m_pDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST , 0, 0,pRenderer->m_iVertexSize, 0, pRenderer->m_iVertexSize/2 );

 

D3DFX代码:

struct VS_INPUT

{

    float3 Position                      : POSITION;   

    float2 Tex0                                 : TEXCOORD0;   

    float3 Tex1                                 : TEXCOORD1;    // UpOffset, LeftOffset, TotalTimeToLife

    float3 Tex2                                 : TEXCOORD2;    // Velocity

    float3 StartDiffuse                : COLOR0;           

};

 

struct VS_OUTPUT

{

    float4 Position                      : POSITION;

    float3 Diffuse                       : COLOR0;

    float2 Tex0                                 : TEXCOORD0;

};

 

matrix matWorldViewProj;                                               // world-view-proj matrix

float4 rightVector;                                                    // Right Vector

float4 upVector;                                                       // Up Vector

float4 time_colour;                                                  // Elasped Time, Delta Colour

float4 acceleration;       

 

VS_OUTPUT VS(const VS_INPUT Input)

{

    VS_OUTPUT    Out = (VS_OUTPUT) 0;

 

    // Position = right + up + pos;

    float4 right = rightVector * Input.Tex1.x;

    float4 up = upVector * Input.Tex1.y;

    float4 Pos = float4(Input.Position,0) + right + up;

 

    // Live Time = fmod( Elapsed Time, TotalTimeToLife )

    float fLiveTime = fmod(time_colour.x, Input.Tex1.z);

 

    // Position = Pos + vt + 1/2*v*t*t

    float4 deltaVel = mul( float4(Input.Tex2,0), fLiveTime);

    deltaVel = deltaVel + acceleration * fLiveTime * fLiveTime;

    //deltaVel.y = deltaVel.y + time_colour.z;

    Pos = Pos + deltaVel;

 

    Pos.w = 1.0;

    Out.Position = mul( Pos, matWorldViewProj );

 

    // color

       Out.Diffuse.x = Input.StartDiffuse.x + time_colour.y*fLiveTime;

    Out.Diffuse.y = Input.StartDiffuse.y + time_colour.z*fLiveTime;

    Out.Diffuse.z = Input.StartDiffuse.z + time_colour.w*fLiveTime;

 

    // texcoord

    Out.Tex0 = Input.Tex0;

 

    return Out;

}

 

technique tec0

{

    pass p0

    {

        VertexShader = compile vs_1_1 VS();

        PixelShader = NULL;

    }

}

编辑器中可调的属性

1, 默认高度

2, 默认宽度

3, 最大粒子数                    这里代表同时存在的粒子数

4, 粒子朝向

5, 面向摄像机的方式

6, 粒子UP向量          

7, 是否是2D粒子系统

发射器

8, 支持所有发射器和发射器特有属性(如圆环发射器的内环大小,外环大小)

9, 角度

10, 起始颜色

11, 结束颜色

12, 方向

13, 最小生存期

14, 最大生存期

15, 最小速度

16, 最大速度

17, 位置

效果器

18, 支持颜色衰减

19, 支持线性外力: "外力" 指加速度a, 满足公式s = vt + 1/2*a*t*t, 受力模式不起作用

截图

编辑器

1,point emitter, colour affector

2,box emitter, acceleration affector

其它

TODO

1,支持更多的Emitter, Affector. 根据粒子拥有的发射器,效果器类型动态编译不同的FX文件以减少运算量.(完成)

    http://blog.csdn.net/fannyfish/archive/2006/06/22/823032.aspx

 

2,支持State-Perspective粒子系统.(完成)

  http://blog.csdn.net/fannyfish/archive/2006/07/25/976753.aspx

3,排序,碰撞

4,支持设置粒子是相对世界坐标系还是本地坐标系

参考资料

1, [ShaderX3] Lutz Latta, Massively Parallel ParticleSystems on the GPU

2, [ShaderX2] O’dell Hicks, Screen-aligned Particles with Minimal VertexBuffer Locking

 

 

改进粒子系统-GPU实现

改进粒子系统-GPU实现 作者:fannyfish Blog:http://blog.csdn.net/fannyfish amma@zsws.org 介绍        即时粒子系统的...
  • pizi0475
  • pizi0475
  • 2015年08月07日 21:37
  • 1685

基于GPU的粒子系统

粒子系统通常要随着时间的推移来发射和销毁粒子。从表面上看,这一工作应该用动态顶点缓冲区来实现,并在CPU上生成和销毁粒子。然后,用当前存活的粒子来填充顶点缓冲区,并对其进行绘制。不过,我们在上一节讲过...
  • pizi0475
  • pizi0475
  • 2015年08月07日 21:39
  • 1649

Directx11基于GPU_GeometryShader的粒子系统

粒子系统作为在游戏中一个挺常见的技术,用在各种爆炸,下雨,火焰等特效中。我们利用GPU中的GeomtryShader来实现一个粒子系统。以下雨特效为例。     介绍粒子系统具体实现前先介绍下Geo...
  • qiul12345
  • qiul12345
  • 2011年11月23日 11:10
  • 1796

SIFT-GPU关于SaveSIFT函数的改进

SIFT-GPU是一个高效的进行SIFT特征提取和匹配的工具,是目前我用过的速度最快的工具。网址如下:http://www.cs.unc.edu/~ccwu/siftgpu/#lowesift 我在...
  • lhanchao
  • lhanchao
  • 2016年08月16日 16:03
  • 1527

移动平台粒子系统的实现原理

粒子系统在游戏中的应用可以说是非常常见。几乎每个游戏都会用到粒子系统。粒子系统可用来表现游戏中的各种效果,比如打斗的刀光剑影,飞船的尾气火焰等等。 其实一个简单粒子构成是由面片组成,在游戏渲染中多数粒...
  • wurh80
  • wurh80
  • 2017年09月12日 01:36
  • 157

Unity粒子系统特性

经代码测试分析,unity粒子系统 Shiruken粒子系统的可编程性比较差。所有的Modules都无法通过代码控制。 可以用ParticleSystem.SetParticles设置粒子,但是设...
  • mooniscrazy
  • mooniscrazy
  • 2014年03月28日 12:59
  • 1068

基于Direct3D实现简单的粒子系统

      这是一个基于D3D的基本的粒子系统,能够实现一些基本的效果,如:雨、雪、烟花等。代码很少,只有一个头文件和一个CPP文件,便于研究粒子系统的原理。EpParticleSystem.h:#i...
  • ntwilford
  • ntwilford
  • 2009年09月12日 07:41
  • 4121

粒子系统的简单实现

粒子系统说起来高深摸测,其实就是许多许多许多许多许多许多的点图象,然后对其进行运行速度,方向,衰减的处理。本文粒子系统的实现是基于图形API,OPenGL。语言是:C++。不可少的,先定义一些全局变量...
  • gameres
  • gameres
  • 2006年09月08日 14:47
  • 1422

OpenGL粒子系统详解及编程实现

粒子系统的基本思想是:采用许多形状简单的微小粒子作为基本元素,用它们来表示不规则模糊物体。这些粒子都有各自的生命周期,在系统中都要经历“产生” 、 “运动和生长”及“消亡”三个阶段。粒子系统是一个有“...
  • dcba2014
  • dcba2014
  • 2016年08月23日 14:23
  • 1871

UE4 粒子系统问题 no fixed bounding box

问题:“WARNING” this particle system has no fixed bounding box and contgains a GPU emitter 解决办法:在粒...
  • sh15285118586
  • sh15285118586
  • 2016年11月04日 00:41
  • 948
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:改进粒子系统-GPU实现
举报原因:
原因补充:

(最多只允许输入30个字)