Graphics.DrawMeshInstancedIndirect and argsOffset

Hi,

I’m trying to use Graphics.DrawMeshInstancedIndirect with a structured buffer in the shader. I just wanted to understand the argsOffset and if it works like i think it should.

Basically I have lets say 32 meshes, and those meshes will be called individually by Graphics.DrawMeshInstancedIndirect. I’ve built the visible list of meshes up into the structured buffer within the shader to modify their position and other attributes, i.e. no material property block.

So I wanted to confirm say i have a structured buffer of 3200 in length as an example, with each mesh having 100 visible instances of it, 32 * 100. If i were to draw the second mesh, would the startIndex of 100 for the argsOffset flow thru to the shader as the uint instanceID : SV_InstanceID variable?

Maybe it doesn’t work like i think it does? If anyone knows that would be great :smile:

Graphics.DrawMeshInstancedIndirect(mesh, 0, _material, _renderBounds, _argsBufferArray[i], startIndex, null,
                                   ShadowCastingMode.Off, false, _layerMask, null, LightProbeUsage.Off);

StructuredBuffer<proceduralvegetationbuffer> _ProceduralVegetationBuffer;

v2f vert (appdata v, uint instanceID : SV_InstanceID)

It’s the offset into the args buffer to read the draw counts from.

Eg if the buffer for args contains 100,0,0,0,0 (100 instances, all defaults) that will draw 100 instances if the args offset is 0.

If the buffer contains 100,0,0,0,0,200,0,0,0,0 then an args offset of 20 (5 ints * 4 bytes for each int) will draw 200 instances.

1 Like

Thanks Richard! So I suppose this won’t solve my problem. Do you or anyone else have a suggestion how to overcome my problem though?

  • I have a procedural tree generation program which can create many meshes
  • I cull and determine which meshes are visible and arrange them in a way so i know how many times i have to draw each mesh (by the way using ECS)
  • Now I know what I need to draw but I don’t want to limit myself with instancing using material property blocks i.e. 1023
  • I currently set the compute buffer array once with all meshes ordered in the array, so position 0 might have 10 trees, at index 10 we start a different mesh and render 200 trees etc.

So what would be the best way to draw this? I’m looking into material property blocks set buffer and seeing if that can help. What I was trying to do was set the compute buffer once, and for each mesh know exactly where to start in the compute buffer array by trying to offset the instance index per mesh draw call somehow if that makes sense.

I have many meshes and one material / shader. Really appreciate any suggestions anyone can provide.

_material.SetBuffer(ShaderProceduralVegetationBuffer, _proceduralVegetationBuffer);
struct proceduralvegetationbuffer
            {
                float2 Position;
                float Age;
                float Foliage;
                float FoliageDisolve;
                float FoliageColor;
                float Flower;
                float Burnt;
            };
            StructuredBuffer<proceduralvegetationbuffer> _ProceduralVegetationBuffer;
v2f vert (appdata v, uint instanceID : SV_InstanceID)
            {
                v2f o;
            
                proceduralvegetationbuffer pvData = _ProceduralVegetationBuffer[instanceID];

The 5th argument of the args buffer is called “start instance location” and ought to be what you need. However, the way this value is interpreted on some platforms means it doesn’t adjust the instance ID like you would expect (eg DX11 uses it in a different way, and we can’t fix this within Unity because it’s how DX11 decided to use that parameter.

So, what i’m trying to say is, if you only care about a certain platform, you could try to use it and see if it works (eg i think it works on Metal).

But, the cross platform way to do this is to provide a value to the shader to add to the instance ID. To do this, call MyShader.SetInt(“InstanceOffset”, myOffset) before each draw call. (directly on the shader, or via a Material Property Block).

3 Likes

So simple hey… thanks very much. I’ll try it out, I thought I couldn’t do this because of how DrawMeshInstancedIndirect is apparently delayed so overwriting any shader values would mess things up. If that doesn’t work I’ll try the Material Property Block.

Oh and I should say I did try the “start instance location” before but didn’t work as I expected on Windows, weird stuff happening on the screen, flickering etc.

Fixed yay! Thanks for your help Richard in explaining what all those values meant because couldn’t find a lot out there about them :slight_smile:

Setting the shader value didn’t work however setting the material property block shader value and just passing it thru on the draw did.

2 Likes

hello @richardkettlewell ,

im currently experiencing strange behavior with Graphics.DrawMeshInstancedIndirect Indirect, the DrawMeshInstancedIndirect still rendering DrawCalls with 0 sets the number of instances.

this is what the Args buffer looks like [600,0,0,0,0,2034,14,0,0,0] and I pass (i * 5 * 4) to argsOffset.

I saw in your comment that the number of instances is set to the first index of the args buffer, which is not what the documentation says, am I missing something?

Thank you!

this is what the DrawMeshInstancedIndirect API displays on different devices:

On a Samsung Galaxy S10, S10+, and unity Editor

On Oneplus 2: (As you can see the Plane is visible when it’s instance count is set to 0 )

Good point - i misspoke in my comment, but luckily the docs are correct, the value are as follows:

https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedIndirect.html

1 Like

thanks for the response :slight_smile:

do you have any idea why is the oneplus 2 rendering drawcalls with 0 as instance count ? (like the plane in this case)

more details:
i just upgraded the Device to Android 8.1 (OpenGles 3.2) and the DrawMeshInstancedIndirect is still rendering objects with 0 value as instance count in the args buffer.
i found out that it draws 1 element of any drawcall request with 0 instance count.

sounds like a possible bug with that device - it’s worth reporting a bug using the bug reporter.

1 Like