文档章节

D3D中的粒子系统(2)

rise-worlds
 rise-worlds
发布于 2016/06/20 13:38
字数 1775
阅读 0
收藏 0

14.2粒子系统的组成

粒子系统是粒子的集合,用来保存和显示这些粒子。粒子系统维护所有粒子的全部属性,影响系统中的所有粒子:粒子的尺寸,起始的位置及应用在粒子上的纹理等。粒子系统的方法负责更新、显示、杀死和创建粒子。

虽然不同的具体(与抽象是相对的)粒子系统有不同的行为,我们归纳并找到一些所有的粒子系统共有的基本属性,我们把这些公共的属性放到一个抽象的cParticleSystem基类,它是我们所有的具体粒子系统的父类,现在让我们看一下cParticleSystem类:
    class cParticleSystem
    {
    protected:
        IDirect3DDevice9*            m_device;
        D3DXVECTOR3                    m_origin;
        cBoundingBox                m_bounding_box;
        float                        m_emit_rate;        // rate new particles are added to system
        float                        m_size;                // size of particles
            IDirect3DTexture9*            m_texture;
        IDirect3DVertexBuffer9*     m_vertex_buffer;
        list<sParticleAttribute>    m_particles;
        int                            m_max_particles;    // max allowed particles system can have
        // following three data elements used for rendering the particle system efficiently
        DWORD    m_vb_num;        // particle number in vertex buffer
        DWORD    m_vb_offset;    // offset in vertex buffer to lock
        DWORD    m_vb_batch_num;    // number of vertices to lock starting at m_vb_offset
    public:
        cParticleSystem();
        virtual ~cParticleSystem();
        virtual bool init(IDirect3DDevice9*    device, const char* texture_filename);
        virtual void reset();
        // sometimes we don't want to free the memory of a dead particle, but rather respawn it instead.
        virtual void reset_particle(sParticleAttribute* particl_attr) = 0;
        virtual void add_particle();
        virtual void update(float time_delta) = 0;
        virtual void pre_render();
        virtual void render();
        virtual void post_render();
        bool is_empty();
        bool is_dead();
    protected:
        virtual void remove_dead_particles();
    };

一些数据成员:

·        m_origin—粒子系统的原点, 这是粒子系统产生时的位置。

·        m_bounding_box—创建粒子系统使用的边界盒,用于限制粒子的活动范围。例如,假如我们让雪系统只落在一个围绕高山的峰顶的体积内,我们会定义一个包括这个体积的边界盒, 出界的粒子将会被杀死。

·        m_emit_rate—新增加到系统中的粒子的速度。通常的标准是每秒。

·        m_size—系统中所有粒子的尺寸。

·        m_particles—系统中粒子属性的一个列表。 我们用这个列表创建,释放及更新粒子。 当我们准备画粒子时, 我们COPY列表节点的一部分到顶点缓存并画粒子,同时我们COPY另外一批粒子,然后重复这一过程直到绘制完所有粒子。

·        m_max_particles—在给定的时间内,系统中允许的粒子最大数。例如,如果创建粒子的速度比释放快的话, 随着时间的增长粒子的数量将会是巨大的,这个成员将避免出现这样的问题。

·        m_vb_num—在给定的时间内顶点缓存中能够保存的粒子的数量,这个值与实际的粒子系统中的粒子数量无关。

注意:m_vb_offset和m_vb_batch_num数据成员在渲染粒子系统时使用,我们在稍后讨论。

方法:

cParticleSystem/ ~cParticleSystem—用来初始化默认值和用来释放设备接口 (vertex buffer, texture)。
    cParticleSystem::cParticleSystem()
    {
        m_device        = NULL;
        m_vertex_buffer = NULL;
        m_texture        = NULL;
    }
    cParticleSystem::~cParticleSystem()
    {
        safe_release<IDirect3DVertexBuffer9*>(m_vertex_buffer);
        safe_release<IDirect3DTexture9*>(m_texture);
    }

init—这个方法做与设备无关的初始化工作,比如创建用来保存点精灵的顶点缓存或创建纹理。
    bool cParticleSystem::init(IDirect3DDevice9* device, const char* texture_filename)
    {
        // Vertex buffer's number 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 number we choose for the vertex buffer is specified by the m_vb_num variable.
        m_device = device;
        HRESULT hr;
        hr = device->CreateVertexBuffer(
                m_vb_num * sizeof(sParticle),
                D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY,
                PARTICLE_FVF,
                D3DPOOL_DEFAULT,    // D3DPOOL_MANAGED can't be used with D3DUSAGE_DYNAMIC
                &m_vertex_buffer,
                NULL);
        if(FAILED(hr))
        {
            MessageBox(NULL, "CreateVertexBuffer() - FAILED", "ParticleSystem", MB_OK);
            return false;
        }
        hr = D3DXCreateTextureFromFile(device, texture_filename, &m_texture);
        if(FAILED(hr))
        {
            MessageBox(NULL, "D3DXCreateTextureFromFile() - FAILED", "ParticleSystem", MB_OK);
            return false;
        }
        return true;
    }

