2012-03-29 3 views
4

Je suis venu pour se renseigner sur instanciation XNABesoin d'aide instanciation à XNA 4.0

Je suis un développeur XNA commençant Stepping récemment en de la 2D à des jeux en 3D.
J'essaye de dessiner un grand nombre de cubes faits uniquement de sommets dans le code. Comme on peut se le douter, dessiner un grand nombre de ces cubes cause beaucoup de stress sur mon ordinateur.
Alors que je cherchais un moyen d'augmenter la performance, je suis tombé sur le terme «instanciation».
Ne sachant pas comment fonctionne l'instanciation dans XNA 4.0, j'ai cherché un tutoriel adapté à quelqu'un de mon niveau.
Cependant, le seul tutoriel que j'ai rencontré (http://blogs.msdn.com/b/shawnhar/archive/2010/06/17/drawinstancedprimitives-in-xna-game-studio-4-0.aspx) est un peu trop avancé pour moi. Je pense qu'il utilise des modèles, des maillages et autres joyeusetés au lieu de sommets, donc je ne peux pas savoir quel morceau de code est vraiment pertinent par rapport à ce que je cherche.

C'est pourquoi je viens à vous. Si quelqu'un pouvait me donner un tutoriel simple (si possible) ou des extraits de code expliquant comment utiliser l'instanciation avec des cubes (ou des figures) dessinés avec des sommets dans XNA 4.0, je serais très obligé.

Répondre

7

Ceci est l'extrait de code le plus simple que je pourrais trouver. C'est une adaptation d'un code que j'ai fait il y a quelques mois pour afficher quelques cubes, comme ce dont vous avez besoin, pas de modèles ni rien de fantaisie.

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); 
     } 
    } 
} 

Je l'ai utilisé THIS texture aux côtés de ce shader:

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(); 
    } 
} 

qui devrait être nommé InstancingShader.fx et placé dans votre dossier de contenu.

Son utilisation de votre Game1 est aussi simple que d'appeler:

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

et dans votre méthode Draw:

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