粒子系统设计思想

用D3D8以后用点精灵来指定一个粒子,而不是D3D8以前的需要用公告板平面(四个顶点)来模拟一个粒子。

点精灵粒子的大小,纹理颜色,都可以用渲染状态来改变。粒子系统的渲染信息结构(位置和颜色)和粒子系统的属性(包括了位置和颜色变化、速度加速度和生命期),粒子属性会每帧更新且拷贝到粒子系统信息结构体渲染即可(不拷贝不需要那么多消息,拷贝了又会影响性能)。

1. 使用点精灵(一个顶点)和渲染状态技术

使用点精灵(一个顶点)和渲染状态技术来表现一个粒子位置,大小,纹理和颜色,而不是用老式的公告板平面(4个顶点)。

2.粒子的顶点缓存(没有索引缓存)放置在显存中,使用D3DUSAGE_DYNAMIC可以大幅提高读取更新性能

粒子的顶点缓存(没有索引缓存)放置在显存中,使用D3DUSAGE_DYNAMIC可以大幅提高读取更新性能,但是不能 用D3DPOOL_MANAGED,D3DLOCK_DISCARD和D3DLOCK_NOOVERWRITE只能在D3DUSAGE_DYNAMIC中 使用,且D3DLOCK_DISCARD可以满天过海避免同步可以有效的提高锁定性能。

3.粒子系统的更新、消亡内存管理和粒子阈值控制数量

粒子系统的更新、消亡内存管理和粒子阈值控制数量,每个子粒子系统都要维护自己的更新和重置函数,粒子消亡后可以通过不删掉内存而是重置的方式提高内存管理效率;且粒子系统需要一个粒子最大量的值,避免粒子的产生率比消亡率大,导致粒子膨胀。

4. 粒子系统分段渲染

粒子系统分段渲染,属性不断更新,拷贝到粒子顶点缓存进行渲染的方式,如果整个拷贝完再渲染会阻碍了CPU和GPU的协同工作效率,应该采用分段的思想来处理,也就是拷贝完一部分渲染一部分,粒子顶点缓存采用动态更新且放置到显存中提高效率,且锁定粒子顶点缓存时候用D3DLOCK_DISCARD和D3DLOCK_NOOVERWRITE方式避免同步提高效率。

粒子系统关键技术细节

1.点精灵相关的状态设置

void PSystem::preRender()

{

_device->SetRenderState(D3DRS_LIGHTING, false);

// 当为true时候点精灵的纹理来自一整个纹理,否则点精灵的纹理来自于顶点指定的uv纹理坐标映射的纹理,默认是false

_device->SetRenderState(D3DRS_POINTSPRITEENABLE, true);

//  true表示用视图空间单位来解释点的大小。视图空间单位的3D空间点在照相机中,点精灵将会自动缩放,

//  这取决到它有多远, 像其他对象一样,离照相机近的粒子比离照相机远的粒子要大。

// false 表示点的大小将用屏幕空间单位来解释。屏幕空间单位是屏幕上的像素单位。. 因此如果你指定false,

// 例如, 设置点精灵的尺寸为3, 则点精灵在屏幕区域中的尺寸为3×3像素。

_device->SetRenderState(D3DRS_POINTSCALEENABLE, true);

// 表示点精灵的尺寸. 这个值可以任意指定视图空间或屏幕空间的点精灵的尺寸, 取决于D3DRS_POINTSCALEENABLE状态如何设置

_device->SetRenderState(D3DRS_POINTSIZE, d3d::FtoDw(_size));

// 表示点精灵的最小尺寸

_device->SetRenderState(D3DRS_POINTSIZE_MIN, d3d::FtoDw(0.2f));

// 表示点精灵的最大尺寸

_device->SetRenderState(D3DRS_POINTSIZE_MAX, d3d::FtoDw(_size + 1));

// control the size of the particle relative to distance

// D3DRS_POINTSCALE_A, D3DRS_POINTSCALE_B, D3DRS_POINTSCALE_C

// 这3个常量表示如何根据距离控制点精灵的尺寸—这个距离是点精灵到照相机的距离。

// 公式是: FinalSize = PointSize * sqrt( 1 / ( A + B*D + C*D^2);再从MinSize, MaxSize,FinalSize中取得大小

// D是点精灵到视图空间原点的距离。

_device->SetRenderState(D3DRS_POINTSCALE_A, d3d::FtoDw(0.0f));

_device->SetRenderState(D3DRS_POINTSCALE_B, d3d::FtoDw(0.0f));

_device->SetRenderState(D3DRS_POINTSCALE_C, d3d::FtoDw(1.0f));

// use alpha from texture

// 为了启用遮罩的,也就是方形的粒子通过alpha融合使得粒子变为圆形的

_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);