o       注意: 我们使用动态的顶点缓存(D3DUSAGE DYNAMIC)。 因为我们需要在每帧中更新我们的粒子,意思是我们将会去存取顶点缓存的内存,回想一下,访问一个静态的顶点缓存慢得不可接受, 所以我们使用动态的顶点缓存。

o       查看我们用过的 D3DUSAGE_POINTS标记,它说明顶点缓存将保存点精灵。

o       顶点缓存的尺寸是由m_vb_num预先确定的,而且与系统中粒子的数量无关。 也就是说, m_vb_num将小于等于系统中粒子的数量。 这是因为渲染粒子系统是一批一批的,不是一次渲染全部。

o       我们使用默认的内存池(pool)代替通常使用的托管内存池,因为动态顶点缓存不能用在托管内存池中。

reset—这个方法重新设置系统中每个粒子的属性:
    void cParticleSystem::reset()
    {
        for(list<sParticleAttribute>::iterator iter = m_particles.begin(); iter != m_particles.end(); iter++)
            reset_particle(&(*iter));
    }

reset_particle—这个方法重新设置粒子的属性。如何重设粒子的属性,这依赖于具体粒子系统的特性。因此我们定义这个方法为虚拟的,等待子类去实现。

add_particle—这个方法用来在系统中增加一个粒子。在增加它到粒子列表之前,使用reset_particle方法先初始化粒子:
    void cParticleSystem::add_particle()
    {
        sParticleAttribute attr;
        reset_particle(&attr);
        m_particles.push_back(attr);
    }

update—这个方法更新系统中所有的粒子。因为这个的方法的执行取决于具体粒子系统的特性,因此我们定义这个方法为抽象的,等待子类去实现。

render—这个方法用来显示系统中所有的粒子。

pre_render—用它来初始化渲染状态,在渲染前设置。 因为系统与系统之间是不同的,所以我们定义它为虚拟的。 默认将执行下列代码:
    void cParticleSystem::pre_render()
    {
        m_device->SetRenderState(D3DRS_LIGHTING,          FALSE);
        m_device->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
        m_device->SetRenderState(D3DRS_POINTSCALEENABLE,  TRUE);
        m_device->SetRenderState(D3DRS_POINTSIZE,          float_to_dword(m_size));
        m_device->SetRenderState(D3DRS_POINTSIZE_MIN,      float_to_dword(0.0f));
        // control the size of the particle relative to distance
            m_device->SetRenderState(D3DRS_POINTSCALE_A,    float_to_dword(0.0f));
        m_device->SetRenderState(D3DRS_POINTSCALE_B,    float_to_dword(0.0f));
        m_device->SetRenderState(D3DRS_POINTSCALE_C,    float_to_dword(1.0f));
        // use alpha from texture
            m_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
        m_device->SetTextureStageState(0, D3DTSS_ALPHAOP,    D3DTOP_SELECTARG1);
        m_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
        m_device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);
        m_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    }

  注意:我们使用alpha混合渲染,以便设置纹理的alpha通道,来设置纹理像素的透明,用它产生多种效果。一种特殊的情况是:获得象纹理那样的非矩形的粒子。例如,获得一个圆形“雪球形”的粒子,我们使用一个简单的带有alpha通道的纹理,它看上去是背景为黑色的带有白色圆形的样子。因此,显示出来时只是一个白圆,这比白色的矩形纹理要好。

post_render—用它去保存所有渲染状态。因为系统与系统间是不同的,所以我们定义它为虚拟的。默认将执行下列代码:
    void cParticleSystem::post_render()
    {
        m_device->SetRenderState(D3DRS_LIGHTING, TRUE);
        m_device->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
        m_device->SetRenderState(D3DRS_POINTSCALEENABLE,  FALSE);
        m_device->SetRenderState(D3DRS_ALPHABLENDENABLE,  FALSE);
    }

is_empty—如果为True则在当前的系统中没有粒子, 否则为false.
    bool cParticleSystem::is_empty()
    {
        return m_particles.empty();
    }

