Help! Can't use SetInstanceBuffer()

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

            }
        }
    }

I don’t have much time, maybe I can revisit that later.

EDIT the difference seems to be you assign GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); twice instead of SetVertexBuffers? I assign an array (size 2) of bindings to it.

I did actually implement instancing like this

private static VertexBufferBinding _vbModelBinding;
private static VertexBufferBinding _instanceBinding;

private static readonly VertexBufferBinding[] VertexBuffers = new VertexBufferBinding[2];

Initialize()
Model model = Art.SphereModelLowPoly;
            ModelMeshPart meshPart = model.Meshes[0].MeshParts[0];
            _vbModelBinding = new VertexBufferBinding(meshPart.VertexBuffer, meshPart.VertexOffset, 0);

            VertexBuffers[0] = _vbModelBinding;

Draw()
 ...
_instanceVertexBuffer.SetData(_instanceTransforms, 0, elementCount, SetDataOptions.None);

            VertexBuffers[1] = _instanceBinding;


    graphicsDevice.SetVertexBuffers(VertexBuffers);

    graphicsDevice.Indices = _indexBuffer;

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

        graphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, _numVertices, _startIndex, _primitiveCount, _instanceTransforms.Length);

There’s no such method. I found the PR that implements it this way, but in XNA this is not how instancing works so the PR was not merged. If you want a full example project, check out the blog post by Shawn Hargreaves on the subject and the corresponding sample

uh, just saw Ossaltu saying:

btw I briefly migrated the microsoft sample on http://xbox.create.msdn.com/en-US/education/catalog/sample/mesh_instancing and it returns the same error

What call raises the error and what’s the error message?

The command
GraphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0,MeshPart.NumVertices, MeshPart.StartIndex,meshPart.PrimitiveCount, instances.Length);

The error is invalid operation exception.
btw, this is my hardwareinstancing effect file
basicly same one as microsoft sample (don’t remember what change beside a higher compiling version of vertex and pixel shader I’ve made.)

//-----------------------------------------------------------------------------
// InstancedModel.fx
//
// Microsoft XNA Community Game Platform
// Copyright © Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------

// Camera settings.
float4x4 World;
float4x4 View;
float4x4 Projection;

// This sample uses a simple Lambert lighting model.
float3 LightDirection = normalize(float3(-1, -1, -1));
float3 DiffuseLight = 5;
float3 AmbientLight = 0.25;
texture Texture;

sampler Sampler = sampler_state
{
Texture = (Texture);
};

struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TextureCoordinate : TEXCOORD0;
};

struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
float2 TextureCoordinate : TEXCOORD0;
};

// Vertex shader helper function shared between the two techniques.
VertexShaderOutput VertexShaderCommon(VertexShaderInput input, float4x4 instanceTransform)
{
VertexShaderOutput output;

// Apply the world and camera matrices to compute the output position.
float4 worldPosition = mul(input.Position, instanceTransform);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);

// Compute lighting, using a simple Lambert model.
float3 worldNormal = mul(input.Normal, instanceTransform);

float diffuseAmount = max(-dot(worldNormal, LightDirection), 0);

float3 lightingResult = saturate(diffuseAmount * DiffuseLight + AmbientLight);

output.Color = float4(lightingResult, 1);

// Copy across the input texture coordinate.
output.TextureCoordinate = input.TextureCoordinate;

return output;

}

// Hardware instancing reads the per-instance world transform from a secondary vertex stream.
VertexShaderOutput HardwareInstancingVertexShader(VertexShaderInput input,
float4x4 instanceTransform : BLENDWEIGHT)
{
return VertexShaderCommon(input, mul(World, transpose(instanceTransform)));
}

// Both techniques share this same pixel shader.
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
return tex2D(Sampler, input.TextureCoordinate) * input.Color;
}

// Hardware instancing technique.
technique HardwareInstancing
{
pass Pass1
{
VertexShader = compile vs_4_0 HardwareInstancingVertexShader();
PixelShader = compile ps_4_0 PixelShaderFunction();
}
}

Are you setting the index buffer, the vertex buffer and did you apply an effect? The error message should tell you what you’re doing wrong.

yes. The effect file is for hardware instancing

The error massage says

An unhandled exception of type ‘System.InvalidOperationException’ occurred in MonoGame.Framework.dll

Additional information: An error occurred while preparing to draw. This is probably because the current vertex declaration does not include all the elements required by the current vertex shader. The current vertex declaration includes these elements: BLENDWEIGHT0, BLENDWEIGHT1, BLENDWEIGHT2, BLENDWEIGHT3.

You have BlendWeight0, Position0, Normal0 and TextureCoordinate0 as input in te vertex shader. So the suggestion is rght and they don’t match with the vertexdeclaration

Em…How to set them?
(I’m a noob on HLSL and primitives, and I didn’t make much change to the microsoft sample…)

