|  | 
 
 
 楼主|
发表于 2013-12-2 21:46:25
|
显示全部楼层 
| 【实例4-2】火焰粒子类 下面是这个例题中完整的火焰粒子类的代码。a 火焰粒子类头文件 a 火焰粒子类源文件复制代码//=============================================================================
//Desc: CFirePartile.h
//=============================================================================
#pragma once
#include "d3dx9.h"
#include "Utility.h"
#include <vector>
#include <list>
using namespace std;
#define  PARTICLENUM_FIRE  30
//顶点结构
struct CUSTOMVERTEX_PARTICLE
{
    D3DXVECTOR3  Position;        //位置
    D3DCOLOR     color;           //颜色
};
#define D3DFVF_CUSTOMEVERTEX_PARTICLE ( D3DFVF_XYZ | D3DFVF_DIFFUSE )
struct CParticle
{
    float m_fWidth;                    //宽度
    float m_fHeight;                   //高度
    bool m_bOwnDimension;            //是否可控制粒子大小
    DWORD m_Color;                 //当前颜色(通常指顶点颜色)
    D3DXVECTOR3 m_vPosition;       //位置
    D3DXVECTOR3 m_vDirection;      //方向(有长度的方向,包含速度)
    float m_fTimeToLive;               //剩余生命
    float m_fTotalTimeToLive;           //生命周期
    float m_fRotation;                  //当前的旋转弧度
    float m_fSpeed;                    //速度
};
class CFirePartile
{
public:
    CFirePartile(void);
    ~CFirePartile(void);
    typedef std::list<CParticle*> ParticleActiveList;    //定义存活粒子链表类型
    typedef std::list<CParticle*> ParticleFreeList;      //定义空闲粒子链表类型
    ParticleActiveList m_ActiveParticles;            //粒子池中已被使用的粒子对象
    ParticleFreeList m_FreeParticles;                //粒子池中未被使用的粒子对象
  UINT m_uiMaxNumVertices; 
    HRESULT Init( LPDIRECT3DDEVICE9 pDevice ); //初始化
    void Update( float fElapsedTime); //更新粒子
    void Render(); //设置合适的渲染状态,渲染粒子
protected:
    LPDIRECT3DVERTEXBUFFER9     m_pVB;            //顶点缓冲区
    LPDIRECT3DTEXTURE9           m_pTexture;         //纹理对象    
    LPDIRECT3DDEVICE9             m_pd3dDevice ;      //设备
    float        m_fSize;                      //粒子火焰大小
    bool        m_bDeviceSupportsPSIZE;       //是否支持点精灵改变大小
    //粒子的生命周期由“最小生命值”和“最大生命值”之间的随机值决定
    float        m_fMinTTL;                   //最小生命值
    float        m_fMaxTTL;                   //最大生命值    
    //粒子的速率由“最小速度”和“最大速度”之间的随机值决定
    float m_fMinSpeed;    
    float m_fMaxSpeed;
    //创建缓冲区    
    void CreateBuffers();    
    //创建粒子
    CParticle*  CreateParticle();
    ParticleActiveList::iterator DeleteParticle( ParticleActiveList::iterator &i );
    //释放函数
    void FreeData();
};
a 项目主文件复制代码//=============================================================================
//Desc: CFirePartile.cpp
//=============================================================================
#include ".\firepartile.h"
CFirePartile::CFirePartile(void)
{
    m_uiMaxNumVertices = 2048;
    m_fSize= 5.0f;
    m_fMinTTL = 10.0f;
    m_fMaxTTL = 20.0f;
    m_fMinSpeed = 6.f;
    m_fMaxSpeed = 8.5f;
}
CFirePartile::~CFirePartile(void)
{
    FreeData();
}
void CFirePartile::FreeData()
{
  //释放激活链表中可能存在的数据
    ParticleActiveList::iterator iACur = m_ActiveParticles.begin();
    ParticleActiveList::iterator iAEnd = m_ActiveParticles.end();
    for(; iACur!=iAEnd; iACur++)
    {
        SAFE_DELETE((*iACur));
    }
  //释放空闲链表中可能存在的数据
    ParticleFreeList::iterator iFCur = m_FreeParticles.begin();
    ParticleFreeList::iterator iFEnd = m_FreeParticles.end();
    for(; iFCur!=iFEnd; iFCur++)
    {
        SAFE_DELETE((*iFCur));
    }
    m_ActiveParticles.clear();
    m_FreeParticles.clear();
    //释放顶点、索引缓冲区
    SAFE_RELEASE( m_pVB );
    //释放纹理
    SAFE_RELEASE( m_pTexture );
}
HRESULT CFirePartile::Init( LPDIRECT3DDEVICE9 pDevice )
{
    if(pDevice)
        m_pd3dDevice = pDevice;
    //创建粒子
    CreateBuffers();
    //获取最大值
    D3DCAPS9 d3dCaps;
    m_pd3dDevice->GetDeviceCaps(&d3dCaps);
    //检查是否支持点精灵粒子尺寸更改
    if (d3dCaps.FVFCaps & D3DFVFCAPS_PSIZE)
    {
        m_bDeviceSupportsPSIZE = true;
    }
    else
    {
        m_bDeviceSupportsPSIZE = false;
        return E_FAIL;
    }
    //创建火焰效果纹理
    if( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, "fire.tga", &m_pTexture ))) 
     return E_FAIL;
    //初始化粒子空闲链表
    for(int i=0; i<PARTICLENUM_FIRE; i++)
    {
        CParticle * pPar =  new CParticle;
        m_FreeParticles.push_back( pPar );
    }
    return S_OK;
}
void CFirePartile::CreateBuffers()
{
    //创建点精灵粒子顶点缓冲区
    if( FAILED( m_pd3dDevice->CreateVertexBuffer( 
        m_uiMaxNumVertices * sizeof(CUSTOMVERTEX_PARTICLE), 
        D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY | D3DUSAGE_POINTS, 
        D3DFVF_CUSTOMEVERTEX_PARTICLE, 
        D3DPOOL_DEFAULT, 
        &m_pVB, NULL )))
    {
        MessageBox(NULL,"顶点缓冲创建失败!","错误",MB_OK);
    }
}
CParticle*  CFirePartile::CreateParticle()
{
    //检查空闲粒子链表是否为空
    if( m_FreeParticles.empty() )
    {
        return NULL;
    }
    //从空闲链表中取出头一个,放入存活链表
    CParticle *p = m_FreeParticles.front();
  //使用到std::list的splice方法,功能:将源链表中的指定数据插入目标链表的指定位置
  //并从源链表中删除该数据
    m_ActiveParticles.splice( m_ActiveParticles.end(), m_FreeParticles, m_FreeParticles.begin() );
    //给粒子一个随机速度,随机生命以及向上的方向
    p->m_fSpeed = GetRandomMinMax(m_fMinSpeed,m_fMaxSpeed);
    p->m_fTotalTimeToLive    = GetRandomMinMax(m_fMinTTL,m_fMaxTTL);
    p->m_vDirection.x = 0.0f; 
    p->m_vDirection.y = 1.0f; 
    p->m_vDirection.z = 0.0f; 
    return p;
}
void CFirePartile::Update( float fElapsedTime)
{
    CUSTOMVERTEX_PARTICLE *pVertices;
    //如果当前的粒子生命已经大于生命周期,则被移到空闲粒子链表
    ParticleActiveList::iterator iCur = m_ActiveParticles.begin();
    ParticleActiveList::iterator iEnd = m_ActiveParticles.end();
    for( ; iCur != iEnd; )
    {
        if((*iCur)->m_fTotalTimeToLive < 0 )
        {
            iCur = DeleteParticle( iCur );    //删除到空闲链表,并返回下一个数据指针
        }
        else
        {
            (*iCur)->m_fTotalTimeToLive -= 1.0;    //递减存活时间
            ++iCur;    //指向下一个粒子
        }
    }
    //如果粒子数小于当前最大粒子数,则补充新的粒子
    if(m_ActiveParticles.size()<PARTICLENUM_FIRE)
    {
        CParticle * pPar =  CreateParticle();
        pPar->m_vPosition.x = GetRandomMinMax(1,2);
        pPar->m_vPosition.y = GetRandomMinMax(0,0);
        pPar->m_vPosition.z = GetRandomMinMax(0,1);
    }
    //重新定向迭代器
    iCur = m_ActiveParticles.begin();
    iEnd = m_ActiveParticles.end();
    //更新缓冲区中粒子的位置属性
    if( FAILED( m_pVB->Lock(0, //给偏移加锁
        PARTICLENUM_FIRE * sizeof(CUSTOMVERTEX_PARTICLE),    //给大小加锁
        (void**) &pVertices, 
        D3DLOCK_DISCARD)))
    {
        return;
    }
        for( ; iCur != iEnd; iCur++)
        {
        //更新每个粒子的当前位置
        (*iCur)->m_vPosition += (fElapsedTime*(*iCur)->m_fSpeed)*(*iCur)->m_vDirection;
        pVertices->Position  = (*iCur)->m_vPosition;
       pVertices->color =D3DCOLOR_XRGB(255,255,255);
        pVertices++;
        }
    m_pVB->Unlock();
}
//删除生命周期结束的粒子
CFirePartile::ParticleActiveList::iterator CFirePartile::DeleteParticle( CFirePartile::ParticleActiveList::iterator &i )
{
        //增加粒子到空闲链表
        m_FreeParticles.push_back( *i );
        //删除i位置的数据,传回下一个数据的位置
        return m_ActiveParticles.erase( i );
}
void CFirePartile::Render()
{
    //设置渲染属性
    m_pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, TRUE );   //启用点精灵
    m_pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE,  TRUE );  //点大小的计算方式
    m_pd3dDevice->SetRenderState( D3DRS_POINTSIZE,   FtoDW(m_fSize) );  //设置点的大小
    m_pd3dDevice->SetRenderState( D3DRS_POINTSIZE_MIN, FtoDW(1.0f) );   //点的最小值
    m_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_A,  FtoDW(0.0f) );  //3个系数
    m_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_B,  FtoDW(0.0f) );  
    m_pd3dDevice->SetRenderState( D3DRS_POINTSCALE_C,  FtoDW(1.0f) );  
     //半透明效果
    m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
    m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
    //禁用照明效果
    m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
    m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
    //..........渲染开始.............
    if( m_ActiveParticles.size() )
    {
        m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(CUSTOMVERTEX_PARTICLE) );
        m_pd3dDevice->SetFVF( D3DFVF_CUSTOMEVERTEX_PARTICLE );
        m_pd3dDevice->SetTexture(0,m_pTexture);
        m_pd3dDevice->DrawPrimitive( D3DPT_POINTLIST, 0, m_ActiveParticles.size());
    }
    //..........渲染结束.............
    //恢复渲染状态...
    m_pd3dDevice->SetRenderState( D3DRS_POINTSPRITEENABLE, FALSE );
    m_pd3dDevice->SetRenderState( D3DRS_POINTSCALEENABLE, FALSE );
    m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
