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