XNA 粒子系统入门

 

几经周折,终于做出来了一个简单的粒子系统。很简单,很丑,但我相信会对想了解这方面的人有所帮助。

什么是粒子系统

粒子系统是利用粒子模拟自然场景的一种技术,例如说雨,雪,水流,爆炸,烟雾等场景。由于这些场景都是根据物理模型计算出来的,也可以说,粒子系统是基于物理原理的一种建模方法。

粒子类

粒子系统是由粒子组成的。一般具有的特征包括质量、位置、速度、受力(能量)、生命周期等。很多个粒子也可以相互作用、组合、效果叠加。

下面是我的类:

 Code
    public class Particle
    {
       
//粒子的位置
      public bool isActive;
       
//粒子的位置
      private Vector3 position;
       
public Vector3 Position
        {
           
set { position = value; }
           
get { return position; }
        }
       
//粒子速度
      private Vector3 velocity;
       
public Vector3 Velocity
        {
           
set { velocity = value; }
           
get { return velocity; }
        }

       
/// <summary>
       
/// 实例一个粒子
       
/// </summary>
       
/// <param name="position"></param>
       
/// <param name="velocity"></param>
        public Particle(Vector3 position,Vector3 velocity)
        {
           
this.position = position;
           
this.velocity = velocity;
            isActive
= true;
        }
    }

 

粒子系统类

粒子系统主要是用来控制粒子的运动和绘制粒子。不清楚作用的话就看代码。

Code
public class ParticleSystem:DrawableGameComponent
{
GameMain game;
Model sphere;
Effect balleffect;
//最大粒子数
Random rnd ;
List
<Particle> particles;
int maxParticlesNum = 600;
float time = 0;

public ParticleSystem(Game game):base(game)
{
this.game = (GameMain)game;
particles
= new List<Particle>();
}

protected override void LoadContent()
{
sphere
= Game.Content.Load<Model>("sphere");
balleffect
= game.Content.Load<Effect>("balleffect");
base.LoadContent();
}

public override void Update(GameTime gameTime)
{
time
+= (float)gameTime.ElapsedGameTime.TotalSeconds;
if (particles.Count < maxParticlesNum/* && (int)(time * 100) % 6 == 0*/)
{
//x、z轴方向的速度随机
rnd = new Random((int)DateTime.Now.Ticks);
float x = (float)rnd.Next(-3, 3) / 10;
float z = (float)rnd.Next(-3, 3) / 10;
//生成速度向量
Vector3 vel = new Vector3(x, 1.6f,z);
//加入一个新的粒子
particles.Add(new Particle(Vector3.Zero,vel));
}

for(int i=0;i<particles.Count;i++)
{
Particle p
= particles[i];
//让粒子速度向下
p.Velocity -= new Vector3(0, 0.005f, 0);
p.Position
+= p.Velocity;
particles[i]
= p;
if ( particles[i].Position.Y<-300)
//移除一个粒子
particles.RemoveAt(i);
}
base.Update(gameTime);
}

public override void Draw(GameTime gameTime)
{
foreach (Particle particle in particles)
{
//如果是活动粒子……
if (particle.isActive)
{
foreach (ModelMesh mesh in sphere.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World
= world;
effect.View
= game.camera.View;
effect.Projection
= game.camera.Projection;
}
mesh.Draw();
}
}
}
base.Draw(gameTime);
}
}

两个类加上游戏主框架,就可以看到效果了,如下图。

clip_image002 clip_image004

这是从两个不同方向看到粒子从两个地方发出(粒子都是一个个球啊,由于拉的太远所以看起来有点像点)

改进

不过现在这样式很不乍的(主要是一点也看不出里面是一个个的小球),下面来给它们加上环境光和颜色。

HLSL代码如下:

Code
float4x4 World;
float4x4 View;
float4x4 Projection;
float4 color;
float3 EyePos;

//方向光
float4 lightDir:Direction
<
string Object="DirectionalLight";
string Space="World";
> ={1.0f,-1.0f,1.0f,0.0f};

//漫反射光
float4 lightColor:Diffuse
<
string UINAme="Dirffuse Light Color";
string Object="DirectionalLight";
> ={1.0f,1.0f,1.0f,1.0f};

//环境光
float4 lightAmbient:Ambient
<
string UIWidget="Ambient Light Color";
string Space="material";
> ={255.0f,255.0f,255.0f,1.0f};

//镜面反射能力
float shininess:SpecularPower
<
string UIWidget="slider";
float UIMin=1.0;
float UIMax=128.0;
float UIStep=1.0;
string UIName="specular power";
> =30;

struct VertexShaderInput
{
float4 Position : POSITION0;
float3 normal:NORMAL;
};

struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 diffAmbColor:COLOR0;
float4 specCol:COLOR1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4x4 normalMat;
normalMat
=mul(World,View);

float4 worldPosition
= mul(input.Position, World);
float4 viewPosition
= mul(worldPosition, View);
output.Position
= mul(viewPosition, Projection);

float4 N
=mul(input.normal,normalMat);
float3 E
=normalize(EyePos-output.Position);
float3 L
=normalize(mul(-lightDir.xyz,normalMat));
float3 H
=normalize(E+L);

output.diffAmbColor
=lightColor*max(0,dot(N,L))+lightAmbient;
output.specCol
=lightColor*pow(max(0,dot(N,H)),shininess);

return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
return input.diffAmbColor*color+input.specCol;
}

technique Technique1
{
pass Pass1
{
VertexShader
= compile vs_1_1 VertexShaderFunction();
PixelShader
= compile ps_1_1 PixelShaderFunction();
}
}

当然粒子的代码也要改啊

下面是新的代码:

    在粒子类中加入字段:public Color color;用于保存粒子的颜色

粒子类的构造方法中加入:

Code
byte[] byts = new byte[4];
new Random().NextBytes(byts);
color
=new Color(byts[0],byts[1],byts[2],255);

随机产生一个颜色。

修改粒子系统的Draw方法:

Code
public override void Draw(GameTime gameTime)
{
foreach (Particle particle in particles)
{
if (particle.isActive)
{
Matrix world
= Matrix.CreateTranslation(particle.Position.X, particle.Position.Y, particle.Position.Z);
balleffect.CurrentTechnique
=balleffect.Techniques[0];
balleffect.Parameters[
"World"].SetValue(world);
balleffect.Parameters[
"View"].SetValue(game.camera.View);
balleffect.Parameters[
"Projection"].SetValue(game.camera.Projection);
balleffect.Parameters[
"color"].SetValue(particle.color.ToVector4());
balleffect.Parameters[
"EyePos"].SetValue(game.camera.mposi);

foreach (ModelMesh mesh in sphere.Meshes)
{
foreach (ModelMeshPart part in mesh.MeshParts)
{
part.Effect
= balleffect;
}
mesh.Draw();
}
}
}
base.Draw(gameTime);
}

最终效果:

clip_image006 clip_image008

从下边和从远处的水平面看到的效果

posted @ 2008-11-03 10:02  齐.net  阅读(7892)  评论(19编辑  收藏  举报