下面是调用CFirePartile类的主文件: 复制代码//=============================================================================
//Desc:项目的主文件
//=============================================================================
#include <Windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
#include <strsafe.h>
#include "FirePartile.h"
//-----------------------------------------------------------------------------
//全局变量
//-----------------------------------------------------------------------------
LPDIRECT3D9             g_pD3D       = NULL; //D3D接口
LPDIRECT3DDEVICE9      g_pd3dDevice  = NULL; //D3D设备
CFirePartile*               g_pFirePartile   =NULL;//火焰类指针
//-----------------------------------------------------------------------------
//Name: InitD3D()
//Desc: 初始化D3D环境
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
    //创建D3D 对象
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;
    //初始化D3D 设备数据结构
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    //创建D3D设备
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }
    //生成火焰对象
    g_pFirePartile = new CFirePartile;
    //初始化
    g_pFirePartile->Init(g_pd3dDevice);
    //渲染状态关闭灯光
    g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
    return S_OK;
}
//-----------------------------------------------------------------------------
//Name: Cleanup()
//Desc: 释放所有申请的资源
//-----------------------------------------------------------------------------
VOID Cleanup()
{
    SAFE_DELETE(g_pFirePartile);
    SAFE_RELEASE(g_pd3dDevice);
    SAFE_RELEASE(g_pD3D);
}
void Update()
{
    static float fPreTime = static_cast<float>(timeGetTime());
    float fCurrentTime = static_cast<float>(timeGetTime());
    float fElapsedTime = (fCurrentTime - fPreTime)*0.001f;
    g_pFirePartile->Update(fElapsedTime);
    fPreTime = fCurrentTime;
}
//-----------------------------------------------------------------------------
//Name: SetupMatrices()
//Desc: 设置世界矩阵,视角变换矩阵和投影变换矩阵
//-----------------------------------------------------------------------------
VOID SetupMatrices()
{
    D3DXVECTOR3 vEyePt( 0.0f,1.0f,-15.0f );      //摄像机位置
    D3DXVECTOR3 vLookatPt( 1.0f, 0.0f, 0.0f );    //观察点位置,前进后退,向左向右,向上向下
    D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );      //摄像机正方向(本地坐标系)
    D3DXMATRIXA16 matView;
    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ) ;
  D3DXMATRIXA16 matProj;
  //它说明物体如何随着距离而缩小
  //参数定义了屏幕纵横比第四和第五个参数定义最近和最远剪切平面
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f ); 
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}
//-----------------------------------------------------------------------------
//Name: Render()
//Desc: 渲染
//-----------------------------------------------------------------------------
VOID Render()
{
    //清屏
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
    Update();
    //开始渲染
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
        //矩阵变换
        SetupMatrices();
        //渲染火焰
        g_pFirePartile->Render();
        //渲染结束
        g_pd3dDevice->EndScene();
    }
    //翻转缓冲
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
//-----------------------------------------------------------------------------
//Name: MsgProc()
//Desc: 消息处理函数
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
    case WM_DESTROY:
        Cleanup();
        PostQuitMessage( 0 );
        return 0;
    }
    return DefWindowProc( hWnd, msg, wParam, lParam );
}
//-----------------------------------------------------------------------------
//Name: WinMain()
//Desc: Win32主程序
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
    //注册窗口类
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
        GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
        "D3D Tutorial", NULL };
    RegisterClassEx( &wc );
    //创建窗口
    HWND hWnd = CreateWindow( "D3D Tutorial", "v5.0 粒子系统:火焰粒子效果",
        WS_OVERLAPPEDWINDOW, 100, 100, 400, 400,
        GetDesktopWindow(), NULL, wc.hInstance, NULL );
    //初始化Direct3D
    if( SUCCEEDED( InitD3D( hWnd ) ) )
    {
                  //显示窗口
            ShowWindow( hWnd, SW_SHOWDEFAULT );
            UpdateWindow( hWnd );
            //消息循环
            MSG msg;
            ZeroMemory( &msg, sizeof(msg) );
            while( msg.message!=WM_QUIT )
            {
                if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
                {
                    TranslateMessage( &msg );
                    DispatchMessage( &msg );
                }
                else
                    Render();    //渲染
            }
    }
    //注销窗口类
    UnregisterClass( "D3D Tutorial", wc.hInstance );
    return 0;
}
 | 
 |