【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 3624|回复: 1

基于DIRECTX的3D粒子系统构建 (1)

[复制链接]
发表于 2006-9-27 17:50:58 | 显示全部楼层 |阅读模式
  本节通过对粒子的主要特征进行分析,来构建一个简单的粒子系统。一个粒子系统的复杂度,主要根据它所应用的环境来决定的。从之前介绍的粒子系统的核心内容来看,粒子系统的基本原理就是数据管理,渲染和更新的过程。这个过程可以很简单,也可以变得非常复杂。
  制作简单的粒子,可以很方便并快速地实现效果,不过功能单一适应能力差。换一个效果,就需要重新修改代码;复杂的粒子系统可以满足大多数情况下的需求,给程序员和美术都可以提供很大的方便。不过要构建这样一套粒子系统,非常不容易。下面通过一个相对简单的实现下雪天气效果的程序,演示如何使用粒子的基本特征实现一个简单粒子。
粒子实现技术
  粒子的具体实现方法,可以分为公告板(Billboard)和点精灵两种方式:粒子是一个很小的物体,数学上它经常被当作是一个点。点图元(在D3DPRIMITIVETYPE中选择D3DPT_POINTLIST)是一个实现粒子的很好的方案。然而由于点图元将会被光栅化为一个像素。这样粒子的灵活性就会降低,例如无法实现不同大小的粒子,以及不能给粒子贴上纹理。在Direct3D 8.0以前,由于点图元的种种不足,程序员不会用它来实现粒子,一般都是用公告板(BillBoard)来显示粒子,公告板是一块小小的四边形,通过自身的世界矩阵的控制,公告板的正面总是面向摄像机。
公告板
公告板是用矩形快速渲染任意形状物体的方法,而粒子正适合用这种方法。
                                
图片1.png
游戏中用公告板构成的粒子系统

  Billboard在控制粒子的旋转和动画方面更有优势,而点精灵必须用Pixel Shader实现。在显卡不支持点精灵时,Billboard是惟一的选择。粒子旋转在很多时候是必需的,例如旋转上升的烟雾粒子更容易模拟烟雾缭绕的现象,如图5-10所示。另外,模拟飘落的树叶或者雪花也会得到意想不到的效果。
  当使用Billboard进行渲染时,所有BillBoard合并到一个缓冲区中,然后一次绘制出来,尽量使显卡进行批量处理以提高渲染效率,否则会导致太多的绘制函数调用而降低效率。由于每个粒子的角度不尽相同,因此在进行渲染前应该为每个粒子计算旋转后的纹理坐标或顶点。
点精灵
  Direct3D 8.0引入了一种称为point sprite(点精灵,由于中英文的差别,point sprite和point primitive有时都被翻译为点图元,为了避免这种混淆,在后文中将直接使用英文),它最适用于实现粒子效果。与普通的点图元不同,point sprite可以加上纹理以及更改大小,与公告板不同,可以用一个点来描述,这样就省下了处理时间和内存,因为现在只需要一个点,而公告板需要4个点(用于描述一个四边形)。point sprite的特点如下:
减少顶点处理数量,由于一个物体渲染只需要一个顶点,因此大大减轻了顶点处理的负担。对于粒子,只需要一个点,顶点是使用Billboard渲染时的1/4。
旋转顶点不容易实现,必须借助pixel shader进行纹理旋转。
  点精灵将在后面的火焰粒子系统中具体得到应用。
粒子系统的组成
  粒子系统是诸多粒子的集合,而且负责这些粒子的维护和显示工作。粒子系统保存着影响系统中所有的粒子的全局属性,诸如大小、起始位置、应用的纹理等。从功能上来说,粒子系统就是负责粒子的更新、显示、销毁和创建的系统。
