Simple instanced rendering example

Hi guys and gals,

I ran into a problem again ^^". I try to use instanced rendering but I can’t get it to work. Does any of you have an idea? I could not find a complete simple example for instanced rendering with MonoGame - if someone knows one, that would be great. Here ist my example:

public readonly struct InstanceTransform : IVertexType
{
  public readonly Matrix Transform;

  public InstanceTransform( Matrix transform)
  {
    Transform= transform;
  }

  VertexDeclaration IVertexType.VertexDeclaration => VertexDeclaration;

  private static readonly VertexDeclaration VertexDeclaration = 
    new VertexDeclaration(
            new VertexElement( 0, VertexElementFormat.Vector4, 
                                  VertexElementUsage.TextureCoordinate, 0),
            new VertexElement( 16, VertexElementFormat.Vector4, 
                                   VertexElementUsage.TextureCoordinate, 1),
            new VertexElement( 32, VertexElementFormat.Vector4, 
                                   VertexElementUsage.TextureCoordinate, 2),
            new VertexElement( 48, VertexElementFormat.Vector4, 
                                   VertexElementUsage.TextureCoordinate, 3));
 }
    
  public class Line
  {
    private VertexBufferBinding[] bindings = new VertexBufferBinding[2];

    private VertexBuffer rectVB;
    private IndexBuffer rectIB;
    private VertexBuffer rectWorldVB;

    public Line()  {}

    public void SetupInstances( 
      GraphicsDevice graphicsDevice, 
      VertexPosition[] vertices, 
      int[] indices )
    {
      // Create a rectangle as instance source.
      var rectVertices = new []
      {
        new VertexPosition( new Vector3( 0.5f, 0.5f, 0 ) ),
        new VertexPosition( new Vector3( -0.5f, 0.5f, 0 ) ),
        new VertexPosition( new Vector3( -0.5f, -0.5f, 0 ) ),
        new VertexPosition( new Vector3( 0.5f, -0.5f, 0 ) )
      };
      var rectIndices = new [] { 0, 1, 2, 0, 2, 3 };

      // Create buffers for that rectangle.
      rectVB = new VertexBuffer(
        graphicsDevice, typeof( VertexPosition ), 4, BufferUsage.WriteOnly );
      rectVB.SetData( lineBodyVertices );

      rectIB= new IndexBuffer(
        graphicsDevice, typeof( int ),  6, BufferUsage.WriteOnly );
      rectIB.SetData( lineBodyIndices );
            
      bindings[0] = new VertexBufferBinding(_LineBodyVertexBuffer);

      var rectWorldMatrices = new InstanceTransform[indices.Length/2];
      for( var i = 0; i < indices.Length / 2; i++ )
      {
        rectWorldMatrices [ i ] = new InstanceTransform( /* some Matrix */ );
      }
            
      rectWorldVB = new VertexBuffer(
        graphicsDevice, typeof( InstanceTransform ),
        indices.Length / 2, BufferUsage.WriteOnly );

      rectWorldVB.SetData( rectWorldMatrices );
            
      bindings[1] = new VertexBufferBinding( rectWorldVB, 0, 1);
    }

    public override void Draw( GraphicsDevice graphicsDevice )
    {
// ...

      graphicsDevice.SetVertexBuffers( bindings);
      graphicsDevice.Indices = rectIB;

      graphicsDevice.DrawInstancedPrimitives(  
                PrimitiveType.TriangleList, 
                0, 
                0, 
                2, 
                rectWolrdVB.VertexCount);

// ...
    }
  }
}

And the shader:

#define VS_SHADERMODEL vs_5_0
#define PS_SHADERMODEL ps_5_0

matrix WorldViewProjection;
matrix WorldInverseTranspose;
matrix World;
matrix View;
matrix Projection;

struct VSIn
{
	float4 Position : POSITION0;
};

struct VertexShaderInstanceInput
{
    float4 row1 : TEXCOORD1;
    float4 row2 : TEXCOORD2;
    float4 row3 : TEXCOORD3;
    float4 row4 : TEXCOORD4;
};

struct VSOut
{
	float4 Position : SV_POSITION;
};

float4x4 CreateMatrixFromCols(
    float4 col1, float4 col2, float4 col3, float4 col4)
{
    return float4x4(
        col1.x, col2.x, col3.x, col4.x,
        col1.y, col2.y, col3.y, col4.y,
        col1.z, col2.z, col3.z, col4.z,
        col1.w, col2.w, col3.w, col4.w);
}


VSOut MainVS( VSIn input, VertexShaderInstanceInput instanceInput)
{
	VSOut output;
	
	float4x4 WorldInstance = CreateMatrixFromCols(
          instanceInput.row1, 
          instanceInput.row2, 
          instanceInput.row3, 
          instanceInput.row4);
    	
	float4 worldPosition = mul(input.Position, WorldInstance);
	float4 viewPosition = mul(worldPosition, View);

	output.Position = mul( viewPosition, Projection );

	return output;
}

float4 MainPS(VSOut input) : COLOR
{
    return float4( 0,0,0,1);
}

technique BasicColorDrawing
{
	pass P0
	{
		VertexShader = compile VS_SHADERMODEL MainVS();
		PixelShader = compile PS_SHADERMODEL MainPS();
	}
};

Cheers,
Georg

PS. I get this error:

Unhandled exception. System.InvalidOperationException:
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: 
SV_Position0, 
TEXCOORD0, TEXCOORD1, TEXCOORD2, TEXCOORD3.

You are using TEXCOORD1 to TEXCOORD4 in your shader code, but in C# you use
TEXCOORD0 to TEXCOORD3.

1 Like

Stupid me :sweat_smile: thank you so much :smiley:

Bottom example in the post.

1 Like