2012-03-29 4 views
4

ich Instancing in XNABenötigen 4.0

Ich bin ein Anfang XNA Entwickler, die vor kurzem nur von 2D auf 3D-Spiele verstärkt fragen haben, kommen mit Instancing in XNA helfen.
Ich versuche, eine große Anzahl von Würfeln zu zeichnen, die ausschließlich aus Scheitelpunkten im Code bestehen. Wie man vermuten könnte, verursacht das Zeichnen einer großen Anzahl dieser Würfel ziemlich viel Stress auf meinem Computer.
Da ich nach einer Möglichkeit suchte, die Leistung zu steigern, stieß ich auf den Begriff "Instancing".
Da ich nicht weiß, wie das Instancing in XNA 4.0 funktioniert, habe ich mich nach einem Tutorial umgesehen, das für jemanden meines Niveaus geeignet ist.
Allerdings ist das einzige Tutorial ich gestoßen bin (http://blogs.msdn.com/b/shawnhar/archive/2010/06/17/drainstancedprimicitives-in-xna-game-studio-4-0.aspx) ist ein bisschen zu fortgeschritten für mich. Ich denke, er verwendet Modelle, Meshes und so weiter, statt Vertices, so dass ich nicht herausfinden kann, welcher Code wirklich relevant ist für das, wonach ich suche.

Deshalb komme ich zu dir. Wenn mir jemand ein einfaches (wenn möglich) Tutorial oder Code-Snippets geben könnte, die erklären, wie man Instantiierung mit Cubes (oder irgendwelchen Zahlen), die mit Vertices in XNA 4.0 gezeichnet sind, verwendet, wäre ich sehr dankbar.

Antwort

7

Dies ist das einfachste Code-Snippet, das ich mir vorstellen konnte. Es ist eine Adaption eines Codes, den ich vor ein paar Monaten gemacht habe, um einige Würfel zu zeigen, genau wie du es brauchst, keine Modelle oder nichts Besonderes.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Content; 

namespace HardwareInstancing 
{ 
    public class Instancing 
    { 
     Texture2D texture; 
     Effect effect; 

     VertexDeclaration instanceVertexDeclaration; 

     VertexBuffer instanceBuffer; 
     VertexBuffer geometryBuffer; 
     IndexBuffer indexBuffer; 

     VertexBufferBinding[] bindings; 
     InstanceInfo[] instances; 

     struct InstanceInfo 
     { 
      public Vector4 World; 
      public Vector2 AtlasCoordinate; 
     }; 

     Int32 instanceCount = 10000; 

     public void Initialize(GraphicsDevice device) 
     { 
      GenerateInstanceVertexDeclaration(); 
      GenerateGeometry(device); 
      GenerateInstanceInformation(device, instanceCount); 

      bindings = new VertexBufferBinding[2]; 
      bindings[0] = new VertexBufferBinding(geometryBuffer); 
      bindings[1] = new VertexBufferBinding(instanceBuffer, 0, 1); 
     } 

     public void Load(ContentManager Content) 
     { 
      effect = Content.Load<Effect>("InstancingShader"); 
      texture = Content.Load<Texture2D>("default_256"); 
     } 

     private void GenerateInstanceVertexDeclaration() 
     { 
      VertexElement[] instanceStreamElements = new VertexElement[2]; 

      instanceStreamElements[0] = 
        new VertexElement(0, VertexElementFormat.Vector4, 
         VertexElementUsage.Position, 1); 

      instanceStreamElements[1] = 
       new VertexElement(sizeof(float) * 4, VertexElementFormat.Vector2, 
        VertexElementUsage.TextureCoordinate, 1); 

      instanceVertexDeclaration = new VertexDeclaration(instanceStreamElements); 
     } 

     //This creates a cube! 
     public void GenerateGeometry(GraphicsDevice device) 
     { 
      VertexPositionTexture[] vertices = new VertexPositionTexture[24]; 

      #region filling vertices 
      vertices[0].Position = new Vector3(-1, 1, -1); 
      vertices[0].TextureCoordinate = new Vector2(0, 0); 
      vertices[1].Position = new Vector3(1, 1, -1); 
      vertices[1].TextureCoordinate = new Vector2(1, 0); 
      vertices[2].Position = new Vector3(-1, 1, 1); 
      vertices[2].TextureCoordinate = new Vector2(0, 1); 
      vertices[3].Position = new Vector3(1, 1, 1); 
      vertices[3].TextureCoordinate = new Vector2(1, 1); 

      vertices[4].Position = new Vector3(-1, -1, 1); 
      vertices[4].TextureCoordinate = new Vector2(0, 0); 
      vertices[5].Position = new Vector3(1, -1, 1); 
      vertices[5].TextureCoordinate = new Vector2(1, 0); 
      vertices[6].Position = new Vector3(-1, -1, -1); 
      vertices[6].TextureCoordinate = new Vector2(0, 1); 
      vertices[7].Position = new Vector3(1, -1, -1); 
      vertices[7].TextureCoordinate = new Vector2(1, 1); 

      vertices[8].Position = new Vector3(-1, 1, -1); 
      vertices[8].TextureCoordinate = new Vector2(0, 0); 
      vertices[9].Position = new Vector3(-1, 1, 1); 
      vertices[9].TextureCoordinate = new Vector2(1, 0); 
      vertices[10].Position = new Vector3(-1, -1, -1); 
      vertices[10].TextureCoordinate = new Vector2(0, 1); 
      vertices[11].Position = new Vector3(-1, -1, 1); 
      vertices[11].TextureCoordinate = new Vector2(1, 1); 

      vertices[12].Position = new Vector3(-1, 1, 1); 
      vertices[12].TextureCoordinate = new Vector2(0, 0); 
      vertices[13].Position = new Vector3(1, 1, 1); 
      vertices[13].TextureCoordinate = new Vector2(1, 0); 
      vertices[14].Position = new Vector3(-1, -1, 1); 
      vertices[14].TextureCoordinate = new Vector2(0, 1); 
      vertices[15].Position = new Vector3(1, -1, 1); 
      vertices[15].TextureCoordinate = new Vector2(1, 1); 

      vertices[16].Position = new Vector3(1, 1, 1); 
      vertices[16].TextureCoordinate = new Vector2(0, 0); 
      vertices[17].Position = new Vector3(1, 1, -1); 
      vertices[17].TextureCoordinate = new Vector2(1, 0); 
      vertices[18].Position = new Vector3(1, -1, 1); 
      vertices[18].TextureCoordinate = new Vector2(0, 1); 
      vertices[19].Position = new Vector3(1, -1, -1); 
      vertices[19].TextureCoordinate = new Vector2(1, 1); 

      vertices[20].Position = new Vector3(1, 1, -1); 
      vertices[20].TextureCoordinate = new Vector2(0, 0); 
      vertices[21].Position = new Vector3(-1, 1, -1); 
      vertices[21].TextureCoordinate = new Vector2(1, 0); 
      vertices[22].Position = new Vector3(1, -1, -1); 
      vertices[22].TextureCoordinate = new Vector2(0, 1); 
      vertices[23].Position = new Vector3(-1, -1, -1); 
      vertices[23].TextureCoordinate = new Vector2(1, 1); 
      #endregion 

      geometryBuffer = new VertexBuffer(device, VertexPositionTexture.VertexDeclaration, 
               24, BufferUsage.WriteOnly); 
      geometryBuffer.SetData(vertices); 

      #region filling indices 

      int[] indices = new int [36]; 
      indices[0] = 0; indices[1] = 1; indices[2] = 2; 
      indices[3] = 1; indices[4] = 3; indices[5] = 2; 

      indices[6] = 4; indices[7] = 5; indices[8] = 6; 
      indices[9] = 5; indices[10] = 7; indices[11] = 6; 

      indices[12] = 8; indices[13] = 9; indices[14] = 10; 
      indices[15] = 9; indices[16] = 11; indices[17] = 10; 

      indices[18] = 12; indices[19] = 13; indices[20] = 14; 
      indices[21] = 13; indices[22] = 15; indices[23] = 14; 

      indices[24] = 16; indices[25] = 17; indices[26] = 18; 
      indices[27] = 17; indices[28] = 19; indices[29] = 18; 

      indices[30] = 20; indices[31] = 21; indices[32] = 22; 
      indices[33] = 21; indices[34] = 23; indices[35] = 22; 

      #endregion 

      indexBuffer = new IndexBuffer(device, typeof(int), 36, BufferUsage.WriteOnly); 
      indexBuffer.SetData(indices); 
     } 

     private void GenerateInstanceInformation(GraphicsDevice device, Int32 count) 
     { 
      instances = new InstanceInfo[count]; 
      Random rnd = new Random(); 

      for (int i = 0; i < count; i++) 
      { 
       //random position example 
       instances[i].World = new Vector4(-rnd.Next(400), 
               -rnd.Next(400), 
               -rnd.Next(400), 1); 

       instances[i].AtlasCoordinate = new Vector2(rnd.Next(0, 2), rnd.Next(0, 2)); 
      } 

      instanceBuffer = new VertexBuffer(device, instanceVertexDeclaration, 
               count, BufferUsage.WriteOnly); 
      instanceBuffer.SetData(instances); 
     } 

     //view and projection should come from your camera 
     public void Draw(ref Matrix view, ref Matrix projection, GraphicsDevice device) 
     { 
      device.Clear(Color.CornflowerBlue); 

      effect.CurrentTechnique = effect.Techniques["Instancing"]; 
      effect.Parameters["WVP"].SetValue(view * projection); 
      effect.Parameters["cubeTexture"].SetValue(texture); 

      device.Indices = indexBuffer; 

      effect.CurrentTechnique.Passes[0].Apply(); 

      device.SetVertexBuffers(bindings); 
      device.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 24, 0, 12, instanceCount); 
     } 
    } 
} 