Okay, so the error message only specifies vertex declaration from one of the vertexbuffers, so if you’re just following the sample you should have another vertex buffer bound with POSITION, NORMAL and TEXCOORD and this should work. Using SEMANTIC0 in the shader for a matrix and then binding Vector4’s with SEMANTIC0, SEMANTIC1, SEMANTIC2 and SEMANTIC3 works in XNA, but it might be what’s causing the issue in MonoGame.

Nevermind, this is not the issue. I have ported this sample to MonoGame before and got it running without any large problems… What changes did you make to the sample?

I may have done some other fixes when porting, but I don’t really remember. If you want, you can try my port from https://github.com/Jjagg/InstancedSample. You’ll need to change the MonoGame reference to the MonoGame DX dll in your installation folder or the MonoGame.Windows project if you build from source. Other than that it should work. Note that it references OpenGL because I ported the sample to implement instanced rendering in OpenGL, but it’s not merged into develop yet so you won’t actually be able to use the OpenGL version of MonoGame with this sample (unless you checkout my branch).

I changed the references to make the first part compile, and when the second part build its content it says E:/Desktop/PORTED HI/InstancedSampleGL/Content/Cats.fbx: error: ExternalReference ‘E:\Desktop\PORTED HI\InstancedSampleGL\Content\InstancedModel.fx’ must reference a .xnb file.

Oh, right… That’s fixed in the develop branch. You can bypass it by using the default model processor and setting the effect on the meshes when you start up the game. You can use the code from the custom processor as is, I think. The idea is to loop over all the meshes in the model and set the effect to your custom effect

Sorry for the late reply.
it says
DX9-style intrinsics are disabled when not in dx9 compatibility mode
for
return SAMPLE_TEXTURE(Texture, input.TextureCoordinate) * input.Color;
and I can’t find how to write substitute for this line in DX11…

Texture2D myTexture

SamplerState mySampler

myTexture.Sample(mySampler, TexCoord)

Umm… I made some changes to convert it to DX10/11 syntax. It compiles successfully in pipeline(with Line 56 have a warning: ‘mul’: implicit truncation of vector type. Still a progress, though), but when I tried to compile it with the game, it fails because “Processor ‘EffectProcessor’ had unexpected failure”.

The .fx looks like this:

//-----------------------------------------------------------------------------
// InstancedModel.fx
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------

// Camera settings.
float4x4 World;
float4x4 View;
float4x4 Projection;

// This sample uses a simple Lambert lighting model.
float3 LightDirection = normalize(float3(-1, -1, -1));
float3 DiffuseLight = 1.25;
float3 AmbientLight = 0.25;

Texture2D myTexture;
SamplerState mySampler;

struct VertexShaderInput
{
float4 Position : POSITION;
float3 Normal : NORMAL0;
float2 TextureCoordinate : TEXCOORD0;
};

struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR;
float2 TextureCoordinate : TEXCOORD0;
};

// Vertex shader helper function shared between the two techniques.
VertexShaderOutput VertexShaderCommon(VertexShaderInput input, float4x4 instanceTransform)
{
VertexShaderOutput output;

// Apply the world and camera matrices to compute the output position.
float4 worldPosition = mul(input.Position, instanceTransform);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
// Compute lighting, using a simple Lambert model.
float3 worldNormal = mul(input.Normal, instanceTransform);

float diffuseAmount = max(-dot(worldNormal, LightDirection), 0);

float3 lightingResult = saturate(diffuseAmount * DiffuseLight + AmbientLight);

output.Color = float4(lightingResult, 1);
// Copy across the input texture coordinate.
output.TextureCoordinate = input.TextureCoordinate;
return output;

}

// Hardware instancing reads the per-instance world transform from a secondary vertex stream.
VertexShaderOutput HardwareInstancingVertexShader(VertexShaderInput input,
float4x4 instanceTransform : BLENDWEIGHT)
{
return VertexShaderCommon(input, mul(World, transpose(instanceTransform)));
}

// When instancing is disabled we take the world transform from an effect parameter.
VertexShaderOutput NoInstancingVertexShader(VertexShaderInput input)
{
return VertexShaderCommon(input, World);
}

// Both techniques share this same pixel shader.
float4 PixelShaderFunction(VertexShaderOutput input) : SV_TARGET
{
return myTexture.Sample(mySampler, input.TextureCoordinate) * input.Color;
}

// Hardware instancing technique.
technique HardwareInstancing
{
pass Pass1
{
VertexShader = compile vs_4_0_level_9_1 HardwareInstancingVertexShader();
PixelShader = compile ps_4_0_level_9_1 PixelShaderFunction();
}
}

// For rendering without instancing.
technique NoInstancing
{
pass Pass1
{
VertexShader = compile vs_4_0_level_9_1 NoInstancingVertexShader();
PixelShader = compile ps_4_0_level_9_1 PixelShaderFunction();
}
}