2013-04-09 55 views
0

我正在嘗試在XNA 4.0中創建的遊戲中創建一個粒子系統。 粒子在發射器初始化的世界呈現。 問題是我想更新Update()上的粒子位置,但它不起作用,粒子被渲染,但僅在位置0,0,0的世界中心。XNA更新VertexBuffer中頂點的位置更新

每個粒子由一組帶頂點的頂點組成。

任何人都可以幫我嗎? 下面是粒子發射器類:

public class ParticleEmitter : RenderableGameObject 
{ 
    VertexBuffer vertexBuffer; 
    VertexDeclaration vertexDeclaration; 
    Effect bbEffect; 

    VertexPositionTexture[] vertices; 

    Texture2D texture; 
    int noVertices = 0; 

    struct Particle 
    { 
     public Vector3 position; 
    } 
    Particle[] particles = new Particle[5]; 

    public ParticleEmitter(Game1 game) 
     : base(game) 
    { 
     SetupParticles(); 

     SetupVertices(); 

     bbEffect = game.Content.Load<Effect>("Effects/Particle"); 
     texture = game.Content.Load<Texture2D>("Textures/fire"); 
    } 

    private void SetupVertices() 
    { 
     int vertexIndex = 0; 
     vertices = new VertexPositionTexture[particles.Length * 6]; 

     for (int i = 0; i < particles.Length; ++i) 
     { 
      vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(0, 0)); 
      vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(1, 0)); 
      vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(1, 1)); 

      vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(0, 0)); 
      vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(1, 1)); 
      vertices[vertexIndex++] = new VertexPositionTexture(particles[i].position, new Vector2(0, 1)); 
     } 

     noVertices = vertexIndex; 

     vertexBuffer = new VertexBuffer(game.GraphicsDevice, typeof(VertexPositionTexture), vertices.Length, BufferUsage.WriteOnly); 
     vertexBuffer.SetData(vertices); 
     vertexDeclaration = new VertexDeclaration(VertexPositionTexture.VertexDeclaration.GetVertexElements()); 
    } 

    private void SetupParticles() 
    { 
     for (int i = 0; i < particles.Length; ++i) 
     { 
      particles[i] = new Particle(); 
      particles[i].position = Position * i; 
     } 
    } 

    private void UpdateVertices() 
    { 
     for (int i = 0; i < particles.Length; ++i) 
     { 
      vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(0, 0)); 
      vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(1, 0)); 
      vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(1, 1)); 

      vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(0, 0)); 
      vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(1, 1)); 
      vertices[i] = new VertexPositionTexture(particles[i].position, new Vector2(0, 1)); 
     } 

     game.GraphicsDevice.SetVertexBuffer(null); 
     vertexBuffer.SetData(vertices); 
    } 

    private void UpdateParticles() 
    { 
     for (int i = 0; i < particles.Length; ++i) 
     { 
      particles[i].position = Position; 
     } 
    } 

    public override void Update(GameTime gameTime) 
    { 
     UpdateParticles(); 
     UpdateVertices(); 

     base.Update(gameTime); 
    } 

    public override void Draw() 
    { 
     DrawParticles(game.camera.viewMatrix); 
    } 

    private void DrawParticles(Matrix currentViewMatrix) 
    { 
     bbEffect.CurrentTechnique = bbEffect.Techniques["CylBillboard"]; 
     bbEffect.Parameters["xWorld"].SetValue(Matrix.Identity); 
     bbEffect.Parameters["xView"].SetValue(currentViewMatrix); 
     bbEffect.Parameters["xProjection"].SetValue(game.camera.projectionMatrix); 
     bbEffect.Parameters["xCamPos"].SetValue(game.camera.Position); 
     bbEffect.Parameters["xAllowedRotDir"].SetValue(new Vector3(0, 1, 0)); 
     bbEffect.Parameters["xBillboardTexture"].SetValue(texture); 

     foreach (EffectPass pass in bbEffect.CurrentTechnique.Passes) 
     { 
      game.GraphicsDevice.BlendState = BlendState.AlphaBlend; 

      pass.Apply(); 
      game.GraphicsDevice.SetVertexBuffer(vertexBuffer); 
      int noTriangles = noVertices/3; 
      game.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, noTriangles); 
     } 
    } 
} 
+0

從性能角度看,'DynamicVertexBuffer'會更好,如果你正在更新的頂點,每一幀。雖然我個人會主張一種不同的方法 - 固定頂點緩衝區和頂點着色器,它們以參數方式推進粒子位置。關於你的問題:你能否澄清你的意思是「它不會工作」? – 2013-04-10 06:11:40

+0

感謝您的回覆,我更新了問題以澄清「它不起作用」。至於你提到的另一種方法。性能更好嗎?如果是這樣,你可以給如何做到這一點的資源? – pjongjang 2013-04-10 07:21:40

+0

[這是我的一箇舊回答](http://stackoverflow.com/a/3138075/165500),給出了更詳細的概述。恐怕我沒有任何實施資源。 – 2013-04-10 09:36:41

回答

1

你沒有真正改變顆粒的位置在所有的,在這種方法:

private void UpdateParticles() 
{ 
    for (int i = 0; i < particles.Length; ++i) 
    { 
     particles[i].position = Position; 
    } 
} 

你每一個粒子都設置爲相同的位置,可能是起源。

你可能想要做的是一樣的東西的速度添加到每個粒子:

struct Particle 
{ 
    public Vector3 position; 
    public Vector3 velocity; 
} 

然後初始化每個粒子具有隨機速度:

// Pass a shared, per-thread instance of Random into this method 
private void SetupParticles(Random random) 
{ 
    for (int i = 0; i < particles.Length; ++i) 
    { 
     particles[i] = new Particle() { 
      position = Vector.Zero, 
      velocity = new Vector3((float)(random.NextDouble() * 2 - 1), 
            (float)(random.NextDouble() * 2 - 1), 
            (float)(random.NextDouble() * 2 - 1)) 
     }; 
    } 
} 

然後根據更新它們一些物理模型(即:隨着時間的推移,由重力引起的速度和加速度)。

Vector3 gravity = new Vector3(0, -9.8f, 0); 

private void UpdateParticles(float time) 
{ 
    for (int i = 0; i < particles.Length; ++i) 
    { 
     particles[i].velocity += gravity * time; 
     particles[i].position += particles[i].velocity * time; 
    } 
} 

(注:這個答案的所有代碼是用手寫當心 - 語法錯誤等)