改进粒子系统-GPU实现

作者:fannyfish

Blog:http://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实现相关推荐

  1. (转)从CPU架构和技术的演变看GPU未来发展

    泡泡网显卡频道5月28日 自从AMD提出Fusion(融聚)的概念.NVIDIA加大力度推广GPU通用计算.Intel率先将CPU和GPU整合在一起之后,大家就会发现CPU和GPU从没如此亲密无间过, ...

  2. GPU通用计算调研报告

    摘要:NVIDIA公司在1999年发布GeForce256时首先提出GPU(图形处理器)的概念,随后大量复杂的应用需求促使整个产业蓬勃发展至今.GPU在这十多年的演变过程中,我们看到GPU从最初帮助C ...

  3. 基于c++ amp的gpu编程

    目录 摘要: 1 简介 2 性能改进 2.1 异构平台 2.2 gpu架构 2.3 通过平行的性能改进 3 gpu编程架构 3.1 opencl 3.2 cdua 3.3 c++ amp 4 一个c+ ...

  4. Unity2018.1中文更新日志速览版

    本文首发于洪流学堂微信公众号. 洪流学堂,学Unity快人几步 Unity2018.1已经正式发布,快来看看一些核心新功能吧! 可编程脚本渲染管线 Unity 2018.1中引入的Scriptable ...

  5. Unity 5.6正式版发布,Unity 2017即将来临

    最新版Unity 5.6正式发布,也是Unity 5.x系列的最后一个版本.其中包括改进的2D功能,更好的图形性能,新的视频播放器,Progressive Lightmapper预览版,新的光照模式, ...

  6. Unigine 2.8 更新内容

    UNIGINE 2.8:改进的数据流,缓存阴影,重构编辑器,更好的植被 2019-04-30 主要变化 重新设计的异步数据流以降低性能峰值. 提高了整个引擎中多个CPU核心的利用率. UnigineE ...

  7. CUDA 11功能清单

    CUDA 11功能清单 基于NVIDIA Ampere GPU架构的新型NVIDIA A100 GPU在加速计算方面实现了最大的飞跃.A100 GPU具有革命性的硬件功能,CUDA 11与A100一起 ...

  8. 病虫害模型算法_基于深度学习的目标检测算法综述

    sigai 基于深度学习的目标检测算法综述 导言 目标检测的任务是找出图像中所有感兴趣的目标(物体),确定它们的位置和大小,是机器视觉领域的核心问题之一.由于各类物体有不同的外观,形状,姿态,加上成像 ...

  9. AI综述专栏 | 基于深度学习的目标检测算法综述

    https://www.toutiao.com/a6685618909275488780/ 2019-04-30 17:35:53 关注微信公众号:人工智能前沿讲习, 重磅干货,第一时间送达 AI综述 ...

最新文章

  1. 17 个品牌,113 款 5G 手机,5G 离我们越来越近
  2. 关于动态规划与备忘录方法的总结
  3. 022_Vue购物车
  4. lvs之 lvs原理架构介绍
  5. python慢在哪里_求大神分析一下我的python脚本慢在哪里?
  6. Python 测试开发教程
  7. linux 环境下配置ftp服务器
  8. swift编写命令行工具
  9. 后端:Java中如何更优雅的处理空值,看完你就懂了!
  10. javascript-复制
  11. 外星人电脑为什么那么贵_为什么系统门窗那么贵?
  12. 【宝藏系列】如何解决word选中文字按backspace无法删除的问题
  13. 那个卖了房子去大理的姑娘,4个月后又回来了
  14. FPGA实现数字识别
  15. html5 3d引擎 星空,使用3D引擎threeJS实现星空粒子移动效果
  16. 有关数据的“那些事儿”,百度云发声啦!
  17. 臭鱼的产品交互设计分享
  18. 控件:TextView
  19. UVA 1471 Defense Lines 防线
  20. Spring(https://www.zhihu.com/question/38597960)

热门文章

  1. uc的剪切板能关掉吗_创意手工 | 一张纸折出专属礼品袋,漂亮简单还实用!你爱了吗?!...
  2. java 链表 最小堆优先级队列_Java集合细说
  3. 没网可以用python吗_在没有网络的情况下能自学python吗?
  4. c# mysql 时间_c# – 无法在VS2010中将MySQL日期/时间值转换为System.DateTime
  5. android git 版本管理,Android版本管理(git 和 repo)
  6. 不安装oracle使用exp命令
  7. 点乘 线性代数_如果看了这些还不懂线性代数,你就来锤我和广坤
  8. c语言对c99标准声明,C语言中C89与C99的区别
  9. Uncaught ReferenceError: FileAsyncWriter is not defined
  10. 导入maven项目报错无法运行