粒子的数据组成
  要构建一个粒子系统,首先必须需要分析粒子系统的属性数据,对一般的粒子系统而言,一般要包含位置信息、速度、朝向生命周期以及颜色等属性信息。不同的粒子系统中的粒子有着不同的属性,然而有一些属性是共有的。下面的示例结构就包含了一些粒子共有的属性。大部分粒子系统并不需要以下的全部属性,然而有的系统需要更多没有列出来的属性。
  1. {
  2.     float m_fWidth;                            //宽度
  3.     float m_fHeight;                    //高度
  4.     bool m_bOwnDimension;                    //是否可控制粒子大小
  5.     DWORD m_Color;                        //当前颜色(通常指顶点颜色)
  6.     D3DXVECTOR3 m_vPosition;        //位置
  7.     D3DXVECTOR3 m_vDirection;        //方向(有长度的方向,包含速度)
  8.     float m_fTimeToLive;                //剩余生命
  9.     float m_fTotalTimeToLive;            //生命周期
  10.     float m_fRotation;                        //当前的旋转弧度
  11.     float m_fSpeed;                            //速度
  12. };
复制代码
m_fWidth,m_fHeight如果是公告板粒子的话就会需要设置宽高。
   m_vPosition在世界坐标系下的粒子位置。
   m_fTotalTimeToLive粒子存活期,控制粒子生存状态的值。例如可以在经过一个给定的时间后销毁激光束的粒子。
   m_fTimeToLive粒子剩余的生存期。
   m_Color粒子的颜色。
   m_fSpeed粒子的速度,以“单位每秒”来描述。

粒子系统的函数组成
  粒子系统的函数主要作用是对粒子数据进行管理,更新以及渲染的。但是一个粒子系统往往有着丰富的函数来为粒子系统实现各种功能提供接口。表5-1中列出了一个粒子系统中常见的一些函数。
粒子系统中常见的函数
  成员函数名称          功能
Init        初始化粒子类需要的设备
Update        粒子的更新函数,所有的粒子数据都在这里面进行逻辑运算
Render        设置合适的渲染状态,渲染粒子
Load        读取粒子脚本
FreeData        系统资源的释放。除了要释放用到的纹理,顶点等信息以外,还有申请的粒子池也需要释放
Reset        所有的粒子属性都会被重置
SetPoolSize        设置粒子池大小
DeleteParticle        从激活粒子链表中删除相应的粒子,放到空闲粒子链表中去
ClearParticle        生成一个新的可用粒子,从空闲粒子链表中取出一段内存,保存到激活粒子链表中
CreateEmitter        创建一个粒子发射器,用来描述粒子的新的产生行为
CreateAffector        创建一个粒子效果器,用来定义粒子的新效果
SetTexAnimDuration        设置粒子纹理动画的周期
SetSceneBlendType        设置粒子颜色与场景颜色的混合方式
SetEnable        粒子启用标志位,是否启用该粒子团
GetEnable        取得该粒子团的启用标志位,一般用来判断当前粒子团是否是可用的

实现简单粒子程序
  了解粒子的原理知识,粒子有哪些方法和属性。本节内容按上述的知识点实现一个简单的雪天效果。这个小程序远远不能和一个完整的粒子系统相媲美,不过通过这个程序,就可以了解到一个基本的粒子系统的实现思想。
粒子结构和类定义
  首先需要定义粒子属性的结构体。在一个雪花类里面,除了一般粒子需要的坐标,纹理,速度等基本属性以外,还需要有旋转等附加属性。这个雪花粒子结构体如下:
  1. struct SnowParticle
  2. {
  3.     float x, y, z;                    //位置
  4.     float fYaw;                //绕自身Y轴旋转角度
  5.     float fPitch;                    //.绕自身X轴旋转角度
  6.     float Dspeed;            //下降速度
  7.     float Rspeed;                    //旋转速度
  8.     int  TexIndex;            //纹理
  9. };