_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);

_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

}

2. 粒子顶点缓存

bool PSystem::init(IDirect3DDevice9* device, char* texFileName)

{

// vertex buffer's size does not equal the number of particles in our system.  We

// use the vertex buffer to draw a portion of our particles at a time.  The arbitrary

// size we choose for the vertex buffer is specified by the _vbSize variable.

_device = device; // save a ptr to the device

HRESULT hr = 0;

// D3DUSAGE_DYNAMIC可以大幅提高读取更新性能,但是不能用D3DPOOL_MANAGED

// D3DLOCK_DISCARD和D3DLOCK_NOOVERWRITE只能在D3DUSAGE_DYNAMIC中使用,

// 且D3DLOCK_DISCARD可以满天过海避免同步可以有效的提高锁定性能。

hr = device->CreateVertexBuffer(

_vbSize * sizeof(Particle),

D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY,

Particle::FVF,

D3DPOOL_DEFAULT, // D3DPOOL_MANAGED can't be used with D3DUSAGE_DYNAMIC

&_vb,

0);

if(FAILED(hr))

{

::MessageBox(0, "CreateVertexBuffer() - FAILED", "PSystem", 0);

return false;

}

hr = D3DXCreateTextureFromFile(

device,

texFileName,

&_tex);

if(FAILED(hr))

{

::MessageBox(0, "D3DXCreateTextureFromFile() - FAILED", "PSystem", 0);

return false;

}

return true;

}

3.更新粒子和回收粒子

void Snow::resetParticle(Attribute* attribute)

{

attribute->_isAlive  = true;

// get random x, z coordinate for the position of the snow flake.

d3d::GetRandomVector(

&attribute->_position,

&_boundingBox._min,

&_boundingBox._max);

// no randomness for height (y-coordinate).  Snow flake

// always starts at the top of bounding box.

// 回收粒子到顶部

attribute->_position.y = _boundingBox._max.y;

// snow flakes fall downwards and slightly to the left

attribute->_velocity.x = d3d::GetRandomFloat(0.0f, 1.0f) * -3.0f;

attribute->_velocity.y = d3d::GetRandomFloat(0.0f, 1.0f) * -10.0f;

attribute->_velocity.z = 0.0f;

// white snow flake

attribute->_color = d3d::WHITE;

}

void Snow::update(float timeDelta)

{

std::list<Attribute>::iterator i;

for(i = _particles.begin(); i != _particles.end(); i++)

{

i->_position += i->_velocity * timeDelta;

// is the point outside bounds?

// 回收粒子到顶部

if( _boundingBox.isPointInside( i->_position ) == false )

{

// nope so kill it, but we want to recycle dead

// particles, so respawn it instead.

resetParticle( &(*i) );

}

}

}

4.分段拷贝和拷贝完成渲染机制,提高CPU和GPU的协同工作效率

void PSystem::render()

