I am making a 3d strategy game with large unit number (1000 per side) , and I’m learning hardware instancing to make it run smoothly(currently it’s 8-10 fps).
I have read on Ossaltu’s post on github that to initialize vertex buffer we need to write
_device.SetVertexBuffer(vertexBuffer);
_device.SetInstanceBuffer(instanceBuffer);
but on my computer(just updated to Monogame3.5) GraphicDevice don’t contain this method.
(I have checked and found this method in GraphicDevice.cs on github)
How should I solve this problem? Should I change build target(currently xna 4.6.1)?
Currently I use a SetVertexBuffer(instanceBuffer) , and it gets “invalid operation exception”
My Code:(based on microsoft xna hardware instancing sample and Filipe/s cubemap)
DynamicVertexBuffer instanceVertexBuffer;
static VertexDeclaration instanceVertexDeclaration = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 0),
new VertexElement(16, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 1),
new VertexElement(32, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 2),
new VertexElement(48, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 3)
);
protected override void initialize(){
HardwareInstancingEffect = Content.Load(“models/InstancedModel”);
}
//A Method to draw models from a matrix array and a model
void DrawModelHardwareInstancing(Model model,Matrix[] instances)
{
if (instances.Length == 0)
return;
// If we have more instances than room in our vertex buffer, grow it to the neccessary size.
if ((instanceVertexBuffer == null) ||
(instances.Length > instanceVertexBuffer.VertexCount))
{
if (instanceVertexBuffer != null)
instanceVertexBuffer.Dispose();
instanceVertexBuffer = new DynamicVertexBuffer(GraphicsDevice, instanceVertexDeclaration,
instances.Length, BufferUsage.WriteOnly);
}
//instances here is transform matrices
// Transfer the latest instance transform matrices into the instanceVertexBuffer.
instanceVertexBuffer.SetData(instances, 0, instances.Length, SetDataOptions.Discard);
foreach (ModelMesh mesh in model.Meshes)
{
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
// Tell the GPU to read from both the model vertex buffer plus our instanceVertexBuffer.
// Set up the instance rendering effect.
Effect effect = HardwareInstancingEffect;
effect.CurrentTechnique = effect.Techniques["HardwareInstancing"];
effect.Parameters["World"].SetValue(Matrix.Identity);//t));
effect.Parameters["View"].SetValue(View);
effect.Parameters["Projection"].SetValue(Projection);
effect.Parameters["Texture"].SetValue(Pixel);
GraphicsDevice.Indices = meshPart.IndexBuffer;
effect.CurrentTechnique.Passes[0].Apply();
//GraphicsDevice.SetVertexBuffers(
// new VertexBufferBinding(meshPart.VertexBuffer, meshPart.VertexOffset, 0),
// new VertexBufferBinding(instanceVertexBuffer, 0, 1)
//);
// Draw all the instance copies in a single call.
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
GraphicsDevice.SetVertexBuffer(instanceVertexBuffer);
GraphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, meshPart.NumVertices, meshPart.StartIndex,
meshPart.PrimitiveCount, instances.Length);
}
}
}