Hardware instancing not working

Hello,

I am currently working on hardware instancing to put grass on a terrain based on this example (GitHub - Eastrall/MonoGame-HardwareInstancing).

But I can’t display the instances on the screen. I can display the GrassElement if I don’t use instancing (so this might not be the issue here)

I think the error might be in the GrassManager but it’s been two days and I can’t find anything to make it working.
I created a structure to pass a Vector4, I created the two buffers to store the geometry and the instances and I bind them to the Graphic Device.

Here is the code

Shader:


#if OPENGL
	#define SV_POSITION POSITION
	#define VS_SHADERMODEL vs_3_0
	#define PS_SHADERMODEL ps_3_0
#else
	#define VS_SHADERMODEL vs_4_0_level_9_1
	#define PS_SHADERMODEL ps_4_0_level_9_1
#endif

matrix WorldViewProjection;

struct InstancingVSInput
{
	float4 Position : POSITION0;
	float4 Color : COLOR0;
};

struct InstancingVSOutput
{
	float4 Position : SV_POSITION;
	float4 Color : COLOR0;
};

InstancingVSOutput InstancingVS(in InstancingVSInput input, float4 instanceTransform : POSITION1)
{
	InstancingVSOutput output = (InstancingVSOutput)0;

	float4 pos = input.Position + instanceTransform;
	pos = mul(pos, WorldViewProjection);

	output.Position = pos;
	output.Color = input.Color;

	return output;
}

float4 InstancingPS(InstancingVSOutput input) : COLOR
{
	return input.Color;
}

technique Instancing
{
	pass P0
	{
		VertexShader = compile VS_SHADERMODEL InstancingVS();
		PixelShader = compile PS_SHADERMODEL InstancingPS();
	}
};

GrassManager

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace _3dtest.Map
{
    class GrassManager
    {

        private const int NBGRASS = 1;

        GrassElement grassElement;
        Effect effect;

        VertexBuffer instancesBuffer;
        IndexBuffer indexBuffer;
        struct GrassInfo
        {
            public Vector4 World;
        };

        VertexBufferBinding[] bindings;
        private VertexDeclaration instanceVertexDeclaration;

        public void Initialize(GraphicsDevice graphicsDevice,int mapSize)
        {
            InitializeInstanceVertexBuffer();

            grassElement = new GrassElement();
            grassElement.Initialize(graphicsDevice);

            indexBuffer = new IndexBuffer(graphicsDevice, typeof(short), grassElement.indices.Length, BufferUsage.WriteOnly);
            indexBuffer.SetData(grassElement.indices);
            

            //Creating instances
            GrassInfo[] pos = new GrassInfo[NBGRASS];
            pos[0].World = new Vector4(30,30,30,1);

            instancesBuffer = new VertexBuffer(graphicsDevice, instanceVertexDeclaration, NBGRASS, BufferUsage.WriteOnly);
            instancesBuffer.SetData(pos);


            bindings = new VertexBufferBinding[2];
            bindings[0] = new VertexBufferBinding(grassElement.vertexBuffer);
            bindings[1] = new VertexBufferBinding(instancesBuffer, 0, 1);
        }

        private void InitializeInstanceVertexBuffer()
        {
            VertexElement[] _instanceStreamElements = new VertexElement[1];

            // Position
            _instanceStreamElements[0] = new VertexElement(0, VertexElementFormat.Vector4,
                        VertexElementUsage.Position, 1);

            instanceVertexDeclaration = new VertexDeclaration(_instanceStreamElements);
        }



        public void LoadContent(ContentManager content)
        {
            effect = content.Load<Effect>("effects/instance_effect");
        }



        public void Draw(GraphicsDevice graphicsDevice,Matrix view,Matrix projection)
        {
            // Set the effect technique and parameters
            effect.CurrentTechnique = effect.Techniques["Instancing"];
            effect.Parameters["WorldViewProjection"].SetValue(view * projection);

            graphicsDevice.Indices = indexBuffer;

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

            graphicsDevice.SetVertexBuffers(bindings);
            graphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList ,0,0,NBGRASS,NBGRASS);  
        }
    }
}

GrassElement:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;

namespace _3dtest.Map
{
    class GrassElement
    {

        public readonly VertexPositionColor[] vertices = new VertexPositionColor[]
        {
            new VertexPositionColor(new Vector3(-10,0,0),Color.Green),
            new VertexPositionColor(new Vector3(0,100,0),Color.Green),
            new VertexPositionColor(new Vector3(10,0,0),Color.Green),
            
        };

        public VertexBuffer vertexBuffer;

        public readonly short[] indices = new short[]
        {
            0,1,2
        };


        public void Initialize(GraphicsDevice graphicsDevice)
        {
            vertexBuffer = new VertexBuffer(graphicsDevice, typeof(
                VertexPositionColor), vertices.Length, BufferUsage.
                WriteOnly);
            vertexBuffer.SetData<VertexPositionColor>(vertices);
        }
        
    }
}

Thank you for your help,

Not looked at your code, but I recently got instancing working and post my code here.

Hope this helps, the shader supports various types of billboards, sperical (always face the camera), cylidrical (faces camera on a given axis) and static (does not follow the camera).

Hope this helps. (it’s 3.8.1 by the way)

1 Like

Thank you for your answer, the examples are really interesting.

It turns out the code in my post is working and I didn’t make a call elsewhere in my program. Always a pleasure to take 2 days to debbug such a dumb error…

2 Likes