复制代码
接下来在这个结构体的基础上构建一个雪花类。在以前的章节已经学习过粒子系统的主要组成部分是数据管理,渲染以及更新。所以在雪花类中,也有对应的数据或者函数。下面就是CSnowParticles类的声明:
  1. class CSnowParticles
  2. {
  3. public:
  4.     CSnowParticles(void);
  5.     ~CSnowParticles(void);
  6.     HRESULT Init( LPDIRECT3DDEVICE9 pd3dDevice );
  7.     void Update( float fElapsedTime );
  8.     void Render( LPDIRECT3DDEVICE9 pd3dDevice );
  9. private:
  10.     LPDIRECT3DVERTEXBUFFER9  m_pSnowVB;                //粒子顶点缓冲区
  11.     D3DXMATRIX                 m_matSnow;                //粒子世界矩阵
  12.     LPDIRECT3DTEXTURE9        m_pSnowTex[3];            //粒子纹理
  13.     SnowParticle                   m_snow[PARTICLENUM_SNOW];  //雪花粒子数组
  14. };
复制代码
粒子初始化
  Init()函数是雪花类的初始化函数。在这个函数中,不但创建了D3D构造粒子需要的顶点缓冲区,初始化了顶点数据,并且加载了雪花需要的纹理。创建顶点缓冲区代码如下:
  1. if( FAILED(  pd3dDevice->CreateVertexBuffer( 4*sizeof(CUSTOMVERTEX_SNOW),
  2.     0, D3DFVF_CUSTOMEVERTEX_SNOW,D3DPOOL_DEFAULT, &m_pSnowVB, NULL ) ) )
  3. {
  4.     return E_FAIL;
  5. }
复制代码
在创建顶点缓冲区的时候,粒子顶点被频繁地更新,因此不必要使用D3DPOOL_MANAGED方式在内存中保留备份。这种类型的缓冲区一般最好使用D3DPOOL_DEFAUL方式创建。这样做的意义在于把资源放在显示内存中绘制速度将会快得多。因为更新资源时,要把资源拷贝到系统内存,然后在渲染时再拷贝到本地显示内存中。这种方式对于需要频繁更新顶点的粒子系统是非常不适合的。
  接下来加载雪花需要的纹理。为了让画面看起来更丰富一些,这里用到了3种不同的纹理,来表现不同形状的雪花。
  1. //创建雪花纹理
  2. if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, "snow1.png", &m_pSnowTex[0] )))
  3.   return E_FAIL;
  4. if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, "snow2.png", &m_pSnowTex[1] )))
  5.   return E_FAIL;
  6. if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, "snow3.png", &m_pSnowTex[2] )))
  7.   return E_FAIL;
  8.   初始化雪花数据的时候,为了让雪花看起来更逼真,给他们取一些随机值,让他们的位置,下落角度等随机排布,并且3张不同形状的雪花纹理会被随机分配到不同的粒子上。
  9. //初始化雪花粒子数组
  10. srand(GetTickCount());
  11. for(int i=0; i<PARTICLENUM_SNOW; i++)
  12. {   
  13.      snow[i].x        = float(rand()%200-100);
  14.      snow[i].z        = float(rand()%200-100);
  15.      snow[i].y        = float(rand()%250);
  16.      snow[i].fYaw    = (rand()%100)/50.0f*D3DX_PI;
  17.      snow[i].fPitch    = (rand()%100)/50.0f*D3DX_PI;
  18.      snow[i].Dspeed   = 20.0f + rand()%10;
  19.      snow[i].Rspeed   = 1.0f +  rand()%10/10.0f;   
  20.      snow[i].TexIndex = rand()%3;                //随机得到一张纹理
  21. }