{

//

// Remarks:  The render method works by filling a section of the vertex buffer with data,

//           then we render that section.  While that section is rendering we lock a new

//           section and begin to fill that section.  Once that sections filled we render it.

//           This process continues until all the particles have been drawn.  The benifit

//           of this method is that we keep the video card and the CPU busy.

if( !_particles.empty() )

{

//

// set render states

//

preRender();

_device->SetTexture(0, _tex);

_device->SetFVF(Particle::FVF);

_device->SetStreamSource(0, _vb, 0, sizeof(Particle));

//

// render batches one by one

//

// start at beginning if we're at the end of the vb

if(_vbOffset >= _vbSize)

_vbOffset = 0;

Particle* v = 0;

// 锁定一个分段进行同时拷贝和分段完成进行渲染,如果是开始那么 D3DLOCK_DISCARD,否则追加数据

_vb->Lock(

_vbOffset    * sizeof( Particle ),

_vbBatchSize * sizeof( Particle ),

(void**)&v,

_vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);

DWORD numParticlesInBatch = 0;

//

// Until all particles have been rendered.

// 分段的填充和分段渲染,提高CPU和GPU的系统工作效率

// 丢弃只是针对顶点缓存说的

std::list<Attribute>::iterator i;

for(i = _particles.begin(); i != _particles.end(); i++)

{

if( i->_isAlive )

{

//

// Copy a batch of the living particles to the

// next vertex buffer segment

//

v->_position = i->_position;

v->_color    = (D3DCOLOR)i->_color;

v++; // next element;

numParticlesInBatch++; //increase batch counter

// if this batch full?

// 分段满了渲染

if(numParticlesInBatch == _vbBatchSize)

{

//

// Draw the last batch of particles that was

// copied to the vertex buffer.

//

_vb->Unlock();

_device->DrawPrimitive(

D3DPT_POINTLIST,

_vbOffset,

_vbBatchSize);

//

// While that batch is drawing, start filling the

// next batch with particles.

//

// move the offset to the start of the next batch

_vbOffset += _vbBatchSize;

// don't offset into memory thats outside the vb's range.

// If we're at the end, start at the beginning.

if(_vbOffset >= _vbSize)

_vbOffset = 0;

// 重新锁定后面或者回到开始的分段,同时进行拷贝和分段完进行渲染

_vb->Lock(

_vbOffset    * sizeof( Particle ),

_vbBatchSize * sizeof( Particle ),

(void**)&v,

_vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);

numParticlesInBatch = 0; // reset for new batch

}

}

}

_vb->Unlock();

// its possible that the LAST batch being filled never

// got rendered because the condition

// (numParticlesInBatch == _vbBatchSize) would not have

// been satisfied.  We draw the last partially filled batch now.

// 最后拷贝好的非整分段数量的缓存,直接进行渲染即可

if( numParticlesInBatch )

{

_device->DrawPrimitive(

D3DPT_POINTLIST,

_vbOffset,

numParticlesInBatch);

}

// next block

// 直接下一个分段的意思,用于下一帧到达进行

/*if(_vbOffset >= _vbSize)

_vbOffset = 0; */

// 判断,回到顶点缓存开头进行分段拷贝,和分段拷贝完成马上渲染

_vbOffset += _vbBatchSize;

//

// reset render states

//

// 重置渲染状态

postRender();

}

}

