Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

DrawMeshInstanced option to provide per instance material property block?

Discussion in '5.5 Beta' started by Prodigga, Oct 11, 2016.

  1. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    I have an array of transformation matricies, and an array of material property blocks (one for each matrix)

    In 5.4, I can do this:

    Code (CSharp):
    1. for (int i = 0; i < matrixList.Count; i++)
    2. {
    3.        Graphics.DrawMesh(someMesh, matrixList[i], someInstancedMaterial, someLayer, null, 0, matPropertyBlockList[i]);
    4. }
    This works as expected. My mesh gets draw multiple times, each instance is draw with custom properties, and the result is only 1 draw call. (Instanced batching)

    In 5.5, this does not work. I have a separate post regarding this here, maybe this is a regression/bug.

    Let's ignore that for a sec. 5.5 provides a new method - DrawMeshInstanced. It takes an array of matricies but only takes a single material property block. From what I can see, the only difference between DrawMeshInstanced and DrawMesh is that I do not have to call DrawMesh hundreds of times. Instead, I can create an array of matricies with hundreds of elements, and call DrawMeshInstanced a single time with all the information. However, DrawMeshInstanced only takes a single material property block, so that means that every instance needs to use the same data!

    I think it is necessary to have a DrawMeshInstanced method that takes an array of material property blocks too, so that we can achieve the same thing as above with a single line:

    Code (CSharp):
    1. Graphics.DrawMeshInstanced(someMesh, matrixArray, someInstancedMaterial, someLayer, null, 0, matPropertyBlockArray);
    As a side note, I wanted to mention that 'Graphics.DrawMesh' (5.4) seems to know how to split up draw calls by itself. It only batches 500 instances together before splitting it out to a second draw call. In contrast to this, 'Graphics.DrawMeshInstanced' simply complains with an error log if you pass it a matrix array with more than 1023 elements and doesn't draw anything. Couldn't this just be handled internally, as with Graphics.DrawMesh in 5.4?
     
    Last edited: Oct 11, 2016
    burningmime likes this.
  2. Hyp-X

    Hyp-X

    Joined:
    Jun 24, 2015
    Posts:
    438
    You can use arrays in your MaterialProperyBlock and use the instance id in your shaders to index into the arrays.
     
    hellowill89 likes this.
  3. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Sounds like a work around? In 5.4 I did not have to deal with arrays and indexing in to arrays in my shader at all. I had MaterialPropertyBlock for each object, and simply passed that along to DrawMesh and it worked fine.

    Using your method, I can't get the built in Standard Shader (Instanced) to work correctly with a custom color for each instance. It sounds like your suggestion is fundamentally different to what normally happens in the instancing pipeline.

    Also I noticed that MaterialPropertyBlock complains when you try to create an array large than 1023 elements, which was a non issue with per-instance MaterialPropertyBlock's.
     
  4. zeroyao

    zeroyao

    Unity Technologies

    Joined:
    Mar 28, 2013
    Posts:
    169
    Hey Prodigga,

    I have replied the other thread that it is a regression bug and is fixed for beta 9.

    Using arrays in the single MaterialPropertyBlock is the preferred way to pass per-instance data to DrawMeshInstanced. In places where each renderer has a MaterialPropertyBlock (DrawMesh, or just regular MeshRenderers being batched) the internal instancing code goes through a loop to collect all data into one single MaterialPropertyBlock, and that is slower than doing that explicitly in scripting.

    I'm adding alloc-free overloads for array getters/setters for MaterialPropertyBlock, Material, Shader and CommandBuffer classes and DrawMeshInstanced method. They will make GC more efficient if you are using List<T> to store your data.
     
  5. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Thanks for the clarification and update! Looking forward to it. :)