Hi,
Just tested out the example provided for the new DrawMeshInstancedIndirect method from here and it works really well. However it took a little while to sort out as its just the scripts and I made a few changes regarding the Surface Shader that might be useful to incorporate back into the example.
Firstly some quick notes
Setting up a new project/scene in Unity will likely default to having soft shadows and depending on the quality setting this might include 2 to 4 cascades. This can heavily impact the performance since each cascade requires rendering all the instances again. Unfortunately I was testing in an existing project set to 4 cascades so the performance was roughly 4 times less than having no shadows.
I recommend initially you set up the quality to no cascades and maybe even test with shadows disabled on the directional light.
Its also best to run in deferred rendering mode as forward mode appears to take an extra little hit with additional passes such as the depth pass that is needed when doing shadows or if you use more than one light source. Mind you Iāve not tested with multiple lights, I did try with DrawMeshInstanced and found they werenāt rendered at all in forward.
I also noticed unlike DrawMeshInstanced Unity is unable to report the total tris/verts in the stats overlay. Unsure if that is a bug or simply not possible?
Example Code
Made a couple of changes here.
Firstly I moved the SetBuffer() call from Update() to end of UpdateBuffers() since the data doesnāt change unless you change the instance count. Having it in Update() didnāt seem to affect performance, but seems odd having it there.
Secondly I added a conditional check in UpdateBuffers for instance count being 0 as that will cause errors.
e.g.
if ( instanceCount < 1 ) instanceCount = 1;
Surface Shader
In order to correctly render shadows you need to add additional pragma defines, specifically āaddshadowā.
I imagine for forwardShadows you would need to add āfullforwardshadowsā too, but didnāt test that.
e.g.
#pragma surface surf Standard addshadow
Finally in setup() I changed _Time.x to _Time.y to speed up the rotation of the assigned mesh that is instanced, otherwise it can be quite hard to see the movement.
On my GTX970 it was able to render 2 million individually rotating cubes at approx 35 fps, that dropped to 18 fps with no cascade shadows in deferred rendering, which is to be expected.
So now the Questions
I assume that for surface shaders the setup() function is required to derive the ObjectToWorld and WorldToObject matrices as those are no longer being generated or passed in by Unity?
I was able to add a custom vertex method to the surface shader that used āunity_InstanceIDā to grab specific instance data in order to modify the vertex positions, but have been unable to do the same inside the Surf function.
For example this code
void surf (Input IN, inout SurfaceOutputStandard o)
{
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
float4 col = colorBuffer[unity_InstanceID];
#else
float4 col = float4(0,0,0,1);
#endif
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * col;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
Results in the instances being rendered as āblackā ( not completely due to ambient lighting etc ). This would suggest that UNITY_PROCEDURAL_INSTANCING_ENABLED is no longer defined for the surf method. if I remove the define conditional check then I get the error
undefined variable ācolorBufferā undefined variable āunity_InstanceIDā
Not sure what I need to do to resolve this?
Finally at some point I want I want to investigate per instance culling by using a computeShader to calculate which instances are within the frustrum and thus fill the instances per TRS matrices into a computeBuffer. I think from memory that is possible using one of the ComputeBuffer types and reading back the count value or something. Would this approach work?