D3D粒子系统设计关键要点相关推荐

  1. 战略制定4大关键要点

    战略制定4大关键要点 原文地址: http://blog.sina.com.cn/u/4c081aa301000a5v [查看原文] 1.选择有持续竞争力的战略     对于那些能够给提供公司长远竞争 ...

  2. 自适应网站设计中的关键要点

    网站建设说难不难,说容易也不简单.但是对于一个刚入门的新手来说,要做一个网站,做好一个网站是有难度的.做网站入门确实是很简单,但是想要做的厉害就难了!你要学的东西很多,而且要学的很精.或许你会经常听到 ...

  3. 机器视觉系统设计关键:成像基准

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 1.导言 开发视觉系统的一个重要活动是验证其部署是否符合工程规范. ...

  4. 成为会带团队的技术人 稳定性(二):可用性治理的三个关键要点

    上一讲我们学习了事故的应急和复盘,但"预防胜于治疗",所以今天我想从事故预防的角度和你聊一聊可用性治理的关键动作. 可能你听过这样一句俗语:只有千日做贼,没有千日防贼.但是在系统稳 ...

  5. 打造百亿量级、亿级日活SDK的十大关键要点

    一个好的SDK应该具备易用性.稳定性.轻量.灵活的特点,而个推作为国内第三方推送市场的早期进入者,一直致力于为开发者提供高效稳定的推送SDK. 经过十年的深耕与创新,个推夯实了行业地位.截止2019年 ...

  6. ADP论文关键要点总结

    一. 离散化方法 1.1. 欧拉法 比较简单: 二. 传统车辆控制梳理总结(LQR+前馈控制) 2.1. LQR 比较简单 2.2. 前馈控制 具体方法 : 再用mathmatica进行化简即可得到前 ...

  7. 网站优化提升用户体验的三个关键要点

    众说周知,在我们优化网站的过程中用户体验这个环节至关紧要,而百度早已公开告知站长,近期调整的一系列算法都是以用户体验为目的.如果我们在用户体验的某些细节操作不当将会给网站带来很大的降权风险,但笔者认为 ...

  8. 设计模式 日志系统设计_模式:我们设计系统的故事

    设计模式 日志系统设计 Design Patterns are some of the most over-used concepts in design today. And we all know ...

  9. DDD不够好用,你需要学习如何进行弹性软件系统设计

    关键要点 当今的分布式系统环境必须采用弹性软件设计. 关键挑战不在于编码,而在于"外围". 做好分布式其实很难,大多数人都严重低估了它的难度. 恰当的功能设计是构建健壮的分布式系统 ...

最新文章

  1. UntraEdit 语法高亮 (MSSQL)
  2. c 运算符重载总结
  3. java调用WCF问题
  4. poe交换机标准与非标准的区别介绍
  5. 计算机启用时间 查找方式,电脑实用知识技巧 篇六:不需要第三方软件,这种方法查看系统启动时间...
  6. Ecipse快捷键的使用
  7. C++11 Primer Plus(三)之名称空间与类
  8. jenkins邮箱发送失败以及解决方案
  9. vsftpd虚拟用户
  10. ubuntu系统编译sh出错 默认dash不是bash
  11. 开关电源测试系统用哪个软件,开关电源测试系统
  12. C++基础知识(一) 键盘输入
  13. NLP系列(2)_用朴素贝叶斯进行文本分类(上)
  14. VAX Patch VA_X.DLL 安装位置的问题 for VS2008 , VS2010 , VS2011
  15. 不会写代码也可以, 手把手教你制作炫酷生日祝福网页(程序员专属情人节表白网站)
  16. win7怎么修改计算机皮肤,鼠标指针怎么换?小编教你win7系统更换鼠标指针皮肤的方法...
  17. DataGridViewCellStyle.Format 设置金额格式无作用解决方案
  18. 2072-歌手大奖赛
  19. 实现DevSecOps正确左移的宣言
  20. java闪光灯_手电筒项目开发一闪光灯

热门文章

  1. HDFS fsimage和edits中的文件信息查看
  2. 中北大学算法分析与设计实验报告一(BF算法)
  3. Treasure Project(藏宝计划)冲刺百倍!
  4. 启动weblogic 报错
  5. 【Dubbo实战】基础学习篇(一)
  6. 叠加等边三角形的绘制 python_《叠》字意思读音、组词解释及笔画数 - 新华字典 - 911查询...
  7. 超级照片美化技法:炫目的舞台光斑效果
  8. 【论文笔记】高维基因数据中的特征选择
  9. ProGet 22.0 Enterprise Crack by Xacker
  10. Python获取 当前目录、上一级目录