复制代码
粒子属性更新
  粒子雪花在系统中,随着时间的变化,位置和旋转角度也在发生着变化,这些数据的更新都是在Update()函数中进行运算的。当雪花位置小于某一个值的时候雪花就会自动被重置,每一个雪粒子在运动的时候都会自身旋转,粒子的偏向角也会随着时间的旋转发生变化。这样看到的效果就是雪花不断地从天空旋转自由飘落的样子。
  1. void CSnowParticles::Update( float fElapsedTime )
  2. {
  3.     //更新每个雪花粒子的当前位置和角度
  4.     for(int i=0; i<PARTICLENUM_SNOW; i++)
  5.     {
  6.         snow[i].y -= snow[i].Dspeed*fElapsedTime;
  7.         if(snow[i].y<0)         //当雪粒子低于地平面的时候
  8.             snow[i].y = 250.0f;
  9.         snow[i].fYaw  += snow[i].Rspeed * fElapsedTime;
  10.         snow[i].fPitch  += snow[i].Rspeed * fElapsedTime;
  11.     }
  12. }
复制代码
粒子的渲染
  粒子类中的渲染函数,主要是负责对粒子当前状态的渲染。这里面除了从雪花数组中获取雪花数据值进行渲染以外还要包括渲染状态的设置。粒子系统有着它特殊的渲染状态,一般粒子系统的贴图都是带有Alpha通道的,这样才能实现各种形状,因此,在渲染它的时候Alpha混合应该是打开的。在处理大量粒子时,粒子间的互相遮挡关系并不重要,因此将深度写入关闭。当然,如果粒子系统不作碰撞检测,可能运动到其他物体背面,所以,深度测试(Z-Test)仍然是开启的。微小的粒子一般没有方向性,因此没有法线,所以也关闭光照计算。
  1. void CSnowParticles::Render( LPDIRECT3DDEVICE9 pd3dDevice )
  2. {
  3.     //设置Alpha混合系数
  4.     pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  5.     pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  6.     //禁用照明效果
  7.     pd3dDevice->SetRenderState( D3DRS_LIGHTING, false );
  8.     //渲染所有雪花
  9.     for(int i=0; i<PARTICLENUM_SNOW; i++)
  10.     {
  11.         //构造并设置当前雪花粒子的世界矩阵
  12.         static D3DXMATRIX matYaw, matPitch, matTrans;
  13.         D3DXMatrixRotationY(&matYaw, snow[i].fYaw);
  14.         D3DXMatrixRotationX(&matPitch, snow[i].fPitch);
  15.         D3DXMatrixTranslation(&matTrans, snow[i].x, snow[i].y, snow[i].z);
  16.         m_matSnow = matYaw * matPitch * matTrans;
  17.         pd3dDevice->SetTransform( D3DTS_WORLD,  &m_matSnow);
  18.         //渲染当前雪花粒子
  19.         pd3dDevice->SetTexture( 0, m_pSnowTex[snow[i].TexIndex] );
  20.         pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
  21.         pd3dDevice->SetStreamSource(0, m_pSnowVB, 0, sizeof(CUSTOMVERTEX_SNOW));
  22.         pd3dDevice->SetFVF(D3DFVF_CUSTOMEVERTEX_SNOW);
  23.         pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
  24.         pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
  25.     }
  26. }
复制代码
 楼主| 发表于 2006-9-27 17:53:51 | 显示全部楼层
【实例4-1】简单粒子——雪   下面是CSnowParticles类的完整实现。 CSnowParticles类头文件
  1. //=============================================================================
  2. //Desc: CSnowParticles.h
  3. //=============================================================================
  4. #pragma once
  5. #include "d3dx9.h"
  6. #include "Utility.h"
  7. #define PARTICLENUM_SNOW 1000
  8. //顶点结构
  9. struct CUSTOMVERTEX_SNOW
  10. {
  11. float x, y, z;
  12. float u, v;
  13. };
  14. #define D3DFVF_CUSTOMEVERTEX_SNOW (D3DFVF_XYZ|D3DFVF_TEX1)
  15. //雪花粒子结构
  16. struct SnowParticle
  17. {
  18. float x, y, z; //位置
  19. float fYaw; //绕自身Y轴旋转角度
  20. float fPitch; //绕自身X轴旋转角度
  21. float Dspeed; //下降速度
  22. float Rspeed; //旋转速度
  23. int TexIndex; //纹理
  24. };
  25. class CSnowParticles
  26. {
  27. public:
  28. CSnowParticles(void);
  29. ~CSnowParticles(void);
  30. HRESULT Init( LPDIRECT3DDEVICE9 pd3dDevice );
  31. void Update( float fElapsedTime );
  32. void Render( LPDIRECT3DDEVICE9 pd3dDevice );
  33. private:
  34. protected:
  35. LPDIRECT3DVERTEXBUFFER9 m_pSnowVB; //粒子顶点缓冲区
  36. D3DXMATRIX m_matSnow; //粒子世界矩阵
  37. LPDIRECT3DTEXTURE9 m_pSnowTex[3]; //粒子纹理
  38. SnowParticle snow[PARTICLENUM_SNOW]; //雪花粒子数组
  39. };
