visual-studio-2010 optimization xna xna-4.0

visual studio 2010 - Necesita ayuda para usar instancias en XNA 4.0



visual-studio-2010 optimization (1)

He venido a preguntar sobre la creación de instancias en XNA

Soy un desarrollador principiante de XNA, que recientemente ha pasado de los juegos 2D a 3D.
Intento dibujar en código un gran número de cubos hechos exclusivamente de vértices. Como uno podría sospechar, dibujar una gran cantidad de estos cubos causa bastante estrés en mi computadora.
Como estaba buscando una manera de aumentar el rendimiento, me encontré con el término "instancias".
Sin saber cómo funciona la creación de instancias en XNA 4.0, he buscado un tutorial adecuado para alguien de mi nivel.
Sin embargo, el único tutorial que he encontrado (http://blogs.msdn.com/b/shawnhar/archive/2010/06/17/drawinstancedprimitives-in-xna-game-studio-4-0.aspx) es un poco demasiado avanzado para mí. Creo que está usando modelos, mallas y otras cosas en lugar de vértices, así que no puedo descifrar qué parte del código es realmente relevante para lo que busco.

Por eso es que vengo a ti. Si alguien pudiera darme un tutorial simple (si es posible) o fragmentos de código explicando cómo usar instancias con cubos (o cualquier figura) dibujados con vértices en XNA 4.0, estaría muy agradecido.


Este es el fragmento de código más simple que podría surgir. Es una adaptación de un código que hice hace un par de meses para mostrar algunos cubos, justo como lo que necesita, sin modelos ni nada sofisticado.

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

He usado ESTA textura junto con este sombreador:

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

que debería llamarse InstancingShader.fx y colocarse en su carpeta de Contenido.

Usarlo desde tu Game1 es tan simple como llamar:

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

y en tu método Draw:

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