粒子和点精灵
粒子(是种微小的物体,在数学上通常用点来表示其模型。所以显示粒子时,使用点图元(由
D3 DPRIMITIVETYPE类型的D3 DPT POINTLIST枚举常量表示)是一个很好的选择。但是光栅化时,点图元将被映射为一个单个像素。这样就无法为我们提供很大的灵活性,因为实际应用中我们可能需要各种尺寸的粒子甚至希望能够对这些粒子进行纹理映射。在Direct3D8.0之前,要想摆脱点图元的这个限制,只能是不去使用它。那时,程序员都愿意用广告牌(billboard)技术来显示一个粒子。广告牌就是一个四边形,通过对其自身世界变换矩阵的控制,使其总是面向摄像机。
Direct3D8.0引入了.-种特别的点图元一点精灵(Point Sprite),该图元极适合应用于粒子系统中。与
普通的点图元不同,点精灵可进行纹理映射且其尺寸可变。点精灵也不同于广告牌,描述点精灵时仅需要一个单点即可。由于我们只需要存储和处理一个顶点而非4个(广告牌要用4个顶点描述),这样就节省了内存和宝贵的运算时间。
粒子结构格式
struct Particle
{
D3DXVECTOR3 m_position; //粒子位置
D3DCOLOR m_color; //粒子颜色
//float m_size; //粒子尺寸
static const DWORD FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE /*| D3DFVF_PSIZE*/;
};
_size来表示其尺寸。为了反映该变化,我们必须为灵活顶点格式FVF增加D3DFVF_PSIZE标记。让每个粒子对象维护其自身的尺寸十分有用,因为这就允许我们单独指定或改变某个粒子的尺寸。但由于大多数图形卡都不支持按照这种方式控制粒子的尺寸,所以我们将不采用这种做法。(可检查结构D3DCAPS9种的成员FVFCaps中的D3DFVFCAPS_PSIZE位来验证),我们将通过绘制状态来控制粒子的尺寸,即使硬件不支持D3DFVFCAPS_PSIZE,借助像素着色器(vertex shader)我们也有可能控制每个粒子的尺寸。
需要注意的是粒子结构参数如果定义了,就需要赋值为正确的值,不然可能会绘制不出来粒子,例如加了粒子尺寸字段,但是没有给该字段赋值。
点精灵绘制状态
点精灵的行为大部分由渲染状态来控制
D3DRS_POINTSPRITEENABLE
默认为false,若指定为tue,则规定整个当前纹理被映射到点精灵上。若指定为false,则规定点精灵的纹理坐标所指定的纹理元应被映射到点精灵上。
D3DRS_POINTSCALEENABLE
默认值为false,若指定为true,则规定点的尺寸将用观察坐标系的单位来度量。观察坐标系的单位是仅用来描述摄像机坐标系中的3D点。点精灵的尺寸将依据近大远小的原则进行相应的比例变换。若指定为false,则规定点的尺寸将用屏幕坐标系的单位(即像素)来度量。如果您将该绘制状态指定为false,而且您想将点精灵的尺寸设为3,则点精灵将变为屏幕上一个3×3的像素区域。
D3DRS_POINTSIZE
用于指定点精灵的尺寸。该值可被解释为观察坐标系中的点精灵尺寸,也可被解释为屏幕坐标系中的点精灵尺寸,这主要取决于绘制状态D3DRS_POINTSCALEENABLE的设置。下面的代码将点的尺寸设为2.5个单位。
Device->SetRenderState(D3DRS_POINTSIZE, d3d::FtoDw(2.5f));
D3DRS_POINTSIZE_MIN、D3DRS_POINTSIZE_MAX
指定点精灵可取的最小/最大尺寸
D3DRS_POINTSCALE_A、D3DRS_POINTSCALE_B、D3DRS_POINTSCALE_C
这3个常量控制了点精灵的尺寸如何随距离发生变化,这里的距离是指点精灵到摄像机的距离。
给定距离和这些常量时,Direct3D使用如下公式计算点精灵的最终尺寸:
- FinalSize:点精灵的最终尺寸
- ViewportHeight:视口(viewport)高度
- Size:对应于由绘制状态D3DRS_POINT_SIZE所指定的值
- A,B,C:分别对应于绘制状态D3DRS_POINTSCALE_A、D3DRS_POINTSCALE_B、
D3DRS_POINTSCALE_C所指定的值 - D:在观察坐标系中点精灵到摄像机的距离。由于在观察坐标系中,摄像机位于坐标原点,所以,(x,y,z)为点精灵在观察者坐标系中的位置
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));
粒子及其属性
一个粒除了位置和颜色外往往还具有许多其他的属性。例如粒子可县有一定的速度。但是绘制粒子时并不需要这些附加属性。所以我们将用于绘制粒子的数据与粒子的属性分别存储在两个不同的结
构中。当我们要创建、销毁或更新粒子时,需要涉及粒子的属性,当我们准备绘制粒子时,可将粒子的位置和颜色信息复制到Particle结构中。
粒子的属性与所要模拟的粒子系统的特定类型相关。通过指定些常用属性可以使这些属性结构变得通用些。下面是一个包舍了些通用的粒子属性的结构。大多数系统并不需要如此众多的属性,但是有些系统可能还需要附加些其他属性。
struct Attribute
{
D3DXVECTOR3 _position; //粒子在世界坐标系中的位置
D3DXVECTOR3 _velocity; //粒子的速度,单位/秒
D3DXVECTOR3 _acceleration; //粒子的加速度
float _lifeTime; //粒子自诞生到消亡所需的时间
float _age; //粒子当前的年龄
D3DXCOLOR _color; //粒子的颜色
D3DXCOLOR _colorFade; //粒子颜色如何随时间渐弱
bool _isAlive; //粒子是否处于活动状态
}
粒子系统的组成
粒子系统是众多粒子的集合,并负责对这些粒了进行维护和显示。粒子系统跟踪系统中影响所有粒子状态的全局属性,例如粒子的尺小、粒子的粒子源、将要映射到粒子的纹理等。按照功能来说,粒子系统主要负责史新(updating)、显示(displaying)、杀死(kil)以及创建(creating)粒子。
class ParticleSystem
{
protected:
IDirect3DDevice9* m_device;
D3DXVECTOR3 m_origin; //系统粒子源,所有的粒子都将从系统粒子源产生
d3d::BoundingBox m_boundingbox; //限制粒子的活动范围,超出该外接体的粒子会杀死
float m_emit_rate; //粒子的增加率,用粒子数/秒来度量
float m_size; //系统中所有粒子的尺寸
IDirect3DTexture9* m_tex;
IDirect3DVertexBuffer9* m_vb;
list<ParticleAttribute> m_particles; //系统中粒子的属性列表
int m_maxParticles; //某个给定时间内,系统所允许拥有的最大粒子数
DWORD m_vbSize; //在一个给定时间顶点缓存中所存储的顶点个数,该值不依赖于粒子系统中实际粒子个数
DWORD m_vbOffset;
DWORD m_vbBatchSize;
public:
ParticleSystem();
virtual ~ParticleSystem();
virtual bool init(IDirect3DDevice9* device, const char*