复制代码
  1. CSnowParticles类源文件
  2. //=============================================================================
  3. //Desc: CSnowParticles.cpp
  4. //=============================================================================
  5. #include ".\snowparticles.h"
  6. CSnowParticles::CSnowParticles(void)
  7. {
  8. }
  9. CSnowParticles::~CSnowParticles(void)
  10. {
  11. SAFE_RELEASE(m_pSnowVB);
  12. for(int i=0;i<3; i++)
  13. SAFE_RELEASE(m_pSnowTex[i]);
  14. }
  15. //粒子数据的初始化
  16. HRESULT CSnowParticles::Init( LPDIRECT3DDEVICE9 pd3dDevice )
  17. {
  18. //创建雪花粒子顶点缓冲区
  19. if( FAILED( pd3dDevice->CreateVertexBuffer( 4*sizeof(CUSTOMVERTEX_SNOW),
  20. 0, D3DFVF_CUSTOMEVERTEX_SNOW,
  21. D3DPOOL_DEFAULT, &m_pSnowVB, NULL ) ) )
  22. {
  23. return E_FAIL;
  24. }
  25. //填充雪花粒子顶点缓冲区
  26. CUSTOMVERTEX_SNOW vertices2[] =
  27. {
  28. { -1, 0, 0, 0.0f, 1.0f, },
  29. { -1, 2, 0, 0.0f, 0.0f, },
  30. { 1, 0, 0, 1.0f, 1.0f, },
  31. { 1, 2, 0, 1.0f, 0.0f, }
  32. };
  33. VOID* pVertices2;
  34. if( FAILED( m_pSnowVB->Lock( 0, sizeof(vertices2), (void**)&pVertices2, 0 ) ) )
  35. return E_FAIL;
  36. memcpy( pVertices2, vertices2, sizeof(vertices2) );
  37. m_pSnowVB->Unlock();
  38. //创建雪花纹理
  39. if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, "snow1.png", &m_pSnowTex[0] )))
  40. return E_FAIL;
  41. if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, "snow2.png", &m_pSnowTex[1] )))
  42. return E_FAIL;
  43. if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, "snow3.png", &m_pSnowTex[2] )))
  44. return E_FAIL;
  45. //初始化雪花粒子数组
  46. srand(GetTickCount());
  47. for(int i=0; i<PARTICLENUM_SNOW; i++)
  48. {
  49. snow[i].x = float(rand()%200-100);
  50. snow[i].z = float(rand()%200-100);
  51. snow[i].y = float(rand()%250);
  52. snow[i].fYaw = (rand()%100)/50.0f*D3DX_PI;
  53. snow[i].fPitch = (rand()%100)/50.0f*D3DX_PI;
  54. snow[i].Dspeed = 20.0f + rand()%10;
  55. snow[i].Rspeed = 1.0f + rand()%10/10.0f;
  56. snow[i].TexIndex = rand()%3; //随即获取雪花粒子纹理
  57. }
  58. return S_OK;
  59. }
  60. //粒子的数据更新
  61. void CSnowParticles::Update( float fElapsedTime )
  62. {
  63. //更新每个雪花粒子的当前位置和角度
  64. for(int i=0; i<PARTICLENUM_SNOW; i++)
  65. {
  66. snow[i].y -= snow[i].Dspeed*fElapsedTime;
  67. if(snow[i].y<-100)
  68. snow[i].y = 150.0f;
  69. snow[i].fYaw += snow[i].Rspeed * fElapsedTime;
  70. snow[i].fPitch += snow[i].Rspeed * fElapsedTime;
  71. }
  72. }
  73. //粒子的渲染
  74. void CSnowParticles::Render( LPDIRECT3DDEVICE9 pd3dDevice )
  75. {
  76. //设置Alpha混合系数
  77. pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
  78. pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  79. //禁用照明效果
  80. pd3dDevice->SetRenderState( D3DRS_LIGHTING, false );
  81. //渲染所有雪花
  82. for(int i=0; i<PARTICLENUM_SNOW; i++)
  83. {
  84. //构造并设置当前雪花粒子的世界矩阵
  85. static D3DXMATRIX matYaw, matPitch, matTrans;
  86. D3DXMatrixRotationY(&matYaw, snow[i].fYaw);
  87. D3DXMatrixRotationX(&matPitch, snow[i].fPitch);
  88. D3DXMatrixTranslation(&matTrans, snow[i].x, snow[i].y, snow[i].z);
  89. m_matSnow = matYaw * matPitch * matTrans;
  90. pd3dDevice->SetTransform( D3DTS_WORLD, &m_matSnow);
  91. //渲染当前雪花粒子
  92. pd3dDevice->SetTexture( 0, m_pSnowTex[snow[i].TexIndex] );
  93. pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
  94. pd3dDevice->SetStreamSource(0, m_pSnowVB, 0, sizeof(CUSTOMVERTEX_SNOW));
  95. pd3dDevice->SetFVF(D3DFVF_CUSTOMEVERTEX_SNOW);
  96. pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
  97. pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
  98. }
  99. }