I THIS Textur neben mit diesem Shader verwendet haben:

float4x4 WVP; 
texture cubeTexture; 

sampler TextureSampler = sampler_state 
{ 
    texture = <cubeTexture>; 
    mipfilter = LINEAR; 
    minfilter = LINEAR; 
    magfilter = LINEAR; 
}; 

struct InstancingVSinput 
{ 
    float4 Position : POSITION0; 
    float2 TexCoord : TEXCOORD0; 
}; 

struct InstancingVSoutput 
{ 
    float4 Position : POSITION0; 
    float2 TexCoord : TEXCOORD0; 
}; 

InstancingVSoutput InstancingVS(InstancingVSinput input, float4 instanceTransform : POSITION1, 
           float2 atlasCoord : TEXCOORD1) 
{ 
    InstancingVSoutput output; 

    float4 pos = input.Position + instanceTransform; 
    pos = mul(pos, WVP); 

    output.Position = pos; 
    output.TexCoord = float2((input.TexCoord.x/2.0f) + (1.0f/2.0f * atlasCoord.x), 
          (input.TexCoord.y/2.0f) + (1.0f/2.0f * atlasCoord.y)); 
    return output; 
} 

float4 InstancingPS(InstancingVSoutput input) : COLOR0 
{ 
    return tex2D(TextureSampler, input.TexCoord); 
} 

technique Instancing 
{ 
    pass Pass0 
    { 
     VertexShader = compile vs_3_0 InstancingVS(); 
     PixelShader = compile ps_3_0 InstancingPS(); 
    } 
} 

die InstancingShader.fx und in Ihrem Content-Ordner platziert werden genannt sollte.

es von Ihrem Game1 ist so einfach wie der Aufruf:

instancing = new Instancing(); 
instancing.Initialize(this.GraphicsDevice); 
instancing.Load(Content); 

und in der Draw-Methode:

instancing.Draw(ref camera.View, ref camera.Projection, GraphicsDevice);