is_dead—如果为True则系统中的所有粒子都是死的,否则为false。
    bool cParticleSystem::is_dead()
    {
        for(list<sParticleAttribute>::iterator iter = m_particles.begin(); iter != m_particles.end(); iter++)
        {
            // Is there at least one living particle? If yes, the system is not dead.
            if(iter->is_alive)
                return false;
        }
        // No living particles found, the system must be dead.
        return true;
    }

remove_dead_particles—搜索属_particle性表,从表中杀死并删除粒子。
    void cParticleSystem::remove_dead_particles()
    {
        list<sParticleAttribute>::iterator iter = m_particles.begin();
        while(iter != m_particles.end())
        {       
            if(! iter->is_alive)
                // erase returns the next iterator, so no need to increment to the next one ourseleves.
                    iter = m_particles.erase(iter);
            else
                iter++;    // next in list
        }
    }

本文转载自:http://www.cnblogs.com/flying_bat/archive/2008/04/04/1137668.html

rise-worlds

rise-worlds

粉丝 2
博文 1755
码字总数 0
作品 0
深圳
程序员
私信 提问
盈趣上海众多游戏技术岗位火热招募中

职位一:C/C++客户端开发工程师 工作职责: 1.负责MTK平台游戏客户端主要模块的开发 2.负责游戏客户端与服务器端的交互 3.负责客户端代码的整合及优化 职位要求: 1. 1年以上MTK平台游戏开发...

yuer150
2011/04/26
366
3
盈趣信息技术上海有限公司众多技术岗位招募中

职位一:C/C++客户端开发工程师 工作职责: 1.负责MTK平台游戏客户端主要模块的开发 2.负责游戏客户端与服务器端的交互 3.负责客户端代码的整合及优化 职位要求: 1. 1年以上MTK平台游戏开发经验...

yuer150
2011/05/02
1K
0
Unreal中的烟雾火焰流体模拟

版权声明:本文所有文章均为原创,原文链接:blog.uwa4d.com,如需转载请联系support@uwa4d.com https://blog.csdn.net/UWA4D/article/details/86649505 【博物纳新】是UWA旨在为开发者推荐新...

UWA
01/29
0
0
3D游戏引擎--Irrlicht

Irrlicht是一个3D游戏引擎。它具有高效,实时等特点,是个完全跨平台的引擎,使用D3D、OpenGL和它的自己的渲染程序。支持动态的阴影,粒子系统,角色动画,室内和室外技术以及碰撞检测等。 更多...

匿名
2008/12/06
40.7K
0
​Unity 游戏开发技巧集锦之使用忍者飞镖创建粒子效果

Unity 游戏开发技巧集锦之使用忍者飞镖创建粒子效果 使用忍者飞镖创建粒子效果 游戏中,诸如烟、火、水滴、落叶等粒子效果,都可以使用粒子系统(particle system)来实现。例如,《明朝传奇...

大学霸
2015/09/09
236
0

没有更多内容

加载失败,请刷新页面

加载更多

聚合与组合的关系

作者总结的很好 http://www.360doc.com/content/07/0612/11/16903_553244.shtml

南桥北木
6分钟前
0
0
好程序员web前端分享DIV+CSS3和html5+CSS3有什么区别

好程序员web前端分享DIV+CSS3和html5+CSS3有什么区别,不管是DIV+CSS3还是html5+CSS3,他们都是我们对网页开发布局方式的统称,但是DIV+CSS3作为网页的基础开发这句话其实并不严谨,因为而d...

好程序员IT
12分钟前
0
0
比特币应用开发10大必备NuGet包

如果要在.NET环境下开发比特币应用,本文列出的10个NuGet开发包是你不可或缺的利器。 如果要快速掌握.NET平台下比特币的应用开发,推荐访问汇智网的课程: C#比特币开发详解 1、NBitcoin C#...

汇智网教程
13分钟前
0
0
Debian 10 Buster发布的新功能

Debian 10 Buster即将发布。第一个候选版本已经出局,我们应该会在几周内看到最终版本。 Debian 10 Buster发布时间表 Debian 10 Buster没有设定的发布日期。为什么会这样?与其他发行版不同,...

叫我甘道夫
23分钟前
2
0
从入侵到变现——“黑洞”下的黑帽SEO分析

概述 由于互联网入口流量主要被搜索引擎占据,网站在搜索引擎中的排名直接影响到市场营销效果,因此SEO服务应运而生。SEO(Search Engine Optimization)全称为搜索引擎优化,是指利用搜索引擎...

zhaowei121
25分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部