DrawMeshInstanced with MaterialPropertyBlock

Hello there,
I am using DrawMeshInstanced to render 1023 cubes in white and use MaterialPropertyBlock to render 1023 cubes in blue. But the property is somehow not applying. The cubes remain white. When I use DrawMesh it is working. Also the performance is better with DrawMesh. I expected it to be vice versa. Maybe my test setup is to simple to verify. Here it is:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Instancetest : MonoBehaviour
{
    public Material material;

    private List<Matrix4x4> _matrixArray0;
    private List<Matrix4x4> _matrixArray1;

    private Vector3 _scaleVector;
    private MaterialPropertyBlock _propBlock;
    private int _colorID;

    private Mesh _cubeMesh;
    private Matrix4x4 _tmpMatrix;

    public bool instanced = true;

    // Use this for initialization
    void Start()
    {
        _matrixArray0 = new List<Matrix4x4>();
        _matrixArray1 = new List<Matrix4x4>();
        _scaleVector = Vector3.one;
        _propBlock = new MaterialPropertyBlock();
        _colorID = Shader.PropertyToID("_Color");

        GameObject tmp = GameObject.CreatePrimitive(PrimitiveType.Cube);
        _cubeMesh = tmp.GetComponent<MeshFilter>().sharedMesh;
        Destroy(tmp);

        for (int i = 0; i < 1023; i++)
        {
            Vector3 pos = Random.insideUnitCircle * 20.0f;
            _tmpMatrix.SetTRS(pos, Quaternion.identity, _scaleVector);
            _matrixArray0.Add(_tmpMatrix);

            _tmpMatrix.SetTRS(pos + Vector3.forward * 2.0f, Quaternion.identity, _scaleVector);
            _matrixArray1.Add(_tmpMatrix);
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (!instanced)
        {
            for (int i = 0; i < _matrixArray0.Count; i++)
            {
                Graphics.DrawMesh(_cubeMesh, _matrixArray0[i], material, 0);
            }

            _propBlock.SetColor(_colorID, Color.blue);

            for (int i = 0; i < _matrixArray0.Count; i++)
            {
                Graphics.DrawMesh(_cubeMesh, _matrixArray1[i], material, 0, null, 0, _propBlock);
            }
        }
        else
        {
            Graphics.DrawMeshInstanced(_cubeMesh, 0, material, _matrixArray0);
            _propBlock.SetColor(_colorID, Color.blue);
            Graphics.DrawMeshInstanced(_cubeMesh, 0, material, _matrixArray1, _propBlock);
        }
    }
}

Just drag the script on a gameobject and assign a material in the inspector. The material should use an instance shader. I just used Create β†’ Shader β†’ Standard Surface Shader (Instanced).
So is there something wrong with the code (or me)? I am using Unity 5.5.0f3.

Thx for your help!

2 Likes

Hey bud,

Nice job using the DrawMeshInstanced API.

Ya gotta use _propBlock.SetVectorArray for the DrawMeshInstanced API!

void Update(){
m_matrices[0]=transform.localToWorldMatrix;
MaterialPropertyBlockmpb=newMaterialPropertyBlock();
Vector4[ ]colors=newVector4[1];
colors[0]=Color.blue;

mpb.SetVectorArray(β€œ_Color”,colors);
Graphics.DrawMeshInstanced(m_cubeMesh,0,m_material,m_matrices,1,mpb, UnityEngine.Rendering.ShadowCastingMode.On,true,0,Camera.main);
}

8 Likes

Thank you very much!
It is working :wink:

Thanks @jknight-nc , that was just the answer I was looking for for my problem too.