改进粒子系统-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上大规模粒子系统的Dx9实现细节总结

GPU上大规模粒子系统的Dx9实现细节总结 转自我们的博客http://www.xiaomingjia.com/?p=51 GPU上的粒子系统在DX10上的实现已经不是什么新鲜事了。考虑到公...
  • itlmy
  • itlmy
  • 2011年10月08日 22:24
  • 580

Directx11基于GPU_GeometryShader的粒子系统

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

初试PyOpenGL四 (Python+OpenGL)GPU粒子系统与基本碰撞

在初试PyOpenGL一 (Python+OpenGL)讲解Pyopengl环境搭建,网格,球体,第一与第三人称摄像机的实现。在初试PyOpenGL二 (Python+OpenGL)基本地形生...

粒子系统实现火焰效果

  • 2015年06月23日 21:59
  • 620KB
  • 下载

cocos2d-x改进的粒子系统和编辑器(需求分析)

先声明,以我对游戏引擎的理解和对图形学的熟悉程度,这篇文章更多的只是臆想和明确方向。我对能否完成它并不抱太大的期望。不过很多时候知道了方向,那么后面就可以一步一步的去完成它,有时候现在感觉很困难的东西...

粒子系统的实现

  • 2008年07月02日 08:30
  • 49KB
  • 下载

Unity3D 粒子系统实现一个简单的爆炸效果

Unity3D 爆炸效果 粒子系统
  • six_sex
  • six_sex
  • 2017年06月04日 09:39
  • 4344

简单的粒子系统实现

  • 2017年04月14日 19:20
  • 4.27MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:改进粒子系统-GPU实现
举报原因:
原因补充:

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