复制代码
项目主文件   下面是调用这个类的主文件:
  1. //=============================================================================
  2. //Desc: 雪花粒子效果主文件
  3. //=============================================================================
  4. #include <Windows.h>
  5. #include <mmsystem.h>
  6. #include <d3dx9.h>
  7. #include <strsafe.h>
  8. #include "SnowParticles.h"
  9. //-----------------------------------------------------------------------------
  10. //全局变量
  11. //-----------------------------------------------------------------------------
  12. LPDIRECT3D9 g_pD3D = NULL; //D3D接口
  13. LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //D3D设备
  14. CSnowParticles* g_pSnowParticles = NULL; //雪花类指针
  15. //-----------------------------------------------------------------------------
  16. //Name: InitD3D()
  17. //Desc: 初始化D3D环境
  18. //-----------------------------------------------------------------------------
  19. HRESULT InitD3D( HWND hWnd )
  20. {
  21. //创建D3D对象
  22. if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
  23. return E_FAIL;
  24. //初始化D3D设备数据结构
  25. D3DPRESENT_PARAMETERS d3dpp;
  26. ZeroMemory( &d3dpp, sizeof(d3dpp) );
  27. d3dpp.Windowed = TRUE;
  28. d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
  29. d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
  30. //创建D3D设备
  31. if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
  32. D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  33. &d3dpp, &g_pd3dDevice ) ) )
  34. {
  35. return E_FAIL;
  36. }
  37. g_pSnowParticles = new CSnowParticles;
  38. g_pSnowParticles->Init(g_pd3dDevice);
  39. //渲染状态双面可见
  40. g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  41. //渲染状态 关闭灯光
  42. g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
  43. return S_OK;
  44. }
  45. //-----------------------------------------------------------------------------
  46. //Name: Cleanup()
  47. //Desc: 释放所有申请的资源
  48. //-----------------------------------------------------------------------------
  49. VOID Cleanup()
  50. {
  51. delete g_pSnowParticles;
  52. if( g_pd3dDevice != NULL )
  53. g_pd3dDevice->Release();
  54. if( g_pD3D != NULL )
  55. g_pD3D->Release();
  56. }
  57. //-----------------------------------------------------------------------------
  58. //Name: SetupMatrices()
  59. //Desc: 设置世界矩阵,视角变换矩阵和投影变换矩阵
  60. //-----------------------------------------------------------------------------
  61. VOID SetupMatrices()
  62. {
  63. D3DXVECTOR3 vEyePt( 0.0f,1.0f,-5.0f ); //摄像机位置
  64. D3DXVECTOR3 vLookatPt( 1.0f, 0.0f, 0.0f ); //观察点位置,前进后退,向左向右,向上向下
  65. D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f ); //摄像机正方向(本地坐标系)
  66. D3DXMATRIXA16 matView;
  67. D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
  68. g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ) ;
  69. D3DXMATRIXA16 matProj;
  70. //它说明物体如何随着距离而缩小,参数定义了屏幕纵横比第四和第五个参数定义最近和最远剪切平面
  71. D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
  72. g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  73. }
  74. //-----------------------------------------------------------------------------
  75. //Name: Render()
  76. //Desc: 渲染
  77. //-----------------------------------------------------------------------------
  78. VOID Render()
  79. {
  80. //清屏
  81. g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
  82. static float fPreTime = static_cast<float>(timeGetTime());
  83. float fCurrentTime = static_cast<float>(timeGetTime());
  84. float fElapsedTime = (fCurrentTime - fPreTime)*0.001f;
  85. g_pSnowParticles->Update(fElapsedTime);
  86. fPreTime = fCurrentTime;
  87. //开始渲染
  88. if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
  89. {
  90. //矩阵变换
  91. SetupMatrices();
  92. //渲染雪花
  93. g_pSnowParticles->Render(g_pd3dDevice);
  94. //渲染结束
  95. g_pd3dDevice->EndScene();
  96. }
  97. //翻转缓冲
  98. g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  99. }
  100. //-----------------------------------------------------------------------------
  101. //Name: MsgProc()
  102. //Desc: 消息处理
  103. //-----------------------------------------------------------------------------
  104. LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  105. {
  106. switch( msg )
  107. {
  108. case WM_DESTROY:
  109. Cleanup();
  110. PostQuitMessage( 0 );
  111. return 0;
  112. }
  113. return DefWindowProc( hWnd, msg, wParam, lParam );
  114. }
  115. //-----------------------------------------------------------------------------
  116. //Name: WinMain()
  117. //Desc: Win32主程序
  118. //-----------------------------------------------------------------------------
  119. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  120. {
  121. //注册窗口类
  122. WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
  123. GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
  124. "D3D Tutorial", NULL };
  125. RegisterClassEx( &wc );
  126. //创建窗口
  127. HWND hWnd = CreateWindow( "D3D Tutorial", "v5.0 粒子系统:雪花粒子效果",
  128. WS_OVERLAPPEDWINDOW, 100, 100, 400, 400,
  129. GetDesktopWindow(), NULL, wc.hInstance, NULL );
  130. //初始化 Direct3D
  131. if( SUCCEEDED( InitD3D( hWnd ) ) )
  132. {
  133. //显示窗口
  134. ShowWindow( hWnd, SW_SHOWDEFAULT );
  135. UpdateWindow( hWnd );
  136. //消息循环
  137. MSG msg;
  138. ZeroMemory( &msg, sizeof(msg) );
  139. while( msg.message!=WM_QUIT )
  140. {
  141. if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
  142. {
  143. TranslateMessage( &msg );
  144. DispatchMessage( &msg );
  145. }
  146. else
  147. Render(); //渲染
  148. }
  149. }
  150. //注销窗口类
  151. UnregisterClass( "D3D Tutorial", wc.hInstance );
  152. return 0;
  153. }
复制代码
图片1.png 下雪的粒子效果
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 06:40

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表